OoOJoin  0.0.1
The next generation of out-of-order join operator
ThreadPerf.hpp
Go to the documentation of this file.
1 
2 //
3 // Created by tony on 06/12/22.
4 //
5 
6 #ifndef INTELLISTREAM_INCLUDE_UTILS_THREADPERF_H_
7 #define INTELLISTREAM_INCLUDE_UTILS_THREADPERF_H_
8 #pragma once
9 #include <string>
10 #include <sys/time.h>
11 #include <assert.h>
12 #include <fcntl.h>
13 #include <inttypes.h>
14 #include <math.h>
15 #include <stdint.h>
16 #include <stdio.h>
17 #include <stdlib.h>
18 #include <string.h>
19 #include <sys/syscall.h>
20 #include <sys/types.h>
21 #include <sys/ioctl.h>
22 #include <sys/stat.h>
23 #include <time.h>
24 #include <unistd.h>
25 #include <linux/perf_event.h>
26 #include <signal.h>
27 #include <memory.h>
28 #include <memory>
29 #include <vector>
30 #include <Utils/ConfigMap.hpp>
31 #define PERF_ERROR(n) printf(n)
32 namespace INTELLI {
37 enum perfTrace {
38  /* sw tracepoints */
39  COUNT_SW_CPU_CLOCK = 0,
40  COUNT_SW_TASK_CLOCK = 1,
41  COUNT_SW_CONTEXT_SWITCHES = 2,
42  COUNT_SW_CPU_MIGRATIONS = 3,
43  COUNT_SW_PAGE_FAULTS = 4,
44  COUNT_SW_PAGE_FAULTS_MIN = 5,
45  COUNT_SW_PAGE_FAULTS_MAJ = 6,
46 
47  /* hw counters */
48  COUNT_HW_CPU_CYCLES = 7,
49  COUNT_HW_INSTRUCTIONS = 8,
50  COUNT_HW_CACHE_REFERENCES = 9,
51  COUNT_HW_CACHE_MISSES = 10,
52  COUNT_HW_BRANCH_INSTRUCTIONS = 11,
53  COUNT_HW_BRANCH_MISSES = 12,
54  COUNT_HW_BUS_CYCLES = 13,
55 
56  /* cache counters */
57 
58  /* L1D - data cache */
59  COUNT_HW_CACHE_L1D_LOADS = 14,
60  COUNT_HW_CACHE_L1D_LOADS_MISSES = 15,
61  COUNT_HW_CACHE_L1D_STORES = 16,
62  COUNT_HW_CACHE_L1D_STORES_MISSES = 17,
63  COUNT_HW_CACHE_L1D_PREFETCHES = 18,
64 
65  /* L1I - instruction cache */
66  COUNT_HW_CACHE_L1I_LOADS = 19,
67  COUNT_HW_CACHE_L1I_LOADS_MISSES = 20,
68 
69  /* LL - last level cache */
70  COUNT_HW_CACHE_LL_LOADS = 21,
71  COUNT_HW_CACHE_LL_LOADS_MISSES = 22,
72  COUNT_HW_CACHE_LL_STORES = 23,
73  COUNT_HW_CACHE_LL_STORES_MISSES = 24,
74 
75  /* DTLB - data translation lookaside buffer */
76  COUNT_HW_CACHE_DTLB_LOADS = 25,
77  COUNT_HW_CACHE_DTLB_LOADS_MISSES = 26,
78  COUNT_HW_CACHE_DTLB_STORES = 27,
79  COUNT_HW_CACHE_DTLB_STORES_MISSES = 28,
80 
81  /* ITLB - instructiont translation lookaside buffer */
82  COUNT_HW_CACHE_ITLB_LOADS = 29,
83  COUNT_HW_CACHE_ITLB_LOADS_MISSES = 30,
84 
85  /* BPU - branch prediction unit */
86  COUNT_HW_CACHE_BPU_LOADS = 31,
87  COUNT_HW_CACHE_BPU_LOADS_MISSES = 32,
88 
89  /* Special internally defined "counter" */
90  /* this is the _only_ floating point value */
91  //LIB_SW_WALL_TIME = 33
92 };
93 
109 class ThreadPerf {
110  protected:
111 
116  class PerfPair {
117  public:
118  int ref;
119  std::string name;
120  uint64_t record;
121  PerfPair(int _ref, std::string _name) {
122  ref = _ref;
123  name = _name;
124  record = 0;
125  }
126  ~PerfPair() {}
127  };
128  class PerfTool {
129  private:
134  class PerfEntry {
135  public:
136  //struct perf_event_attr attr;
137  int fds;
138  bool addressable;
139  uint64_t prevVale;
140  PerfEntry() { addressable = false; }
141  ~PerfEntry() {}
142  };
143  /* data */
144  std::vector<PerfEntry> entries;
145  pid_t myPid;
146  int myCpu;
147  uint64_t prevValue;
148 #define LIBPERF_ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]))
153  struct perf_event_attr default_attrs[32] = {
154  {.type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_CPU_CLOCK}, //1
155  {.type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_TASK_CLOCK}, //2
156  {.type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_CONTEXT_SWITCHES},//3
157  {.type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_CPU_MIGRATIONS},//4
158  {.type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_PAGE_FAULTS},//5
159  {.type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_PAGE_FAULTS_MIN},//6
160  {.type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_PAGE_FAULTS_MAJ},//7
161  {.type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_CPU_CYCLES},//8
162  {.type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_INSTRUCTIONS},//9
163  {.type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_CACHE_REFERENCES},//10
164  {.type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_CACHE_MISSES},//11
165  {.type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_BRANCH_INSTRUCTIONS},//12
166  {.type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_BRANCH_MISSES},//13
167  {.type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_BUS_CYCLES},//14
168  //15
169  {.type = PERF_TYPE_HW_CACHE, .config = (PERF_COUNT_HW_CACHE_L1D | (PERF_COUNT_HW_CACHE_OP_READ << 8)
170  | (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16))},
171  //16
172  {.type = PERF_TYPE_HW_CACHE, .config = (PERF_COUNT_HW_CACHE_L1D | (PERF_COUNT_HW_CACHE_OP_READ << 8)
173  | (PERF_COUNT_HW_CACHE_RESULT_MISS << 16))},
174  //17, no x64
175  {.type = PERF_TYPE_HW_CACHE, .config = (PERF_COUNT_HW_CACHE_L1D | (PERF_COUNT_HW_CACHE_OP_WRITE << 8)
176  | (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16))},
177  //18, no x64, no rk3399
178  {.type = PERF_TYPE_HW_CACHE, .config = (PERF_COUNT_HW_CACHE_L1D | (PERF_COUNT_HW_CACHE_OP_WRITE << 8)
179  | (PERF_COUNT_HW_CACHE_RESULT_MISS << 16))},
180  //19, no x64
181  {.type = PERF_TYPE_HW_CACHE, .config = (PERF_COUNT_HW_CACHE_L1D | (PERF_COUNT_HW_CACHE_OP_PREFETCH << 8)
182  | (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16))},
183  //20
184  {.type = PERF_TYPE_HW_CACHE, .config = (PERF_COUNT_HW_CACHE_L1I | (PERF_COUNT_HW_CACHE_OP_READ << 8)
185  | (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16))},
186  //21, no rk3399
187  {.type = PERF_TYPE_HW_CACHE, .config = (PERF_COUNT_HW_CACHE_L1I | (PERF_COUNT_HW_CACHE_OP_READ << 8)
188  | (PERF_COUNT_HW_CACHE_RESULT_MISS << 16))},
189  //22, no rk3399
190  {.type = PERF_TYPE_HW_CACHE, .config = (PERF_COUNT_HW_CACHE_LL | (PERF_COUNT_HW_CACHE_OP_READ << 8)
191  | (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16))},
192  //23, no rk3399
193  {.type = PERF_TYPE_HW_CACHE, .config = (PERF_COUNT_HW_CACHE_LL | (PERF_COUNT_HW_CACHE_OP_READ << 8)
194  | (PERF_COUNT_HW_CACHE_RESULT_MISS << 16))},
195  //24,no rk3399
196  {.type = PERF_TYPE_HW_CACHE, .config = (PERF_COUNT_HW_CACHE_LL | (PERF_COUNT_HW_CACHE_OP_WRITE << 8)
197  | (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16))},
198  //25
199  {.type = PERF_TYPE_HW_CACHE, .config = (PERF_COUNT_HW_CACHE_LL | (PERF_COUNT_HW_CACHE_OP_WRITE << 8)
200  | (PERF_COUNT_HW_CACHE_RESULT_MISS << 16))},
201  //26
202  {.type = PERF_TYPE_HW_CACHE, .config = (PERF_COUNT_HW_CACHE_DTLB | (PERF_COUNT_HW_CACHE_OP_READ << 8)
203  | (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16))},
204  //27, no rk3399
205  {.type = PERF_TYPE_HW_CACHE, .config = (PERF_COUNT_HW_CACHE_DTLB | (PERF_COUNT_HW_CACHE_OP_READ << 8)
206  | (PERF_COUNT_HW_CACHE_RESULT_MISS << 16))},
207  //28
208  {.type = PERF_TYPE_HW_CACHE, .config = (PERF_COUNT_HW_CACHE_DTLB | (PERF_COUNT_HW_CACHE_OP_WRITE << 8)
209  | (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16))},
210  //29,no rk3399
211  {.type = PERF_TYPE_HW_CACHE, .config = (PERF_COUNT_HW_CACHE_DTLB | (PERF_COUNT_HW_CACHE_OP_WRITE << 8)
212  | (PERF_COUNT_HW_CACHE_RESULT_MISS << 16))},
213  //30
214  {.type = PERF_TYPE_HW_CACHE, .config = (PERF_COUNT_HW_CACHE_ITLB | (PERF_COUNT_HW_CACHE_OP_READ << 8)
215  | (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16))},
216  //31
217  {.type = PERF_TYPE_HW_CACHE, .config = (PERF_COUNT_HW_CACHE_ITLB | (PERF_COUNT_HW_CACHE_OP_READ << 8)
218  | (PERF_COUNT_HW_CACHE_RESULT_MISS << 16))},
219  //32
220  {.type = PERF_TYPE_HW_CACHE, .config = (PERF_COUNT_HW_CACHE_BPU | (PERF_COUNT_HW_CACHE_OP_READ << 8)
221  | (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16))},
222  /* { .type = PERF_TYPE_HW_CACHE, .config = (PERF_COUNT_HW_CACHE_BPU | (PERF_COUNT_HW_CACHE_OP_READ << 8) | (PERF_COUNT_HW_CACHE_RESULT_MISS << 16))}, */
223  };
224  long
225  sys_perf_event_open(struct perf_event_attr *hw_event,
226  pid_t pid, int cpu, int group_fd,
227  unsigned long flags) {
228  return syscall(__NR_perf_event_open, hw_event, pid, cpu,
229  group_fd, flags);
230  }
231  public:
237  PerfTool() {
238 
239  }
240  PerfTool(pid_t pid, int cpu) {
241  if (pid == -1) { pid = gettid(); }
242  myPid = pid;
243  myCpu = cpu;
244  int nr_counters = 32;
245  for (int i = 0; i < nr_counters; i++) {
246  PerfEntry entry;
247  default_attrs[i].size = sizeof(struct perf_event_attr);
248  entry.fds = sys_perf_event_open(&default_attrs[i], pid, cpu, -1, 0);
249  if (entry.fds < 0) {
250  entry.addressable = false;
251  } else {
252  entry.addressable = true;
253  ioctl(entry.fds, PERF_EVENT_IOC_DISABLE);
254  ioctl(entry.fds, PERF_EVENT_IOC_RESET);
255  }
256  entries.push_back(entry);
257  }
258  }
259  ~PerfTool() {
260  for (size_t i = 0; i < entries.size(); i++) {
261  if (entries[i].addressable == true) {
262  close(entries[i].fds);
263  //printf("close perf %d\r\n",i);
264  }
265  }
266  }
267  // reading result from a perf trace on [ch], will return 0 if the channel is invaild
268  uint64_t readPerf(size_t ch) {
269  if (ch > entries.size()) {
270  return 0;
271  }
272  if (entries[ch].addressable == false) {
273  return 0;
274  }
275  uint64_t value;
276  int ru = read(entries[ch].fds, &value, sizeof(uint64_t));
277  if (ru < 0) {
278  PERF_ERROR("invalid read");
279  }
280  return value;
281  }
282  // start the perf trace on [ch]
283  int startPerf(size_t ch) {
284  ioctl(entries[ch].fds, PERF_EVENT_IOC_ENABLE);
285  return 1;
286  }
287  // st the perf trace on [ch]
288  int stopPerf(size_t ch) {
289  if (ch > entries.size()) {
290  return -1;
291  }
292  if (entries[ch].addressable == false) {
293  return -1;
294  }
295  ioctl(entries[ch].fds, PERF_EVENT_IOC_DISABLE);
296  ioctl(entries[ch].fds, PERF_EVENT_IOC_RESET);
297  return 1;
298  }
299  //check the addressability of [ch]
300  bool isValidChannel(size_t ch) {
301  if (ch > entries.size()) {
302  return false;
303  }
304  return entries[ch].addressable;
305  }
306  };
307  typedef std::shared_ptr<PerfTool> PerfToolPtr;
308  std::string getChValueAsString(size_t idx);
309 
310  PerfToolPtr myTool;
314  std::vector<PerfPair> pairs;
315  struct timeval tstart, tend;
316  uint64_t latency;
317  public:
318  ThreadPerf() {}
323  ThreadPerf(int cpu) {
324  myTool = std::make_shared<PerfTool>(0, cpu);
325  //setPerfList();
326  }
330  virtual void setPerfList() {
331  pairs.push_back(PerfPair(COUNT_HW_CPU_CYCLES, "cpuCycle"));
332  pairs.push_back(PerfPair(COUNT_HW_INSTRUCTIONS, "instructions"));
333  pairs.push_back(PerfPair(COUNT_HW_CACHE_REFERENCES, "cacheRefs"));
334  pairs.push_back(PerfPair(COUNT_HW_CACHE_MISSES, "cacheMiss"));
335  pairs.push_back(PerfPair(COUNT_SW_CPU_CLOCK, "cpuClock"));
336  pairs.push_back(PerfPair(COUNT_SW_TASK_CLOCK, "taskClock"));
337  //pairs.push_back(PerfPair(COUNT_HW_CACHE_L1I_LOADS_MISSES, "L1ILoadMiss"));
338  }
343  void start() {
344  for (size_t i = 0; i < pairs.size(); i++) {
345  myTool->startPerf(pairs[i].ref);
346  }
347  gettimeofday(&tstart, NULL);
348  }
352  void end() {
353  gettimeofday(&tend, NULL);
354  for (size_t i = 0; i < pairs.size(); i++) {
355  pairs[i].record = myTool->readPerf(pairs[i].ref);
356  myTool->stopPerf(pairs[i].ref);
357  }
358  }
364  uint64_t getResultById(size_t idx) {
365  if (idx > pairs.size()) {
366  return 0;
367  }
368  size_t ch = pairs[idx].ref;
369  if (myTool->isValidChannel(ch) == false) {
370  return 0;
371  }
372  return pairs[idx].record;
373  }
379  uint64_t getResultByName(string name) {
380  for (size_t i = 0; i < pairs.size(); i++) {
381  if (pairs[i].name == name) {
382  return pairs[i].record;
383  }
384  }
385  return 0;
386  }
393  ConfigMapPtr ru = newConfigMap();
394  for (size_t i = 0; i < pairs.size(); i++) {
395  ru->edit(pairs[i].name, (uint64_t) pairs[i].record);
396  }
397  return ru;
398  }
399 };
400 
401 }
402 #endif //INTELLISTREAM_INCLUDE_UTILS_THREADPERF_H_
perfTrace
The low level description of perf events, used inside, don't touch me UNLESS you know what you are do...
Definition: ThreadPerf.hpp:37
a record pair of perf events
Definition: ThreadPerf.hpp:116
Definition: ThreadPerf.hpp:128
The top entity to provide perf traces, please use this class only UNLESS you know what you are doing.
Definition: ThreadPerf.hpp:109
void start()
To start perf tracing.
Definition: ThreadPerf.hpp:343
virtual void setPerfList()
To set up all your interest perf events.
Definition: ThreadPerf.hpp:330
void end()
To end a perf tracing.
Definition: ThreadPerf.hpp:352
std::vector< PerfPair > pairs
To contain all of your interested perf events.
Definition: ThreadPerf.hpp:314
ConfigMapPtr resultToConfigMap()
convert the perf result into a ConfigMap
Definition: ThreadPerf.hpp:392
ThreadPerf(int cpu)
To setup this perf to specific cpu.
Definition: ThreadPerf.hpp:323
uint64_t getResultById(size_t idx)
Get the perf result by its index of PerfPair.
Definition: ThreadPerf.hpp:364
uint64_t getResultByName(string name)
Get the perf result by its name of of PerfPair.
Definition: ThreadPerf.hpp:379
#define newConfigMap
(Macro) To creat a new ConfigMap under shared pointer.
Definition: ConfigMap.hpp:362
std::shared_ptr< ConfigMap > ConfigMapPtr
The class to describe a shared pointer to ConfigMap.
Definition: ConfigMap.hpp:356
The low-level perf descriptions passed to OS.