Coverage Report

Created: 2026-10-28 17:42

/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 */