compute-runtime/shared/source/helpers/l3_range.h

139 lines
4.3 KiB
C++

/*
* Copyright (C) 2021 Intel Corporation
*
* SPDX-License-Identifier: MIT
*
*/
#pragma once
#include "shared/source/helpers/basic_math.h"
#include "shared/source/helpers/constants.h"
#include "shared/source/helpers/debug_helpers.h"
#include "shared/source/utilities/stackvec.h"
#include <cstdint>
#include <limits>
namespace NEO {
static const size_t maxFlushSubrangeCount = 126;
struct L3Range {
static constexpr uint64_t minAlignment = MemoryConstants::pageSize;
static constexpr uint64_t minAlignmentMask = minAlignment - 1ULL;
static constexpr uint64_t minAlignmentBitOffset = Math::ffs(minAlignment);
static constexpr uint64_t maxSingleRange = 4 * MemoryConstants::gigaByte;
static constexpr uint64_t maxMaskValue = Math::ffs(maxSingleRange / minAlignment);
static const uint64_t policySize = 2;
L3Range() = default;
uint64_t getMask() const {
return data.common.mask;
}
void setMask(uint64_t mask) {
data.common.mask = mask;
}
uint64_t getAddress() const {
return data.common.address << L3Range::minAlignmentBitOffset;
}
void setAddress(uint64_t address) {
data.common.address = address >> L3Range::minAlignmentBitOffset;
}
void setPolicy(uint64_t policy) {
data.common.policy = policy;
}
uint64_t getPolicy() const {
return data.common.policy;
}
static constexpr bool meetsMinimumAlignment(uint64_t v) {
return (0 == (v & minAlignmentMask));
}
static uint32_t getMaskFromSize(uint64_t size) {
UNRECOVERABLE_IF(false == Math::isPow2(size));
UNRECOVERABLE_IF((size < minAlignment) || (size > maxSingleRange));
auto ret = Math::ffs(size >> minAlignmentBitOffset);
static_assert(maxMaskValue < std::numeric_limits<uint32_t>::max(), "");
return static_cast<uint32_t>(ret);
}
uint64_t getSizeInBytes() const {
return (1ULL << (minAlignmentBitOffset + getMask()));
}
uint64_t getMaskedAddress() const {
return getAddress() & (~maxNBitValue(minAlignmentBitOffset + getMask()));
}
static L3Range fromAddressSize(uint64_t address, uint64_t size) {
L3Range ret;
ret.setAddress(address);
ret.setMask(getMaskFromSize(size));
return ret;
}
static L3Range fromAddressSizeWithPolicy(uint64_t address, uint64_t size, uint64_t policy) {
L3Range ret = fromAddressSize(address, size);
ret.setPolicy(policy);
return ret;
}
static L3Range fromAddressMask(uint64_t address, uint64_t mask) {
L3Range ret;
ret.setAddress(address);
ret.setMask(mask);
return ret;
}
protected:
union Data {
struct {
uint64_t mask : minAlignmentBitOffset;
uint64_t address : sizeof(uint64_t) * 8 - minAlignmentBitOffset - policySize;
uint64_t policy : policySize;
} common;
uint64_t raw;
} data;
static_assert(sizeof(Data) == sizeof(uint64_t), "");
};
inline bool operator==(const L3Range &lhs, const L3Range &rhs) {
return (lhs.getAddress() == rhs.getAddress()) && (lhs.getMask() == rhs.getMask());
}
inline bool operator!=(const L3Range &lhs, const L3Range &rhs) {
return (false == (lhs == rhs));
}
template <typename ContainerT>
inline void coverRangeExactImpl(uint64_t address, uint64_t size, ContainerT &ret, uint64_t policy) {
UNRECOVERABLE_IF(false == L3Range::meetsMinimumAlignment(address));
UNRECOVERABLE_IF(false == L3Range::meetsMinimumAlignment(size));
const uint64_t end = address + size;
uint64_t offset = address;
while (offset < end) {
uint64_t maxRangeSizeBySize = Math::prevPowerOfTwo(end - offset);
uint64_t maxRangeSizeByOffset = offset ? (1ULL << Math::ffs(offset)) : L3Range::maxSingleRange;
uint64_t rangeSize = std::min(maxRangeSizeBySize, maxRangeSizeByOffset);
rangeSize = std::min(rangeSize, +L3Range::maxSingleRange);
ret.push_back(L3Range::fromAddressSizeWithPolicy(offset, rangeSize, policy));
offset += rangeSize;
}
}
using L3RangesVec = StackVec<L3Range, 32>;
template <typename RetVecT>
inline void coverRangeExact(uint64_t address, uint64_t size, RetVecT &ret, uint64_t policy) {
coverRangeExactImpl(address, size, ret, policy);
}
} // namespace NEO