-
Notifications
You must be signed in to change notification settings - Fork 246
/
Copy pathl3_range.h
153 lines (123 loc) · 4.86 KB
/
l3_range.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
/*
* Copyright (C) 2021-2024 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 {
inline 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 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 <class T>
constexpr bool isCanPreallocStlContainer(const std::vector<T>& v) { return true; }
template <class T1, class T2>
constexpr bool isCanPreallocStlContainer(const std::unordered_map<T1, T2>& v) { return true; }
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;
uint64_t maxRangeSizeBySize;
uint64_t maxRangeSizeByOffset;
uint64_t rangeSize;
if constexpr (is_can_prealloc_stl_container(ret)) {
maxRangeSizeBySize = Math::prevPowerOfTwo(end - offset);
maxRangeSizeByOffset = offset ? (1ULL << Math::ffs(offset)) : L3Range::maxSingleRange;
rangeSize = std::min(maxRangeSizeBySize, maxRangeSizeByOffset);
rangeSize = std::min(rangeSize, +L3Range::maxSingleRange);
ret.reserve((end - offset) / rangeSize);
}
while (offset < end) {
maxRangeSizeBySize = Math::prevPowerOfTwo(end - offset);
maxRangeSizeByOffset = offset ? (1ULL << Math::ffs(offset)) : L3Range::maxSingleRange;
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