/home/runner/work/charm/charm/src/ck-ldb/TreeStrategyBase.h
Line | Count | Source (jump to first uncovered line) |
1 | | // Author: Juan Galvez <jjgalvez@illinois.edu> |
2 | | |
3 | | #ifndef TREESTRATEGYBASE_H |
4 | | #define TREESTRATEGYBASE_H |
5 | | |
6 | | #include <algorithm> |
7 | | #include <random> |
8 | | |
9 | | namespace TreeStrategy |
10 | | { |
11 | | template <typename T, bool is_ptr = std::is_pointer<T>::value> |
12 | | struct CmpLoadGreater |
13 | | { |
14 | | }; |
15 | | |
16 | | template <typename T> |
17 | | struct CmpLoadGreater<T, true> |
18 | | { |
19 | | inline bool operator()(const T a, const T b) const |
20 | | { |
21 | | return (a->getLoad() > b->getLoad()); |
22 | | } |
23 | | }; |
24 | | |
25 | | template <typename T> |
26 | | struct CmpLoadGreater<T, false> |
27 | | { |
28 | | inline bool operator()(const T& a, const T& b) const |
29 | 863k | { |
30 | 863k | return (a.getLoad() > b.getLoad()); |
31 | 863k | } _ZNK12TreeStrategy14CmpLoadGreaterINS_3ObjILi1ELb0EEELb0EEclERKS2_S5_ Line | Count | Source | 29 | 682k | { | 30 | 682k | return (a.getLoad() > b.getLoad()); | 31 | 682k | } |
Unexecuted instantiation: _ZNK12TreeStrategy14CmpLoadGreaterINS_4ProcILi1ELb1ELb0EEELb0EEclERKS2_S5_ _ZNK12TreeStrategy14CmpLoadGreaterINS_4ProcILi1ELb0ELb0EEELb0EEclERKS2_S5_ Line | Count | Source | 29 | 180k | { | 30 | 180k | return (a.getLoad() > b.getLoad()); | 31 | 180k | } |
|
32 | | }; |
33 | | |
34 | | template <typename T, bool is_ptr = std::is_pointer<T>::value> |
35 | | struct CmpLoadLess |
36 | | { |
37 | | }; |
38 | | |
39 | | template <typename T> |
40 | | struct CmpLoadLess<T, true> |
41 | | { |
42 | | inline bool operator()(const T a, const T b) const |
43 | | { |
44 | | return (a->getLoad() < b->getLoad()); |
45 | | } |
46 | | }; |
47 | | |
48 | | template <typename T> |
49 | | struct CmpLoadLess<T, false> |
50 | | { |
51 | | inline bool operator()(const T& a, const T& b) const |
52 | 9 | { |
53 | 9 | return (a.getLoad() < b.getLoad()); |
54 | 9 | } Unexecuted instantiation: _ZNK12TreeStrategy11CmpLoadLessINS_4ProcILi1ELb1ELb0EEELb0EEclERKS2_S5_ _ZNK12TreeStrategy11CmpLoadLessINS_4ProcILi1ELb0ELb0EEELb0EEclERKS2_S5_ Line | Count | Source | 52 | 9 | { | 53 | 9 | return (a.getLoad() < b.getLoad()); | 54 | 9 | } |
|
55 | | }; |
56 | | |
57 | | template <typename T, bool is_ptr = std::is_pointer<T>::value> |
58 | | struct CmpId |
59 | | { |
60 | | }; |
61 | | |
62 | | template <typename T> |
63 | | struct CmpId<T, true> |
64 | | { |
65 | | inline bool operator()(const T a, const T b) const { return (a->id < b->id); } |
66 | | }; |
67 | | |
68 | | template <typename T> |
69 | | struct CmpId<T, false> |
70 | | { |
71 | 1.15k | inline bool operator()(const T& a, const T& b) const { return (a.id < b.id); }Unexecuted instantiation: _ZNK12TreeStrategy5CmpIdINS_4ProcILi1ELb1ELb0EEELb0EEclERKS2_S5_ _ZNK12TreeStrategy5CmpIdINS_4ProcILi1ELb0ELb0EEELb0EEclERKS2_S5_ Line | Count | Source | 71 | 1.15k | inline bool operator()(const T& a, const T& b) const { return (a.id < b.id); } |
|
72 | | }; |
73 | | |
74 | | template <typename T> |
75 | | T* ptr(T& obj) |
76 | 14.9k | { |
77 | 14.9k | return &obj; |
78 | 14.9k | } // turn reference into pointer _ZN12TreeStrategy3ptrIKNS_3ObjILi1ELb0EEEEEPT_RS4_ Line | Count | Source | 76 | 704 | { | 77 | 704 | return &obj; | 78 | 704 | } // turn reference into pointer |
Unexecuted instantiation: _ZN12TreeStrategy3ptrIKNS_4ProcILi1ELb1ELb0EEEEEPT_RS4_ Unexecuted instantiation: _ZN12TreeStrategy3ptrINS_4ProcILi1ELb1ELb0EEEEEPT_RS3_ _ZN12TreeStrategy3ptrIKNS_4ProcILi1ELb0ELb0EEEEEPT_RS4_ Line | Count | Source | 76 | 566 | { | 77 | 566 | return &obj; | 78 | 566 | } // turn reference into pointer |
_ZN12TreeStrategy3ptrINS_4ProcILi1ELb0ELb0EEEEEPT_RS3_ Line | Count | Source | 76 | 13.7k | { | 77 | 13.7k | return &obj; | 78 | 13.7k | } // turn reference into pointer |
|
79 | | |
80 | | template <typename T> |
81 | | T* ptr(T* obj) |
82 | | { |
83 | | return obj; |
84 | | } // obj is already pointer, return it |
85 | | |
86 | | // ---------------- Obj -------------------- |
87 | | |
88 | | struct obj_1_data |
89 | | { |
90 | | float load; |
91 | | }; |
92 | | template <int N> |
93 | | struct obj_N_data |
94 | | { |
95 | | float load[N]; |
96 | | float maxload; |
97 | | }; |
98 | | |
99 | | template <int N, bool multi = (N > 1)> |
100 | | class Obj : public std::conditional<multi, obj_N_data<N>, obj_1_data>::type |
101 | | { |
102 | | public: |
103 | | int id; |
104 | | int oldPe; |
105 | | |
106 | | inline void populate(int _id, float* _load, int _oldPe) |
107 | | { |
108 | | id = _id; |
109 | | oldPe = _oldPe; |
110 | | this->maxload = 0; |
111 | | for (int i = 0; i < N; i++) |
112 | | { |
113 | | this->load[i] = _load[i]; |
114 | | if (this->load[i] > this->maxload) this->maxload = this->load[i]; |
115 | | } |
116 | | } |
117 | | |
118 | | inline float getLoad() const { return this->maxload; } |
119 | | }; |
120 | | |
121 | | template <> |
122 | | inline void Obj<1>::populate(int _id, float* _load, int _oldPe) |
123 | 65.0k | { |
124 | 65.0k | id = _id; |
125 | 65.0k | load = *_load; |
126 | 65.0k | oldPe = _oldPe; |
127 | 65.0k | } |
128 | | |
129 | | template <> |
130 | | inline float Obj<1>::getLoad() const |
131 | 1.49M | { |
132 | 1.49M | return load; |
133 | 1.49M | } |
134 | | |
135 | | // ------------------ Proc ------------------ |
136 | | |
137 | | /** |
138 | | * class Proc<int N, bool rateAware> |
139 | | * This just shows the interface. only the specializations (below) are defined |
140 | | * N: number of dimensions of vector load |
141 | | * rateAware: true if speed aware, false otherwise |
142 | | */ |
143 | | template <int N, bool rateAware, bool multi = (N > 1)> |
144 | | class Proc |
145 | | { |
146 | | public: |
147 | | void populate(int _id, float* _bgload, float* _speed); |
148 | | float getLoad() const; // returns current load of processor |
149 | | void assign(const Obj<N>* o); // add object loads to this processor's loads |
150 | | void assign(const Obj<N>& o); // add object loads to this processor's loads |
151 | | void resetLoad(); // sets processor loads to background loads |
152 | | }; |
153 | | |
154 | | template <int N> |
155 | | struct proc_N_data |
156 | | { |
157 | | float load[N] = {0}; |
158 | | float bgload[N] = {0}; |
159 | | float maxload = 0; |
160 | | }; |
161 | | struct proc_1_data |
162 | | { |
163 | | float load = 0; |
164 | | float bgload = 0; |
165 | | }; |
166 | | |
167 | | // --------- Proc rateAware=false specializations --------- |
168 | | |
169 | | template <int N, bool multi> |
170 | | class Proc<N, false, multi> |
171 | | : public std::conditional<multi, proc_N_data<N>, proc_1_data>::type |
172 | | { |
173 | | public: |
174 | | int id = -1; |
175 | | |
176 | | inline void populate(int _id, float* _bgload, float* _speed) |
177 | | { |
178 | | id = _id; |
179 | | std::copy_n(_bgload, N, this->bgload); |
180 | | } |
181 | | |
182 | | inline float getLoad() const { return this->maxload; } |
183 | | |
184 | | inline void assign(const Obj<N>* o) |
185 | | { |
186 | | for (int i = 0; i < N; i++) |
187 | | { |
188 | | this->load[i] += o->load[i]; |
189 | | if (this->load[i] > this->maxload) this->maxload = this->load[i]; |
190 | | } |
191 | | } |
192 | 131k | inline void assign(const Obj<N>& o) { assign(&o); } |
193 | | |
194 | | inline void resetLoad() |
195 | | { |
196 | | this->maxload = 0; |
197 | | for (int i = 0; i < N; i++) |
198 | | { |
199 | | this->load[i] = this->bgload[i]; |
200 | | if (this->load[i] > this->maxload) this->maxload = this->load[i]; |
201 | | } |
202 | | } |
203 | | }; |
204 | | |
205 | | template <> |
206 | | void Proc<1, false>::populate(int _id, float* _bgload, float* _speed) |
207 | 3.72k | { |
208 | 3.72k | id = _id; |
209 | 3.72k | this->bgload = *_bgload; |
210 | 3.72k | } |
211 | | template <> |
212 | | float Proc<1, false>::getLoad() const |
213 | 442k | { |
214 | 442k | return this->load; |
215 | 442k | } |
216 | | template <> |
217 | | void Proc<1, false>::assign(const Obj<1>* o) |
218 | 196k | { |
219 | 196k | this->load += o->load; |
220 | 196k | } |
221 | | template <> |
222 | | void Proc<1, false>::resetLoad() |
223 | 11.1k | { |
224 | 11.1k | this->load = this->bgload; |
225 | 11.1k | } |
226 | | |
227 | | // --------- Proc rateAware=true specializations --------- |
228 | | |
229 | | // TODO further specialize for N=1 by having speed not be an array? |
230 | | |
231 | | template <int N, bool multi> |
232 | | class Proc<N, true, multi> |
233 | | : public std::conditional<multi, proc_N_data<N>, proc_1_data>::type |
234 | | { |
235 | | public: |
236 | | int id = -1; |
237 | | float speed[N] = {1.0}; |
238 | | |
239 | | inline void populate(int _id, float* _bgload, float* _speed) |
240 | | { |
241 | | id = _id; |
242 | | std::copy_n(_bgload, N, this->bgload); |
243 | | std::copy_n(_speed, N, this->speed); |
244 | | } |
245 | | |
246 | | inline float getLoad() const { return this->maxload; } |
247 | | |
248 | | inline void assign(const Obj<N>* o) |
249 | | { |
250 | | for (int i = 0; i < N; i++) |
251 | | { |
252 | | this->load[i] += (o->load[i] / speed[i]); |
253 | | if (this->load[i] > this->maxload) this->maxload = this->load[i]; |
254 | | } |
255 | | } |
256 | 0 | inline void assign(const Obj<N>& o) { assign(&o); } |
257 | | |
258 | | inline void resetLoad() |
259 | | { |
260 | | this->maxload = 0; |
261 | | for (int i = 0; i < N; i++) |
262 | | { |
263 | | this->load[i] = this->bgload[i]; |
264 | | if (this->load[i] > this->maxload) this->maxload = this->load[i]; |
265 | | } |
266 | | } |
267 | | }; |
268 | | |
269 | | template <> |
270 | | void Proc<1, true>::populate(int _id, float* _bgload, float* _speed) |
271 | 0 | { |
272 | 0 | id = _id; |
273 | 0 | this->bgload = *_bgload; |
274 | 0 | speed[0] = _speed[0]; |
275 | 0 | } |
276 | | template <> |
277 | | float Proc<1, true>::getLoad() const |
278 | 0 | { |
279 | 0 | return this->load; |
280 | 0 | } |
281 | | template <> |
282 | | void Proc<1, true>::assign(const Obj<1>* o) |
283 | 0 | { |
284 | 0 | this->load += (o->load / speed[0]); |
285 | 0 | } |
286 | | template <> |
287 | | void Proc<1, true>::resetLoad() |
288 | 0 | { |
289 | 0 | this->load = this->bgload; |
290 | 0 | } |
291 | | |
292 | | // ---------------- Strategy -------------------- |
293 | | |
294 | | template <typename O, typename P, typename S> |
295 | | class Strategy |
296 | | { |
297 | | public: |
298 | | virtual void solve(std::vector<O>& objs, std::vector<P>& procs, S& solution, |
299 | | bool objsSorted = false) = 0; |
300 | 129 | virtual ~Strategy() {}Unexecuted instantiation: _ZN12TreeStrategy8StrategyINS_3ObjILi1ELb0EEENS_4ProcILi1ELb1ELb0EEEN15StrategyWrapperIS2_S4_E8SolutionEED2Ev Unexecuted instantiation: _ZN12TreeStrategy8StrategyINS_3ObjILi1ELb0EEENS_4ProcILi1ELb1ELb0EEENS_14GreedySolutionIS2_S4_EEED2Ev Unexecuted instantiation: _ZN12TreeStrategy8StrategyINS_3ObjILi1ELb0EEENS_4ProcILi1ELb0ELb0EEEN15StrategyWrapperIS2_S4_E8SolutionEED2Ev _ZN12TreeStrategy8StrategyINS_3ObjILi1ELb0EEENS_4ProcILi1ELb0ELb0EEENS_14GreedySolutionIS2_S4_EEED2Ev Line | Count | Source | 300 | 129 | virtual ~Strategy() {} |
|
301 | | }; |
302 | | |
303 | | template <typename O, typename P, typename S> |
304 | | class Random : public Strategy<O, P, S> |
305 | | { |
306 | | public: |
307 | | Random() |
308 | 32 | { |
309 | 32 | std::random_device rd; |
310 | 32 | rng = std::mt19937(rd()); |
311 | 32 | } Unexecuted instantiation: _ZN12TreeStrategy6RandomINS_3ObjILi1ELb0EEENS_4ProcILi1ELb1ELb0EEEN15StrategyWrapperIS2_S4_E8SolutionEEC2Ev _ZN12TreeStrategy6RandomINS_3ObjILi1ELb0EEENS_4ProcILi1ELb0ELb0EEEN15StrategyWrapperIS2_S4_E8SolutionEEC2Ev Line | Count | Source | 308 | 32 | { | 309 | 32 | std::random_device rd; | 310 | 32 | rng = std::mt19937(rd()); | 311 | 32 | } |
|
312 | | void solve(std::vector<O>& objs, std::vector<P>& procs, S& solution, bool objsSorted) |
313 | 520 | { |
314 | 520 | std::uniform_int_distribution<int> uni(0, procs.size() - 1); |
315 | 4.80k | for (const auto& o : objs) solution.assign(o, procs[uni(rng)]); |
316 | 520 | } Unexecuted instantiation: _ZN12TreeStrategy6RandomINS_3ObjILi1ELb0EEENS_4ProcILi1ELb1ELb0EEEN15StrategyWrapperIS2_S4_E8SolutionEE5solveERSt6vectorIS2_SaIS2_EERS9_IS4_SaIS4_EERS7_b _ZN12TreeStrategy6RandomINS_3ObjILi1ELb0EEENS_4ProcILi1ELb0ELb0EEEN15StrategyWrapperIS2_S4_E8SolutionEE5solveERSt6vectorIS2_SaIS2_EERS9_IS4_SaIS4_EERS7_b Line | Count | Source | 313 | 520 | { | 314 | 520 | std::uniform_int_distribution<int> uni(0, procs.size() - 1); | 315 | 4.80k | for (const auto& o : objs) solution.assign(o, procs[uni(rng)]); | 316 | 520 | } |
|
317 | | |
318 | | private: |
319 | | std::mt19937 rng; |
320 | | }; |
321 | | |
322 | | template <typename O, typename P, typename S> |
323 | | class Dummy : public Strategy<O, P, S> |
324 | | { |
325 | | public: |
326 | 0 | void solve(std::vector<O>& objs, std::vector<P>& procs, S& solution, bool objsSorted) { |
327 | 0 | } // do nothing Unexecuted instantiation: _ZN12TreeStrategy5DummyINS_3ObjILi1ELb0EEENS_4ProcILi1ELb1ELb0EEEN15StrategyWrapperIS2_S4_E8SolutionEE5solveERSt6vectorIS2_SaIS2_EERS9_IS4_SaIS4_EERS7_b Unexecuted instantiation: _ZN12TreeStrategy5DummyINS_3ObjILi1ELb0EEENS_4ProcILi1ELb0ELb0EEEN15StrategyWrapperIS2_S4_E8SolutionEE5solveERSt6vectorIS2_SaIS2_EERS9_IS4_SaIS4_EERS7_b |
328 | | }; |
329 | | |
330 | | template <typename O, typename P, typename S> |
331 | | class Rotate : public Strategy<O, P, S> |
332 | | { |
333 | | public: |
334 | | void solve(std::vector<O>& objs, std::vector<P>& procs, S& solution, bool objsSorted) |
335 | 202 | { |
336 | 202 | std::sort(procs.begin(), procs.end(), CmpId<P>()); |
337 | | // could use unordered_map but vector is faster and doesn't require much memory, even |
338 | | // for a few million PEs |
339 | 202 | std::vector<int> procMap(CkNumPes(), -1); // real pe -> idx in procs |
340 | 958 | for (int i = 0; i < procs.size(); i++) procMap[procs[i].id] = i; |
341 | 202 | for (const auto& o : objs) |
342 | 5.60k | { |
343 | 5.60k | if (procMap[o.oldPe] == -1) CkAbort("Rotate does not support foreign objects\n"); |
344 | 5.60k | P& p = procs[(procMap[o.oldPe] + 1) % procs.size()]; |
345 | 5.60k | solution.assign(o, p); |
346 | | // fprintf(stderr, "Moving object %d from PE %d to %d\n", o.id, o.oldPe, p.id); |
347 | 5.60k | } |
348 | 202 | } Unexecuted instantiation: _ZN12TreeStrategy6RotateINS_3ObjILi1ELb0EEENS_4ProcILi1ELb1ELb0EEEN15StrategyWrapperIS2_S4_E8SolutionEE5solveERSt6vectorIS2_SaIS2_EERS9_IS4_SaIS4_EERS7_b _ZN12TreeStrategy6RotateINS_3ObjILi1ELb0EEENS_4ProcILi1ELb0ELb0EEEN15StrategyWrapperIS2_S4_E8SolutionEE5solveERSt6vectorIS2_SaIS2_EERS9_IS4_SaIS4_EERS7_b Line | Count | Source | 335 | 202 | { | 336 | 202 | std::sort(procs.begin(), procs.end(), CmpId<P>()); | 337 | | // could use unordered_map but vector is faster and doesn't require much memory, even | 338 | | // for a few million PEs | 339 | 202 | std::vector<int> procMap(CkNumPes(), -1); // real pe -> idx in procs | 340 | 958 | for (int i = 0; i < procs.size(); i++) procMap[procs[i].id] = i; | 341 | 202 | for (const auto& o : objs) | 342 | 5.60k | { | 343 | 5.60k | if (procMap[o.oldPe] == -1) CkAbort("Rotate does not support foreign objects\n"); | 344 | 5.60k | P& p = procs[(procMap[o.oldPe] + 1) % procs.size()]; | 345 | 5.60k | solution.assign(o, p); | 346 | | // fprintf(stderr, "Moving object %d from PE %d to %d\n", o.id, o.oldPe, p.id); | 347 | 5.60k | } | 348 | 202 | } |
|
349 | | }; |
350 | | |
351 | | } // namespace TreeStrategy |
352 | | |
353 | | #endif /* TREESTRATEGYBASE_H */ |