master
c 1,356 lines 50.6 KB
Raw
1 // SPDX-License-Identifier: GPL-3.0-or-later
2
3 #include "libnetdata/libnetdata.h"
4
5 #include <linux/perf_event.h>
6
7 #define PLUGIN_PERF_NAME "perf.plugin"
8
9 // Hardware counters
10 #define NETDATA_CHART_PRIO_PERF_CPU_CYCLES 8800
11 #define NETDATA_CHART_PRIO_PERF_INSTRUCTIONS 8801
12 #define NETDATA_CHART_PRIO_PERF_IPC 8802
13 #define NETDATA_CHART_PRIO_PERF_BRANCH_INSTRUCTIONS 8803
14 #define NETDATA_CHART_PRIO_PERF_CACHE 8804
15 #define NETDATA_CHART_PRIO_PERF_BUS_CYCLES 8805
16 #define NETDATA_CHART_PRIO_PERF_FRONT_BACK_CYCLES 8806
17
18 // Software counters
19 #define NETDATA_CHART_PRIO_PERF_MIGRATIONS 8810
20 #define NETDATA_CHART_PRIO_PERF_ALIGNMENT 8811
21 #define NETDATA_CHART_PRIO_PERF_EMULATION 8812
22
23 // Hardware cache counters
24 #define NETDATA_CHART_PRIO_PERF_L1D 8820
25 #define NETDATA_CHART_PRIO_PERF_L1D_PREFETCH 8821
26 #define NETDATA_CHART_PRIO_PERF_L1I 8822
27 #define NETDATA_CHART_PRIO_PERF_LL 8823
28 #define NETDATA_CHART_PRIO_PERF_DTLB 8824
29 #define NETDATA_CHART_PRIO_PERF_ITLB 8825
30 #define NETDATA_CHART_PRIO_PERF_PBU 8826
31
32 #define RRD_TYPE_PERF "perf"
33 #define RRD_FAMILY_HW "hardware"
34 #define RRD_FAMILY_SW "software"
35 #define RRD_FAMILY_CACHE "cache"
36
37 #define NO_FD (-1)
38 #define ALL_PIDS (-1)
39 #define RUNNING_THRESHOLD 100
40
41 static int debug = 0;
42
43 static int update_every = 1;
44 static int freq = 0;
45
46 typedef enum perf_event_id {
47 // Hardware counters
48 EV_ID_CPU_CYCLES,
49 EV_ID_INSTRUCTIONS,
50 EV_ID_CACHE_REFERENCES,
51 EV_ID_CACHE_MISSES,
52 EV_ID_BRANCH_INSTRUCTIONS,
53 EV_ID_BRANCH_MISSES,
54 EV_ID_BUS_CYCLES,
55 EV_ID_STALLED_CYCLES_FRONTEND,
56 EV_ID_STALLED_CYCLES_BACKEND,
57 EV_ID_REF_CPU_CYCLES,
58
59 // Software counters
60 // EV_ID_CPU_CLOCK,
61 // EV_ID_TASK_CLOCK,
62 // EV_ID_PAGE_FAULTS,
63 // EV_ID_CONTEXT_SWITCHES,
64 EV_ID_CPU_MIGRATIONS,
65 // EV_ID_PAGE_FAULTS_MIN,
66 // EV_ID_PAGE_FAULTS_MAJ,
67 EV_ID_ALIGNMENT_FAULTS,
68 EV_ID_EMULATION_FAULTS,
69
70 // Hardware cache counters
71 EV_ID_L1D_READ_ACCESS,
72 EV_ID_L1D_READ_MISS,
73 EV_ID_L1D_WRITE_ACCESS,
74 EV_ID_L1D_WRITE_MISS,
75 EV_ID_L1D_PREFETCH_ACCESS,
76
77 EV_ID_L1I_READ_ACCESS,
78 EV_ID_L1I_READ_MISS,
79
80 EV_ID_LL_READ_ACCESS,
81 EV_ID_LL_READ_MISS,
82 EV_ID_LL_WRITE_ACCESS,
83 EV_ID_LL_WRITE_MISS,
84
85 EV_ID_DTLB_READ_ACCESS,
86 EV_ID_DTLB_READ_MISS,
87 EV_ID_DTLB_WRITE_ACCESS,
88 EV_ID_DTLB_WRITE_MISS,
89
90 EV_ID_ITLB_READ_ACCESS,
91 EV_ID_ITLB_READ_MISS,
92
93 EV_ID_PBU_READ_ACCESS,
94
95 EV_ID_END
96 } perf_event_id_t;
97
98 enum perf_event_group {
99 EV_GROUP_CYCLES,
100 EV_GROUP_INSTRUCTIONS_AND_CACHE,
101 EV_GROUP_SOFTWARE,
102 EV_GROUP_CACHE_L1D,
103 EV_GROUP_CACHE_L1I_LL_DTLB,
104 EV_GROUP_CACHE_ITLB_BPU,
105
106 EV_GROUP_NUM
107 };
108
109 static int number_of_cpus;
110
111 static int *group_leader_fds[EV_GROUP_NUM];
112
113 static struct perf_event {
114 perf_event_id_t id;
115
116 int type;
117 int config;
118
119 int **group_leader_fd;
120 int *fd;
121
122 int disabled;
123 int updated;
124
125 uint64_t value;
126
127 uint64_t *prev_value;
128 uint64_t *prev_time_enabled;
129 uint64_t *prev_time_running;
130 } perf_events[] = {
131 // Hardware counters
132 {EV_ID_CPU_CYCLES, PERF_TYPE_HARDWARE, PERF_COUNT_HW_CPU_CYCLES, &group_leader_fds[EV_GROUP_CYCLES], NULL, 1, 0, 0, NULL, NULL, NULL},
133 {EV_ID_INSTRUCTIONS, PERF_TYPE_HARDWARE, PERF_COUNT_HW_INSTRUCTIONS, &group_leader_fds[EV_GROUP_INSTRUCTIONS_AND_CACHE], NULL, 1, 0, 0, NULL, NULL, NULL},
134 {EV_ID_CACHE_REFERENCES, PERF_TYPE_HARDWARE, PERF_COUNT_HW_CACHE_REFERENCES, &group_leader_fds[EV_GROUP_INSTRUCTIONS_AND_CACHE], NULL, 1, 0, 0, NULL, NULL, NULL},
135 {EV_ID_CACHE_MISSES, PERF_TYPE_HARDWARE, PERF_COUNT_HW_CACHE_MISSES, &group_leader_fds[EV_GROUP_INSTRUCTIONS_AND_CACHE], NULL, 1, 0, 0, NULL, NULL, NULL},
136 {EV_ID_BRANCH_INSTRUCTIONS, PERF_TYPE_HARDWARE, PERF_COUNT_HW_BRANCH_INSTRUCTIONS, &group_leader_fds[EV_GROUP_INSTRUCTIONS_AND_CACHE], NULL, 1, 0, 0, NULL, NULL, NULL},
137 {EV_ID_BRANCH_MISSES, PERF_TYPE_HARDWARE, PERF_COUNT_HW_BRANCH_MISSES, &group_leader_fds[EV_GROUP_INSTRUCTIONS_AND_CACHE], NULL, 1, 0, 0, NULL, NULL, NULL},
138 {EV_ID_BUS_CYCLES, PERF_TYPE_HARDWARE, PERF_COUNT_HW_BUS_CYCLES, &group_leader_fds[EV_GROUP_CYCLES], NULL, 1, 0, 0, NULL, NULL, NULL},
139 {EV_ID_STALLED_CYCLES_FRONTEND, PERF_TYPE_HARDWARE, PERF_COUNT_HW_STALLED_CYCLES_FRONTEND, &group_leader_fds[EV_GROUP_CYCLES], NULL, 1, 0, 0, NULL, NULL, NULL},
140 {EV_ID_STALLED_CYCLES_BACKEND, PERF_TYPE_HARDWARE, PERF_COUNT_HW_STALLED_CYCLES_BACKEND, &group_leader_fds[EV_GROUP_CYCLES], NULL, 1, 0, 0, NULL, NULL, NULL},
141 {EV_ID_REF_CPU_CYCLES, PERF_TYPE_HARDWARE, PERF_COUNT_HW_REF_CPU_CYCLES, &group_leader_fds[EV_GROUP_CYCLES], NULL, 1, 0, 0, NULL, NULL, NULL},
142
143 // Software counters
144 // {EV_ID_CPU_CLOCK, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_CPU_CLOCK, &group_leader_fds[EV_GROUP_SOFTWARE], NULL, 1, 0, 0, NULL, NULL, NULL},
145 // {EV_ID_TASK_CLOCK, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_TASK_CLOCK, &group_leader_fds[EV_GROUP_SOFTWARE], NULL, 1, 0, 0, NULL, NULL, NULL},
146 // {EV_ID_PAGE_FAULTS, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_PAGE_FAULTS, &group_leader_fds[EV_GROUP_SOFTWARE], NULL, 1, 0, 0, NULL, NULL, NULL},
147 // {EV_ID_CONTEXT_SWITCHES, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_CONTEXT_SWITCHES, &group_leader_fds[EV_GROUP_SOFTWARE], NULL, 1, 0, 0, NULL, NULL, NULL},
148 {EV_ID_CPU_MIGRATIONS, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_CPU_MIGRATIONS, &group_leader_fds[EV_GROUP_SOFTWARE], NULL, 1, 0, 0, NULL, NULL, NULL},
149 // {EV_ID_PAGE_FAULTS_MIN, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_PAGE_FAULTS_MIN, &group_leader_fds[EV_GROUP_SOFTWARE], NULL, 1, 0, 0, NULL, NULL, NULL},
150 // {EV_ID_PAGE_FAULTS_MAJ, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_PAGE_FAULTS_MAJ, &group_leader_fds[EV_GROUP_SOFTWARE], NULL, 1, 0, 0, NULL, NULL, NULL},
151 {EV_ID_ALIGNMENT_FAULTS, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_ALIGNMENT_FAULTS, &group_leader_fds[EV_GROUP_SOFTWARE], NULL, 1, 0, 0, NULL, NULL, NULL},
152 {EV_ID_EMULATION_FAULTS, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_EMULATION_FAULTS, &group_leader_fds[EV_GROUP_SOFTWARE], NULL, 1, 0, 0, NULL, NULL, NULL},
153
154 // Hardware cache counters
155 {
156 EV_ID_L1D_READ_ACCESS, PERF_TYPE_HW_CACHE,
157 (PERF_COUNT_HW_CACHE_L1D) | (PERF_COUNT_HW_CACHE_OP_READ << 8) | (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16),
158 &group_leader_fds[EV_GROUP_CACHE_L1D], NULL, 1, 0, 0, NULL, NULL, NULL
159 }, {
160 EV_ID_L1D_READ_MISS, PERF_TYPE_HW_CACHE,
161 (PERF_COUNT_HW_CACHE_L1D) | (PERF_COUNT_HW_CACHE_OP_READ << 8) | (PERF_COUNT_HW_CACHE_RESULT_MISS << 16),
162 &group_leader_fds[EV_GROUP_CACHE_L1D], NULL, 1, 0, 0, NULL, NULL, NULL
163 }, {
164 EV_ID_L1D_WRITE_ACCESS, PERF_TYPE_HW_CACHE,
165 (PERF_COUNT_HW_CACHE_L1D) | (PERF_COUNT_HW_CACHE_OP_WRITE << 8) | (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16),
166 &group_leader_fds[EV_GROUP_CACHE_L1D], NULL, 1, 0, 0, NULL, NULL, NULL
167 }, {
168 EV_ID_L1D_WRITE_MISS, PERF_TYPE_HW_CACHE,
169 (PERF_COUNT_HW_CACHE_L1D) | (PERF_COUNT_HW_CACHE_OP_WRITE << 8) | (PERF_COUNT_HW_CACHE_RESULT_MISS << 16),
170 &group_leader_fds[EV_GROUP_CACHE_L1D], NULL, 1, 0, 0, NULL, NULL, NULL
171 }, {
172 EV_ID_L1D_PREFETCH_ACCESS, PERF_TYPE_HW_CACHE,
173 (PERF_COUNT_HW_CACHE_L1D) | (PERF_COUNT_HW_CACHE_OP_PREFETCH << 8) | (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16),
174 &group_leader_fds[EV_GROUP_CACHE_L1D], NULL, 1, 0, 0, NULL, NULL, NULL
175 },
176
177 {
178 EV_ID_L1I_READ_ACCESS, PERF_TYPE_HW_CACHE,
179 (PERF_COUNT_HW_CACHE_L1I) | (PERF_COUNT_HW_CACHE_OP_READ << 8) | (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16),
180 &group_leader_fds[EV_GROUP_CACHE_L1I_LL_DTLB], NULL, 1, 0, 0, NULL, NULL, NULL
181 }, {
182 EV_ID_L1I_READ_MISS, PERF_TYPE_HW_CACHE,
183 (PERF_COUNT_HW_CACHE_L1I) | (PERF_COUNT_HW_CACHE_OP_READ << 8) | (PERF_COUNT_HW_CACHE_RESULT_MISS << 16),
184 &group_leader_fds[EV_GROUP_CACHE_L1I_LL_DTLB], NULL, 1, 0, 0, NULL, NULL, NULL
185 },
186
187 {
188 EV_ID_LL_READ_ACCESS, PERF_TYPE_HW_CACHE,
189 (PERF_COUNT_HW_CACHE_LL) | (PERF_COUNT_HW_CACHE_OP_READ << 8) | (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16),
190 &group_leader_fds[EV_GROUP_CACHE_L1I_LL_DTLB], NULL, 1, 0, 0, NULL, NULL, NULL
191 }, {
192 EV_ID_LL_READ_MISS, PERF_TYPE_HW_CACHE,
193 (PERF_COUNT_HW_CACHE_LL) | (PERF_COUNT_HW_CACHE_OP_READ << 8) | (PERF_COUNT_HW_CACHE_RESULT_MISS << 16),
194 &group_leader_fds[EV_GROUP_CACHE_L1I_LL_DTLB], NULL, 1, 0, 0, NULL, NULL, NULL
195 }, {
196 EV_ID_LL_WRITE_ACCESS, PERF_TYPE_HW_CACHE,
197 (PERF_COUNT_HW_CACHE_LL) | (PERF_COUNT_HW_CACHE_OP_WRITE << 8) | (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16),
198 &group_leader_fds[EV_GROUP_CACHE_L1I_LL_DTLB], NULL, 1, 0, 0, NULL, NULL, NULL
199 }, {
200 EV_ID_LL_WRITE_MISS, PERF_TYPE_HW_CACHE,
201 (PERF_COUNT_HW_CACHE_LL) | (PERF_COUNT_HW_CACHE_OP_WRITE << 8) | (PERF_COUNT_HW_CACHE_RESULT_MISS << 16),
202 &group_leader_fds[EV_GROUP_CACHE_L1I_LL_DTLB], NULL, 1, 0, 0, NULL, NULL, NULL
203 },
204
205 {
206 EV_ID_DTLB_READ_ACCESS, PERF_TYPE_HW_CACHE,
207 (PERF_COUNT_HW_CACHE_DTLB) | (PERF_COUNT_HW_CACHE_OP_READ << 8) | (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16),
208 &group_leader_fds[EV_GROUP_CACHE_L1I_LL_DTLB], NULL, 1, 0, 0, NULL, NULL, NULL
209 }, {
210 EV_ID_DTLB_READ_MISS, PERF_TYPE_HW_CACHE,
211 (PERF_COUNT_HW_CACHE_DTLB) | (PERF_COUNT_HW_CACHE_OP_READ << 8) | (PERF_COUNT_HW_CACHE_RESULT_MISS << 16),
212 &group_leader_fds[EV_GROUP_CACHE_L1I_LL_DTLB], NULL, 1, 0, 0, NULL, NULL, NULL
213 }, {
214 EV_ID_DTLB_WRITE_ACCESS, PERF_TYPE_HW_CACHE,
215 (PERF_COUNT_HW_CACHE_DTLB) | (PERF_COUNT_HW_CACHE_OP_WRITE << 8) | (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16),
216 &group_leader_fds[EV_GROUP_CACHE_L1I_LL_DTLB], NULL, 1, 0, 0, NULL, NULL, NULL
217 }, {
218 EV_ID_DTLB_WRITE_MISS, PERF_TYPE_HW_CACHE,
219 (PERF_COUNT_HW_CACHE_DTLB) | (PERF_COUNT_HW_CACHE_OP_WRITE << 8) | (PERF_COUNT_HW_CACHE_RESULT_MISS << 16),
220 &group_leader_fds[EV_GROUP_CACHE_ITLB_BPU], NULL, 1, 0, 0, NULL, NULL, NULL
221 },
222
223 {
224 EV_ID_ITLB_READ_ACCESS, PERF_TYPE_HW_CACHE,
225 (PERF_COUNT_HW_CACHE_ITLB) | (PERF_COUNT_HW_CACHE_OP_READ << 8) | (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16),
226 &group_leader_fds[EV_GROUP_CACHE_ITLB_BPU], NULL, 1, 0, 0, NULL, NULL, NULL
227 }, {
228 EV_ID_ITLB_READ_MISS, PERF_TYPE_HW_CACHE,
229 (PERF_COUNT_HW_CACHE_ITLB) | (PERF_COUNT_HW_CACHE_OP_READ << 8) | (PERF_COUNT_HW_CACHE_RESULT_MISS << 16),
230 &group_leader_fds[EV_GROUP_CACHE_ITLB_BPU], NULL, 1, 0, 0, NULL, NULL, NULL
231 },
232
233 {
234 EV_ID_PBU_READ_ACCESS, PERF_TYPE_HW_CACHE,
235 (PERF_COUNT_HW_CACHE_BPU) | (PERF_COUNT_HW_CACHE_OP_READ << 8) | (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16),
236 &group_leader_fds[EV_GROUP_CACHE_ITLB_BPU], NULL, 1, 0, 0, NULL, NULL, NULL
237 },
238
239 {EV_ID_END, 0, 0, NULL, NULL, 0, 0, 0, NULL, NULL, NULL}
240 };
241
242 static bool perf_init() {
243 int cpu, group;
244 struct perf_event_attr perf_event_attr;
245 struct perf_event *current_event = NULL;
246 unsigned long flags = 0;
247
248 number_of_cpus = (int)os_get_system_cpus();
249
250 // initialize all perf event file descriptors
251 for(current_event = &perf_events[0]; current_event->id != EV_ID_END; current_event++) {
252 current_event->fd = mallocz(number_of_cpus * sizeof(int));
253 memset(current_event->fd, NO_FD, number_of_cpus * sizeof(int));
254
255 current_event->prev_value = mallocz(number_of_cpus * sizeof(uint64_t));
256 memset(current_event->prev_value, 0, number_of_cpus * sizeof(uint64_t));
257
258 current_event->prev_time_enabled = mallocz(number_of_cpus * sizeof(uint64_t));
259 memset(current_event->prev_time_enabled, 0, number_of_cpus * sizeof(uint64_t));
260
261 current_event->prev_time_running = mallocz(number_of_cpus * sizeof(uint64_t));
262 memset(current_event->prev_time_running, 0, number_of_cpus * sizeof(uint64_t));
263 }
264
265 for(group = 0; group < EV_GROUP_NUM; group++) {
266 group_leader_fds[group] = mallocz(number_of_cpus * sizeof(int));
267 memset(group_leader_fds[group], NO_FD, number_of_cpus * sizeof(int));
268 }
269
270 memset(&perf_event_attr, 0, sizeof(perf_event_attr));
271
272 int enabled = 0;
273
274 for(cpu = 0; cpu < number_of_cpus; cpu++) {
275 for(current_event = &perf_events[0]; current_event->id != EV_ID_END; current_event++) {
276 if(unlikely(current_event->disabled)) continue;
277
278 perf_event_attr.type = current_event->type;
279 perf_event_attr.config = current_event->config;
280 perf_event_attr.read_format = PERF_FORMAT_TOTAL_TIME_ENABLED | PERF_FORMAT_TOTAL_TIME_RUNNING;
281
282 int fd, group_leader_fd = *(*current_event->group_leader_fd + cpu);
283
284 fd = syscall(
285 __NR_perf_event_open,
286 &perf_event_attr,
287 ALL_PIDS,
288 cpu,
289 group_leader_fd,
290 flags
291 );
292
293 if(unlikely(group_leader_fd == NO_FD)) group_leader_fd = fd;
294
295 if(unlikely(fd < 0)) {
296 switch errno {
297 case EACCES:
298 collector_error("Cannot access to the PMU: Permission denied");
299 break;
300 case EBUSY:
301 collector_error("Another event already has exclusive access to the PMU");
302 break;
303 default:
304 collector_error("Cannot open perf event");
305 }
306 collector_error("Disabling event %u", current_event->id);
307 current_event->disabled = 1;
308 } else {
309 enabled++;
310 }
311
312 *(current_event->fd + cpu) = fd;
313 *(*current_event->group_leader_fd + cpu) = group_leader_fd;
314
315 if(unlikely(debug)) fprintf(stderr, "perf.plugin: event id = %u, cpu = %d, fd = %d, leader_fd = %d\n", current_event->id, cpu, fd, group_leader_fd);
316 }
317 }
318
319 return enabled > 0;
320 }
321
322 static void perf_free(void) {
323 int cpu, group;
324 struct perf_event *current_event = NULL;
325
326 for(current_event = &perf_events[0]; current_event->id != EV_ID_END; current_event++) {
327 for(cpu = 0; cpu < number_of_cpus; cpu++)
328 if(*(current_event->fd + cpu) != NO_FD) close(*(current_event->fd + cpu));
329
330 free(current_event->fd);
331 free(current_event->prev_value);
332 free(current_event->prev_time_enabled);
333 free(current_event->prev_time_running);
334 }
335
336 for(group = 0; group < EV_GROUP_NUM; group++)
337 free(group_leader_fds[group]);
338 }
339
340 static void reenable_events() {
341 int group, cpu;
342
343 for(group = 0; group < EV_GROUP_NUM; group++) {
344 for(cpu = 0; cpu < number_of_cpus; cpu++) {
345 int current_fd = *(group_leader_fds[group] + cpu);
346
347 if(unlikely(current_fd == NO_FD)) continue;
348
349 if(ioctl(current_fd, PERF_EVENT_IOC_DISABLE, PERF_IOC_FLAG_GROUP) == -1
350 || ioctl(current_fd, PERF_EVENT_IOC_ENABLE, PERF_IOC_FLAG_GROUP) == -1)
351 {
352 collector_error("Cannot reenable event group");
353 }
354 }
355 }
356 }
357
358 static int perf_collect() {
359 int cpu;
360 struct perf_event *current_event = NULL;
361 static uint64_t prev_cpu_cycles_value = 0;
362 struct {
363 uint64_t value;
364 uint64_t time_enabled;
365 uint64_t time_running;
366 } read_result;
367
368 for(current_event = &perf_events[0]; current_event->id != EV_ID_END; current_event++) {
369 current_event->updated = 0;
370 current_event->value = 0;
371
372 if(unlikely(current_event->disabled)) continue;
373
374 for(cpu = 0; cpu < number_of_cpus; cpu++) {
375
376 ssize_t read_size = read(current_event->fd[cpu], &read_result, sizeof(read_result));
377
378 if(likely(read_size == sizeof(read_result))) {
379 if (likely(read_result.time_running
380 && read_result.time_running != *(current_event->prev_time_running + cpu)
381 && (read_result.time_enabled / read_result.time_running < RUNNING_THRESHOLD))) {
382 current_event->value += (read_result.value - *(current_event->prev_value + cpu)) \
383 * (read_result.time_enabled - *(current_event->prev_time_enabled + cpu)) \
384 / (read_result.time_running - *(current_event->prev_time_running + cpu));
385 }
386
387 *(current_event->prev_value + cpu) = read_result.value;
388 *(current_event->prev_time_enabled + cpu) = read_result.time_enabled;
389 *(current_event->prev_time_running + cpu) = read_result.time_running;
390
391 current_event->updated = 1;
392 }
393 else {
394 collector_error("Cannot update value for event %u", current_event->id);
395 return 1;
396 }
397 }
398
399 if(unlikely(debug)) fprintf(stderr, "perf.plugin: successfully read event id = %u, value = %"PRIu64"\n", current_event->id, current_event->value);
400 }
401
402 if(unlikely(perf_events[EV_ID_CPU_CYCLES].value == prev_cpu_cycles_value))
403 reenable_events();
404 prev_cpu_cycles_value = perf_events[EV_ID_CPU_CYCLES].value;
405
406 return 0;
407 }
408
409 static void perf_send_metrics() {
410 static int // Hardware counters
411 cpu_cycles_chart_generated = 0,
412 instructions_chart_generated = 0,
413 ipc_chart_generated = 0,
414 branch_chart_generated = 0,
415 cache_chart_generated = 0,
416 bus_cycles_chart_generated = 0,
417 stalled_cycles_chart_generated = 0,
418
419 // Software counters
420 migrations_chart_generated = 0,
421 alignment_chart_generated = 0,
422 emulation_chart_generated = 0,
423
424 // Hardware cache counters
425 L1D_chart_generated = 0,
426 L1D_prefetch_chart_generated = 0,
427 L1I_chart_generated = 0,
428 LL_chart_generated = 0,
429 DTLB_chart_generated = 0,
430 ITLB_chart_generated = 0,
431 PBU_chart_generated = 0;
432
433 // ------------------------------------------------------------------------
434
435 if(likely(perf_events[EV_ID_CPU_CYCLES].updated || perf_events[EV_ID_REF_CPU_CYCLES].updated)) {
436 if(unlikely(!cpu_cycles_chart_generated)) {
437 cpu_cycles_chart_generated = 1;
438
439 printf("CHART %s.%s '' 'CPU cycles' 'cycles/s' %s '' line %d %d '' %s\n"
440 , RRD_TYPE_PERF
441 , "cpu_cycles"
442 , RRD_FAMILY_HW
443 , NETDATA_CHART_PRIO_PERF_CPU_CYCLES
444 , update_every
445 , PLUGIN_PERF_NAME
446 );
447 printf("DIMENSION %s '' absolute 1 1\n", "cpu");
448 printf("DIMENSION %s '' absolute 1 1\n", "ref_cpu");
449 }
450
451 printf(
452 "BEGIN %s.%s\n"
453 , RRD_TYPE_PERF
454 , "cpu_cycles"
455 );
456 if(likely(perf_events[EV_ID_CPU_CYCLES].updated)) {
457 printf(
458 "SET %s = %lld\n"
459 , "cpu"
460 , (collected_number) perf_events[EV_ID_CPU_CYCLES].value
461 );
462 }
463 if(likely(perf_events[EV_ID_REF_CPU_CYCLES].updated)) {
464 printf(
465 "SET %s = %lld\n"
466 , "ref_cpu"
467 , (collected_number) perf_events[EV_ID_REF_CPU_CYCLES].value
468 );
469 }
470 printf("END\n");
471 }
472
473 // ------------------------------------------------------------------------
474
475 if(likely(perf_events[EV_ID_INSTRUCTIONS].updated)) {
476 if(unlikely(!instructions_chart_generated)) {
477 instructions_chart_generated = 1;
478
479 printf("CHART %s.%s '' 'Instructions' 'instructions/s' %s '' line %d %d '' %s\n"
480 , RRD_TYPE_PERF
481 , "instructions"
482 , RRD_FAMILY_HW
483 , NETDATA_CHART_PRIO_PERF_INSTRUCTIONS
484 , update_every
485 , PLUGIN_PERF_NAME
486 );
487 printf("DIMENSION %s '' absolute 1 1\n", "instructions");
488 }
489
490 printf(
491 "BEGIN %s.%s\n"
492 , RRD_TYPE_PERF
493 , "instructions"
494 );
495 printf(
496 "SET %s = %lld\n"
497 , "instructions"
498 , (collected_number) perf_events[EV_ID_INSTRUCTIONS].value
499 );
500 printf("END\n");
501 }
502
503 // ------------------------------------------------------------------------
504
505 if(likely(perf_events[EV_ID_INSTRUCTIONS].updated) && likely(perf_events[EV_ID_CPU_CYCLES].updated)) {
506 if(unlikely(!ipc_chart_generated)) {
507 ipc_chart_generated = 1;
508
509 printf("CHART %s.%s '' '%s' 'instructions/cycle' %s '' line %d %d '' %s\n"
510 , RRD_TYPE_PERF
511 , "instructions_per_cycle"
512 , "Instructions per Cycle(IPC)"
513 , RRD_FAMILY_HW
514 , NETDATA_CHART_PRIO_PERF_IPC
515 , update_every
516 , PLUGIN_PERF_NAME
517 );
518 printf("DIMENSION %s '' absolute 1 100\n", "ipc");
519 }
520
521 printf("BEGIN %s.%s\n"
522 , RRD_TYPE_PERF
523 , "instructions_per_cycle"
524 );
525
526 NETDATA_DOUBLE result = ((NETDATA_DOUBLE)perf_events[EV_ID_INSTRUCTIONS].value /
527 (NETDATA_DOUBLE)perf_events[EV_ID_CPU_CYCLES].value) * 100.0;
528 printf("SET %s = %lld\n"
529 , "ipc"
530 , (collected_number) result
531 );
532 printf("END\n");
533 }
534
535 // ------------------------------------------------------------------------
536
537 if(likely(perf_events[EV_ID_BRANCH_INSTRUCTIONS].updated || perf_events[EV_ID_BRANCH_MISSES].updated)) {
538 if(unlikely(!branch_chart_generated)) {
539 branch_chart_generated = 1;
540
541 printf("CHART %s.%s '' 'Branch instructions' 'instructions/s' %s '' line %d %d '' %s\n"
542 , RRD_TYPE_PERF
543 , "branch_instructions"
544 , RRD_FAMILY_HW
545 , NETDATA_CHART_PRIO_PERF_BRANCH_INSTRUCTIONS
546 , update_every
547 , PLUGIN_PERF_NAME
548 );
549 printf("DIMENSION %s '' absolute 1 1\n", "instructions");
550 printf("DIMENSION %s '' absolute 1 1\n", "misses");
551 }
552
553 printf(
554 "BEGIN %s.%s\n"
555 , RRD_TYPE_PERF
556 , "branch_instructions"
557 );
558 if(likely(perf_events[EV_ID_BRANCH_INSTRUCTIONS].updated)) {
559 printf(
560 "SET %s = %lld\n"
561 , "instructions"
562 , (collected_number) perf_events[EV_ID_BRANCH_INSTRUCTIONS].value
563 );
564 }
565 if(likely(perf_events[EV_ID_BRANCH_MISSES].updated)) {
566 printf(
567 "SET %s = %lld\n"
568 , "misses"
569 , (collected_number) perf_events[EV_ID_BRANCH_MISSES].value
570 );
571 }
572 printf("END\n");
573 }
574
575 // ------------------------------------------------------------------------
576
577 if(likely(perf_events[EV_ID_CACHE_REFERENCES].updated || perf_events[EV_ID_CACHE_MISSES].updated)) {
578 if(unlikely(!cache_chart_generated)) {
579 cache_chart_generated = 1;
580
581 printf("CHART %s.%s '' 'Cache operations' 'operations/s' %s '' line %d %d '' %s\n"
582 , RRD_TYPE_PERF
583 , "cache"
584 , RRD_FAMILY_HW
585 , NETDATA_CHART_PRIO_PERF_CACHE
586 , update_every
587 , PLUGIN_PERF_NAME
588 );
589 printf("DIMENSION %s '' absolute 1 1\n", "references");
590 printf("DIMENSION %s '' absolute 1 1\n", "misses");
591 }
592
593 printf(
594 "BEGIN %s.%s\n"
595 , RRD_TYPE_PERF
596 , "cache"
597 );
598 if(likely(perf_events[EV_ID_CACHE_REFERENCES].updated)) {
599 printf(
600 "SET %s = %lld\n"
601 , "references"
602 , (collected_number) perf_events[EV_ID_CACHE_REFERENCES].value
603 );
604 }
605 if(likely(perf_events[EV_ID_CACHE_MISSES].updated)) {
606 printf(
607 "SET %s = %lld\n"
608 , "misses"
609 , (collected_number) perf_events[EV_ID_CACHE_MISSES].value
610 );
611 }
612 printf("END\n");
613 }
614
615 // ------------------------------------------------------------------------
616
617 if(likely(perf_events[EV_ID_BUS_CYCLES].updated)) {
618 if(unlikely(!bus_cycles_chart_generated)) {
619 bus_cycles_chart_generated = 1;
620
621 printf("CHART %s.%s '' 'Bus cycles' 'cycles/s' %s '' line %d %d '' %s\n"
622 , RRD_TYPE_PERF
623 , "bus_cycles"
624 , RRD_FAMILY_HW
625 , NETDATA_CHART_PRIO_PERF_BUS_CYCLES
626 , update_every
627 , PLUGIN_PERF_NAME
628 );
629 printf("DIMENSION %s '' absolute 1 1\n", "bus");
630 }
631
632 printf(
633 "BEGIN %s.%s\n"
634 , RRD_TYPE_PERF
635 , "bus_cycles"
636 );
637 printf(
638 "SET %s = %lld\n"
639 , "bus"
640 , (collected_number) perf_events[EV_ID_BUS_CYCLES].value
641 );
642 printf("END\n");
643 }
644
645 // ------------------------------------------------------------------------
646
647 if(likely(perf_events[EV_ID_STALLED_CYCLES_FRONTEND].updated || perf_events[EV_ID_STALLED_CYCLES_BACKEND].updated)) {
648 if(unlikely(!stalled_cycles_chart_generated)) {
649 stalled_cycles_chart_generated = 1;
650
651 printf("CHART %s.%s '' 'Stalled frontend and backend cycles' 'cycles/s' %s '' line %d %d '' %s\n"
652 , RRD_TYPE_PERF
653 , "stalled_cycles"
654 , RRD_FAMILY_HW
655 , NETDATA_CHART_PRIO_PERF_FRONT_BACK_CYCLES
656 , update_every
657 , PLUGIN_PERF_NAME
658 );
659 printf("DIMENSION %s '' absolute 1 1\n", "frontend");
660 printf("DIMENSION %s '' absolute 1 1\n", "backend");
661 }
662
663 printf(
664 "BEGIN %s.%s\n"
665 , RRD_TYPE_PERF
666 , "stalled_cycles"
667 );
668 if(likely(perf_events[EV_ID_STALLED_CYCLES_FRONTEND].updated)) {
669 printf(
670 "SET %s = %lld\n"
671 , "frontend"
672 , (collected_number) perf_events[EV_ID_STALLED_CYCLES_FRONTEND].value
673 );
674 }
675 if(likely(perf_events[EV_ID_STALLED_CYCLES_BACKEND].updated)) {
676 printf(
677 "SET %s = %lld\n"
678 , "backend"
679 , (collected_number) perf_events[EV_ID_STALLED_CYCLES_BACKEND].value
680 );
681 }
682 printf("END\n");
683 }
684
685 // ------------------------------------------------------------------------
686
687 if(likely(perf_events[EV_ID_CPU_MIGRATIONS].updated)) {
688 if(unlikely(!migrations_chart_generated)) {
689 migrations_chart_generated = 1;
690
691 printf("CHART %s.%s '' 'CPU migrations' 'migrations' %s '' line %d %d '' %s\n"
692 , RRD_TYPE_PERF
693 , "migrations"
694 , RRD_FAMILY_SW
695 , NETDATA_CHART_PRIO_PERF_MIGRATIONS
696 , update_every
697 , PLUGIN_PERF_NAME
698 );
699 printf("DIMENSION %s '' absolute 1 1\n", "migrations");
700 }
701
702 printf(
703 "BEGIN %s.%s\n"
704 , RRD_TYPE_PERF
705 , "migrations"
706 );
707 printf(
708 "SET %s = %lld\n"
709 , "migrations"
710 , (collected_number) perf_events[EV_ID_CPU_MIGRATIONS].value
711 );
712 printf("END\n");
713 }
714
715 // ------------------------------------------------------------------------
716
717 if(likely(perf_events[EV_ID_ALIGNMENT_FAULTS].updated)) {
718 if(unlikely(!alignment_chart_generated)) {
719 alignment_chart_generated = 1;
720
721 printf("CHART %s.%s '' 'Alignment faults' 'faults' %s '' line %d %d '' %s\n"
722 , RRD_TYPE_PERF
723 , "alignment_faults"
724 , RRD_FAMILY_SW
725 , NETDATA_CHART_PRIO_PERF_ALIGNMENT
726 , update_every
727 , PLUGIN_PERF_NAME
728 );
729 printf("DIMENSION %s '' absolute 1 1\n", "faults");
730 }
731
732 printf(
733 "BEGIN %s.%s\n"
734 , RRD_TYPE_PERF
735 , "alignment_faults"
736 );
737 printf(
738 "SET %s = %lld\n"
739 , "faults"
740 , (collected_number) perf_events[EV_ID_ALIGNMENT_FAULTS].value
741 );
742 printf("END\n");
743 }
744
745 // ------------------------------------------------------------------------
746
747 if(likely(perf_events[EV_ID_EMULATION_FAULTS].updated)) {
748 if(unlikely(!emulation_chart_generated)) {
749 emulation_chart_generated = 1;
750
751 printf("CHART %s.%s '' 'Emulation faults' 'faults' %s '' line %d %d '' %s\n"
752 , RRD_TYPE_PERF
753 , "emulation_faults"
754 , RRD_FAMILY_SW
755 , NETDATA_CHART_PRIO_PERF_EMULATION
756 , update_every
757 , PLUGIN_PERF_NAME
758 );
759 printf("DIMENSION %s '' absolute 1 1\n", "faults");
760 }
761
762 printf(
763 "BEGIN %s.%s\n"
764 , RRD_TYPE_PERF
765 , "emulation_faults"
766 );
767 printf(
768 "SET %s = %lld\n"
769 , "faults"
770 , (collected_number) perf_events[EV_ID_EMULATION_FAULTS].value
771 );
772 printf("END\n");
773 }
774
775 // ------------------------------------------------------------------------
776
777 if(likely(perf_events[EV_ID_L1D_READ_ACCESS].updated || perf_events[EV_ID_L1D_READ_MISS].updated
778 || perf_events[EV_ID_L1D_WRITE_ACCESS].updated || perf_events[EV_ID_L1D_WRITE_MISS].updated)) {
779 if(unlikely(!L1D_chart_generated)) {
780 L1D_chart_generated = 1;
781
782 printf("CHART %s.%s '' 'L1D cache operations' 'events/s' %s '' line %d %d '' %s\n"
783 , RRD_TYPE_PERF
784 , "l1d_cache"
785 , RRD_FAMILY_CACHE
786 , NETDATA_CHART_PRIO_PERF_L1D
787 , update_every
788 , PLUGIN_PERF_NAME
789 );
790 printf("DIMENSION %s '' absolute 1 1\n", "read_access");
791 printf("DIMENSION %s '' absolute 1 1\n", "read_misses");
792 printf("DIMENSION %s '' absolute -1 1\n", "write_access");
793 printf("DIMENSION %s '' absolute -1 1\n", "write_misses");
794 }
795
796 printf(
797 "BEGIN %s.%s\n"
798 , RRD_TYPE_PERF
799 , "l1d_cache"
800 );
801 if(likely(perf_events[EV_ID_L1D_READ_ACCESS].updated)) {
802 printf(
803 "SET %s = %lld\n"
804 , "read_access"
805 , (collected_number) perf_events[EV_ID_L1D_READ_ACCESS].value
806 );
807 }
808 if(likely(perf_events[EV_ID_L1D_READ_MISS].updated)) {
809 printf(
810 "SET %s = %lld\n"
811 , "read_misses"
812 , (collected_number) perf_events[EV_ID_L1D_READ_MISS].value
813 );
814 }
815 if(likely(perf_events[EV_ID_L1D_WRITE_ACCESS].updated)) {
816 printf(
817 "SET %s = %lld\n"
818 , "write_access"
819 , (collected_number) perf_events[EV_ID_L1D_WRITE_ACCESS].value
820 );
821 }
822 if(likely(perf_events[EV_ID_L1D_WRITE_MISS].updated)) {
823 printf(
824 "SET %s = %lld\n"
825 , "write_misses"
826 , (collected_number) perf_events[EV_ID_L1D_WRITE_MISS].value
827 );
828 }
829 printf("END\n");
830 }
831
832 // ------------------------------------------------------------------------
833
834 if(likely(perf_events[EV_ID_L1D_PREFETCH_ACCESS].updated)) {
835 if(unlikely(!L1D_prefetch_chart_generated)) {
836 L1D_prefetch_chart_generated = 1;
837
838 printf("CHART %s.%s '' 'L1D prefetch cache operations' 'prefetches/s' %s '' line %d %d '' %s\n"
839 , RRD_TYPE_PERF
840 , "l1d_cache_prefetch"
841 , RRD_FAMILY_CACHE
842 , NETDATA_CHART_PRIO_PERF_L1D_PREFETCH
843 , update_every
844 , PLUGIN_PERF_NAME
845 );
846 printf("DIMENSION %s '' absolute 1 1\n", "prefetches");
847 }
848
849 printf(
850 "BEGIN %s.%s\n"
851 , RRD_TYPE_PERF
852 , "l1d_cache_prefetch"
853 );
854 printf(
855 "SET %s = %lld\n"
856 , "prefetches"
857 , (collected_number) perf_events[EV_ID_L1D_PREFETCH_ACCESS].value
858 );
859 printf("END\n");
860 }
861
862 // ------------------------------------------------------------------------
863
864 if(likely(perf_events[EV_ID_L1I_READ_ACCESS].updated || perf_events[EV_ID_L1I_READ_MISS].updated)) {
865 if(unlikely(!L1I_chart_generated)) {
866 L1I_chart_generated = 1;
867
868 printf("CHART %s.%s '' 'L1I cache operations' 'events/s' %s '' line %d %d '' %s\n"
869 , RRD_TYPE_PERF
870 , "l1i_cache"
871 , RRD_FAMILY_CACHE
872 , NETDATA_CHART_PRIO_PERF_L1I
873 , update_every
874 , PLUGIN_PERF_NAME
875 );
876 printf("DIMENSION %s '' absolute 1 1\n", "read_access");
877 printf("DIMENSION %s '' absolute 1 1\n", "read_misses");
878 }
879
880 printf(
881 "BEGIN %s.%s\n"
882 , RRD_TYPE_PERF
883 , "l1i_cache"
884 );
885 if(likely(perf_events[EV_ID_L1I_READ_ACCESS].updated)) {
886 printf(
887 "SET %s = %lld\n"
888 , "read_access"
889 , (collected_number) perf_events[EV_ID_L1I_READ_ACCESS].value
890 );
891 }
892 if(likely(perf_events[EV_ID_L1I_READ_MISS].updated)) {
893 printf(
894 "SET %s = %lld\n"
895 , "read_misses"
896 , (collected_number) perf_events[EV_ID_L1I_READ_MISS].value
897 );
898 }
899 printf("END\n");
900 }
901
902 // ------------------------------------------------------------------------
903
904 if(likely(perf_events[EV_ID_LL_READ_ACCESS].updated || perf_events[EV_ID_LL_READ_MISS].updated
905 || perf_events[EV_ID_LL_WRITE_ACCESS].updated || perf_events[EV_ID_LL_WRITE_MISS].updated)) {
906 if(unlikely(!LL_chart_generated)) {
907 LL_chart_generated = 1;
908
909 printf("CHART %s.%s '' 'LL cache operations' 'events/s' %s '' line %d %d '' %s\n"
910 , RRD_TYPE_PERF
911 , "ll_cache"
912 , RRD_FAMILY_CACHE
913 , NETDATA_CHART_PRIO_PERF_LL
914 , update_every
915 , PLUGIN_PERF_NAME
916 );
917 printf("DIMENSION %s '' absolute 1 1\n", "read_access");
918 printf("DIMENSION %s '' absolute 1 1\n", "read_misses");
919 printf("DIMENSION %s '' absolute -1 1\n", "write_access");
920 printf("DIMENSION %s '' absolute -1 1\n", "write_misses");
921 }
922
923 printf(
924 "BEGIN %s.%s\n"
925 , RRD_TYPE_PERF
926 , "ll_cache"
927 );
928 if(likely(perf_events[EV_ID_LL_READ_ACCESS].updated)) {
929 printf(
930 "SET %s = %lld\n"
931 , "read_access"
932 , (collected_number) perf_events[EV_ID_LL_READ_ACCESS].value
933 );
934 }
935 if(likely(perf_events[EV_ID_LL_READ_MISS].updated)) {
936 printf(
937 "SET %s = %lld\n"
938 , "read_misses"
939 , (collected_number) perf_events[EV_ID_LL_READ_MISS].value
940 );
941 }
942 if(likely(perf_events[EV_ID_LL_WRITE_ACCESS].updated)) {
943 printf(
944 "SET %s = %lld\n"
945 , "write_access"
946 , (collected_number) perf_events[EV_ID_LL_WRITE_ACCESS].value
947 );
948 }
949 if(likely(perf_events[EV_ID_LL_WRITE_MISS].updated)) {
950 printf(
951 "SET %s = %lld\n"
952 , "write_misses"
953 , (collected_number) perf_events[EV_ID_LL_WRITE_MISS].value
954 );
955 }
956 printf("END\n");
957 }
958
959 // ------------------------------------------------------------------------
960
961 if(likely(perf_events[EV_ID_DTLB_READ_ACCESS].updated || perf_events[EV_ID_DTLB_READ_MISS].updated
962 || perf_events[EV_ID_DTLB_WRITE_ACCESS].updated || perf_events[EV_ID_DTLB_WRITE_MISS].updated)) {
963 if(unlikely(!DTLB_chart_generated)) {
964 DTLB_chart_generated = 1;
965
966 printf("CHART %s.%s '' 'DTLB cache operations' 'events/s' %s '' line %d %d '' %s\n"
967 , RRD_TYPE_PERF
968 , "dtlb_cache"
969 , RRD_FAMILY_CACHE
970 , NETDATA_CHART_PRIO_PERF_DTLB
971 , update_every
972 , PLUGIN_PERF_NAME
973 );
974 printf("DIMENSION %s '' absolute 1 1\n", "read_access");
975 printf("DIMENSION %s '' absolute 1 1\n", "read_misses");
976 printf("DIMENSION %s '' absolute -1 1\n", "write_access");
977 printf("DIMENSION %s '' absolute -1 1\n", "write_misses");
978 }
979
980 printf(
981 "BEGIN %s.%s\n"
982 , RRD_TYPE_PERF
983 , "dtlb_cache"
984 );
985 if(likely(perf_events[EV_ID_DTLB_READ_ACCESS].updated)) {
986 printf(
987 "SET %s = %lld\n"
988 , "read_access"
989 , (collected_number) perf_events[EV_ID_DTLB_READ_ACCESS].value
990 );
991 }
992 if(likely(perf_events[EV_ID_DTLB_READ_MISS].updated)) {
993 printf(
994 "SET %s = %lld\n"
995 , "read_misses"
996 , (collected_number) perf_events[EV_ID_DTLB_READ_MISS].value
997 );
998 }
999 if(likely(perf_events[EV_ID_DTLB_WRITE_ACCESS].updated)) {
1000 printf(
1001 "SET %s = %lld\n"
1002 , "write_access"
1003 , (collected_number) perf_events[EV_ID_DTLB_WRITE_ACCESS].value
1004 );
1005 }
1006 if(likely(perf_events[EV_ID_DTLB_WRITE_MISS].updated)) {
1007 printf(
1008 "SET %s = %lld\n"
1009 , "write_misses"
1010 , (collected_number) perf_events[EV_ID_DTLB_WRITE_MISS].value
1011 );
1012 }
1013 printf("END\n");
1014 }
1015
1016 // ------------------------------------------------------------------------
1017
1018 if(likely(perf_events[EV_ID_ITLB_READ_ACCESS].updated || perf_events[EV_ID_ITLB_READ_MISS].updated)) {
1019 if(unlikely(!ITLB_chart_generated)) {
1020 ITLB_chart_generated = 1;
1021
1022 printf("CHART %s.%s '' 'ITLB cache operations' 'events/s' %s '' line %d %d '' %s\n"
1023 , RRD_TYPE_PERF
1024 , "itlb_cache"
1025 , RRD_FAMILY_CACHE
1026 , NETDATA_CHART_PRIO_PERF_ITLB
1027 , update_every
1028 , PLUGIN_PERF_NAME
1029 );
1030 printf("DIMENSION %s '' absolute 1 1\n", "read_access");
1031 printf("DIMENSION %s '' absolute 1 1\n", "read_misses");
1032 }
1033
1034 printf(
1035 "BEGIN %s.%s\n"
1036 , RRD_TYPE_PERF
1037 , "itlb_cache"
1038 );
1039 if(likely(perf_events[EV_ID_ITLB_READ_ACCESS].updated)) {
1040 printf(
1041 "SET %s = %lld\n"
1042 , "read_access"
1043 , (collected_number) perf_events[EV_ID_ITLB_READ_ACCESS].value
1044 );
1045 }
1046 if(likely(perf_events[EV_ID_ITLB_READ_MISS].updated)) {
1047 printf(
1048 "SET %s = %lld\n"
1049 , "read_misses"
1050 , (collected_number) perf_events[EV_ID_ITLB_READ_MISS].value
1051 );
1052 }
1053 printf("END\n");
1054 }
1055
1056 // ------------------------------------------------------------------------
1057
1058 if(likely(perf_events[EV_ID_PBU_READ_ACCESS].updated)) {
1059 if(unlikely(!PBU_chart_generated)) {
1060 PBU_chart_generated = 1;
1061
1062 printf("CHART %s.%s '' 'PBU cache operations' 'events/s' %s '' line %d %d '' %s\n"
1063 , RRD_TYPE_PERF
1064 , "pbu_cache"
1065 , RRD_FAMILY_CACHE
1066 , NETDATA_CHART_PRIO_PERF_PBU
1067 , update_every
1068 , PLUGIN_PERF_NAME
1069 );
1070 printf("DIMENSION %s '' absolute 1 1\n", "read_access");
1071 }
1072
1073 printf(
1074 "BEGIN %s.%s\n"
1075 , RRD_TYPE_PERF
1076 , "pbu_cache"
1077 );
1078 printf(
1079 "SET %s = %lld\n"
1080 , "read_access"
1081 , (collected_number) perf_events[EV_ID_PBU_READ_ACCESS].value
1082 );
1083 printf("END\n");
1084 }
1085 }
1086
1087 void parse_command_line(int argc, char **argv) {
1088 int i, plugin_enabled = 0;
1089
1090 for(i = 1; i < argc ; i++) {
1091 if(isdigit(*argv[i]) && !freq) {
1092 int n = str2i(argv[i]);
1093 if(n > 0 && n < 86400) {
1094 freq = n;
1095 continue;
1096 }
1097 }
1098 else if(strcmp("version", argv[i]) == 0 || strcmp("-version", argv[i]) == 0 || strcmp("--version", argv[i]) == 0 || strcmp("-v", argv[i]) == 0 || strcmp("-V", argv[i]) == 0) {
1099 printf("perf.plugin %s\n", NETDATA_VERSION);
1100 exit(0);
1101 }
1102 else if(strcmp("all", argv[i]) == 0) {
1103 struct perf_event *current_event = NULL;
1104
1105 for(current_event = &perf_events[0]; current_event->id != EV_ID_END; current_event++)
1106 current_event->disabled = 0;
1107
1108 plugin_enabled = 1;
1109 continue;
1110 }
1111 else if(strcmp("cycles", argv[i]) == 0) {
1112 perf_events[EV_ID_CPU_CYCLES].disabled = 0;
1113 perf_events[EV_ID_REF_CPU_CYCLES].disabled = 0;
1114 plugin_enabled = 1;
1115 continue;
1116 }
1117 else if(strcmp("instructions", argv[i]) == 0) {
1118 perf_events[EV_ID_INSTRUCTIONS].disabled = 0;
1119 plugin_enabled = 1;
1120 continue;
1121 }
1122 else if(strcmp("branch", argv[i]) == 0) {
1123 perf_events[EV_ID_BRANCH_INSTRUCTIONS].disabled = 0;
1124 perf_events[EV_ID_BRANCH_MISSES].disabled = 0;
1125 plugin_enabled = 1;
1126 continue;
1127 }
1128 else if(strcmp("cache", argv[i]) == 0) {
1129 perf_events[EV_ID_CACHE_REFERENCES].disabled = 0;
1130 perf_events[EV_ID_CACHE_MISSES].disabled = 0;
1131 plugin_enabled = 1;
1132 continue;
1133 }
1134 else if(strcmp("bus", argv[i]) == 0) {
1135 perf_events[EV_ID_BUS_CYCLES].disabled = 0;
1136 plugin_enabled = 1;
1137 continue;
1138 }
1139 else if(strcmp("stalled", argv[i]) == 0) {
1140 perf_events[EV_ID_STALLED_CYCLES_FRONTEND].disabled = 0;
1141 perf_events[EV_ID_STALLED_CYCLES_BACKEND].disabled = 0;
1142 plugin_enabled = 1;
1143 continue;
1144 }
1145 else if(strcmp("migrations", argv[i]) == 0) {
1146 perf_events[EV_ID_CPU_MIGRATIONS].disabled = 0;
1147 plugin_enabled = 1;
1148 continue;
1149 }
1150 else if(strcmp("alignment", argv[i]) == 0) {
1151 perf_events[EV_ID_ALIGNMENT_FAULTS].disabled = 0;
1152 plugin_enabled = 1;
1153 continue;
1154 }
1155 else if(strcmp("emulation", argv[i]) == 0) {
1156 perf_events[EV_ID_EMULATION_FAULTS].disabled = 0;
1157 plugin_enabled = 1;
1158 continue;
1159 }
1160 else if(strcmp("L1D", argv[i]) == 0) {
1161 perf_events[EV_ID_L1D_READ_ACCESS].disabled = 0;
1162 perf_events[EV_ID_L1D_READ_MISS].disabled = 0;
1163 perf_events[EV_ID_L1D_WRITE_ACCESS].disabled = 0;
1164 perf_events[EV_ID_L1D_WRITE_MISS].disabled = 0;
1165 plugin_enabled = 1;
1166 continue;
1167 }
1168 else if(strcmp("L1D-prefetch", argv[i]) == 0) {
1169 perf_events[EV_ID_L1D_PREFETCH_ACCESS].disabled = 0;
1170 plugin_enabled = 1;
1171 continue;
1172 }
1173 else if(strcmp("L1I", argv[i]) == 0) {
1174 perf_events[EV_ID_L1I_READ_ACCESS].disabled = 0;
1175 perf_events[EV_ID_L1I_READ_MISS].disabled = 0;
1176 plugin_enabled = 1;
1177 continue;
1178 }
1179 else if(strcmp("LL", argv[i]) == 0) {
1180 perf_events[EV_ID_LL_READ_ACCESS].disabled = 0;
1181 perf_events[EV_ID_LL_READ_MISS].disabled = 0;
1182 perf_events[EV_ID_LL_WRITE_ACCESS].disabled = 0;
1183 perf_events[EV_ID_LL_WRITE_MISS].disabled = 0;
1184 plugin_enabled = 1;
1185 continue;
1186 }
1187 else if(strcmp("DTLB", argv[i]) == 0) {
1188 perf_events[EV_ID_DTLB_READ_ACCESS].disabled = 0;
1189 perf_events[EV_ID_DTLB_READ_MISS].disabled = 0;
1190 perf_events[EV_ID_DTLB_WRITE_ACCESS].disabled = 0;
1191 perf_events[EV_ID_DTLB_WRITE_MISS].disabled = 0;
1192 plugin_enabled = 1;
1193 continue;
1194 }
1195 else if(strcmp("ITLB", argv[i]) == 0) {
1196 perf_events[EV_ID_ITLB_READ_ACCESS].disabled = 0;
1197 perf_events[EV_ID_ITLB_READ_MISS].disabled = 0;
1198 plugin_enabled = 1;
1199 continue;
1200 }
1201 else if(strcmp("PBU", argv[i]) == 0) {
1202 perf_events[EV_ID_PBU_READ_ACCESS].disabled = 0;
1203 plugin_enabled = 1;
1204 continue;
1205 }
1206 else if(strcmp("debug", argv[i]) == 0) {
1207 debug = 1;
1208 continue;
1209 }
1210 else if(strcmp("-h", argv[i]) == 0 || strcmp("--help", argv[i]) == 0) {
1211 fprintf(stderr,
1212 "\n"
1213 " netdata perf.plugin %s\n"
1214 " Copyright 2018-2025 Netdata Inc.\n"
1215 " Released under GNU General Public License v3 or later.\n"
1216 "\n"
1217 " This program is a data collector plugin for netdata.\n"
1218 "\n"
1219 " Available command line options:\n"
1220 "\n"
1221 " COLLECTION_FREQUENCY data collection frequency in seconds\n"
1222 " minimum: %d\n"
1223 "\n"
1224 " all enable all charts\n"
1225 "\n"
1226 " cycles enable CPU cycles chart\n"
1227 "\n"
1228 " instructions enable Instructions chart\n"
1229 "\n"
1230 " branch enable Branch instructions chart\n"
1231 "\n"
1232 " cache enable Cache operations chart\n"
1233 "\n"
1234 " bus enable Bus cycles chart\n"
1235 "\n"
1236 " stalled enable Stalled frontend and backend cycles chart\n"
1237 "\n"
1238 " migrations enable CPU migrations chart\n"
1239 "\n"
1240 " alignment enable Alignment faults chart\n"
1241 "\n"
1242 " emulation enable Emulation faults chart\n"
1243 "\n"
1244 " L1D enable L1D cache operations chart\n"
1245 "\n"
1246 " L1D-prefetch enable L1D prefetch cache operations chart\n"
1247 "\n"
1248 " L1I enable L1I cache operations chart\n"
1249 "\n"
1250 " LL enable LL cache operations chart\n"
1251 "\n"
1252 " DTLB enable DTLB cache operations chart\n"
1253 "\n"
1254 " ITLB enable ITLB cache operations chart\n"
1255 "\n"
1256 " PBU enable PBU cache operations chart\n"
1257 "\n"
1258 " debug enable verbose output\n"
1259 " default: disabled\n"
1260 "\n"
1261 " -v\n"
1262 " -V\n"
1263 " --version print version and exit\n"
1264 "\n"
1265 " -h\n"
1266 " --help print this message and exit\n"
1267 "\n"
1268 " For more information:\n"
1269 " https://github.com/netdata/netdata/tree/master/src/collectors/perf.plugin\n"
1270 "\n"
1271 , NETDATA_VERSION
1272 , update_every
1273 );
1274 exit(1);
1275 }
1276
1277 collector_error("ignoring parameter '%s'", argv[i]);
1278 }
1279
1280 if(!plugin_enabled){
1281 collector_info("no charts enabled - nothing to do.");
1282 printf("DISABLE\n");
1283 exit(1);
1284 }
1285 }
1286
1287 int main(int argc, char **argv) {
1288 nd_log_initialize_for_external_plugins("perf.plugin");
1289 netdata_threads_init_for_external_plugins(0);
1290
1291 parse_command_line(argc, argv);
1292
1293 errno_clear();
1294
1295 if(freq >= update_every)
1296 update_every = freq;
1297 else if(freq)
1298 collector_error("update frequency %d seconds is too small for PERF. Using %d.", freq, update_every);
1299
1300 if (unlikely(debug))
1301 fprintf(stderr, "perf.plugin: calling perf_init()\n");
1302
1303 if (!perf_init()) {
1304 perf_free();
1305 collector_info("all perf counters are disabled");
1306 fprintf(stdout, "EXIT\n");
1307 fflush(stdout);
1308 exit(1);
1309 }
1310
1311 // ------------------------------------------------------------------------
1312 // the main loop
1313
1314 if(unlikely(debug)) fprintf(stderr, "perf.plugin: starting data collection\n");
1315
1316 time_t started_t = now_monotonic_sec();
1317
1318 size_t iteration;
1319
1320 int perf = 1;
1321
1322 heartbeat_t hb;
1323 heartbeat_init(&hb, update_every * USEC_PER_SEC);
1324 for(iteration = 0; 1; iteration++) {
1325 usec_t dt = heartbeat_next(&hb);
1326
1327 if (unlikely(exit_initiated_get()))
1328 break;
1329
1330 if (unlikely(debug && iteration))
1331 fprintf(stderr, "perf.plugin: iteration %zu, dt %" PRIu64 " usec\n", iteration, dt);
1332
1333 if(likely(perf)) {
1334 if (unlikely(debug))
1335 fprintf(stderr, "perf.plugin: calling perf_collect()\n");
1336
1337 perf = !perf_collect();
1338
1339 if(likely(perf)) {
1340 if (unlikely(debug))
1341 fprintf(stderr, "perf.plugin: calling perf_send_metrics()\n");
1342
1343 perf_send_metrics();
1344 }
1345 }
1346
1347 fflush(stdout);
1348
1349 // restart check (14400 seconds)
1350 if (now_monotonic_sec() - started_t > 14400)
1351 break;
1352 }
1353
1354 collector_info("process exiting");
1355 perf_free();
1356 }