master
c 425 lines 16.4 KB
Raw
1 // SPDX-License-Identifier: GPL-3.0-or-later
2
3 #include "perflib-rrd.h"
4
5 #define COLLECTED_NUMBER_PRECISION 10000
6
7 RRDDIM *perflib_rrddim_add(
8 RRDSET *st,
9 const char *id,
10 const char *name,
11 collected_number multiplier,
12 collected_number divider,
13 COUNTER_DATA *cd)
14 {
15 RRD_ALGORITHM algorithm = RRD_ALGORITHM_ABSOLUTE;
16
17 switch (cd->current.CounterType) {
18 case PERF_COUNTER_COUNTER:
19 case PERF_SAMPLE_COUNTER:
20 case PERF_COUNTER_BULK_COUNT:
21 // (N1 - N0) / ((D1 - D0) / F)
22 // multiplier *= cd->current.Frequency / 10000000;
23 // tested, the frequency is not that useful for netdata
24 // we get right results without it.
25 algorithm = RRD_ALGORITHM_INCREMENTAL;
26 break;
27
28 case PERF_COUNTER_QUEUELEN_TYPE:
29 case PERF_COUNTER_100NS_QUEUELEN_TYPE:
30 case PERF_COUNTER_OBJ_TIME_QUEUELEN_TYPE:
31 case PERF_COUNTER_LARGE_QUEUELEN_TYPE:
32 case PERF_AVERAGE_BULK: // normally not displayed
33 // (N1 - N0) / (D1 - D0)
34 algorithm = RRD_ALGORITHM_INCREMENTAL;
35 break;
36
37 case PERF_OBJ_TIME_TIMER:
38 case PERF_COUNTER_TIMER:
39 case PERF_100NSEC_TIMER:
40 case PERF_PRECISION_SYSTEM_TIMER:
41 case PERF_PRECISION_100NS_TIMER:
42 case PERF_PRECISION_OBJECT_TIMER:
43 case PERF_SAMPLE_FRACTION:
44 // 100 * (N1 - N0) / (D1 - D0)
45 multiplier *= 100;
46 algorithm = RRD_ALGORITHM_INCREMENTAL;
47 break;
48
49 case PERF_COUNTER_TIMER_INV:
50 case PERF_100NSEC_TIMER_INV:
51 // 100 * (1 - ((N1 - N0) / (D1 - D0)))
52 divider *= COLLECTED_NUMBER_PRECISION;
53 algorithm = RRD_ALGORITHM_ABSOLUTE;
54 break;
55
56 case PERF_COUNTER_MULTI_TIMER:
57 // 100 * ((N1 - N0) / ((D1 - D0) / TB)) / B1
58 divider *= COLLECTED_NUMBER_PRECISION;
59 algorithm = RRD_ALGORITHM_ABSOLUTE;
60 break;
61
62 case PERF_100NSEC_MULTI_TIMER:
63 // 100 * ((N1 - N0) / (D1 - D0)) / B1
64 divider *= COLLECTED_NUMBER_PRECISION;
65 algorithm = RRD_ALGORITHM_ABSOLUTE;
66 break;
67
68 case PERF_COUNTER_MULTI_TIMER_INV:
69 case PERF_100NSEC_MULTI_TIMER_INV:
70 // 100 * (B1 - ((N1 - N0) / (D1 - D0)))
71 divider *= COLLECTED_NUMBER_PRECISION;
72 algorithm = RRD_ALGORITHM_ABSOLUTE;
73 break;
74
75 case PERF_COUNTER_RAWCOUNT:
76 case PERF_COUNTER_LARGE_RAWCOUNT:
77 // N as decimal
78 algorithm = RRD_ALGORITHM_ABSOLUTE;
79 break;
80
81 case PERF_COUNTER_RAWCOUNT_HEX:
82 case PERF_COUNTER_LARGE_RAWCOUNT_HEX:
83 // N as hexadecimal
84 algorithm = RRD_ALGORITHM_ABSOLUTE;
85 break;
86
87 case PERF_COUNTER_DELTA:
88 case PERF_COUNTER_LARGE_DELTA:
89 // N1 - N0
90 algorithm = RRD_ALGORITHM_ABSOLUTE;
91 break;
92
93 case PERF_RAW_FRACTION:
94 case PERF_LARGE_RAW_FRACTION:
95 // 100 * N / B
96 algorithm = RRD_ALGORITHM_ABSOLUTE;
97 divider *= COLLECTED_NUMBER_PRECISION;
98 break;
99
100 case PERF_AVERAGE_TIMER:
101 // ((N1 - N0) / TB) / (B1 - B0)
102 // divider *= cd->current.Frequency / 10000000;
103 algorithm = RRD_ALGORITHM_INCREMENTAL;
104 break;
105
106 case PERF_ELAPSED_TIME:
107 // (D0 - N0) / F
108 algorithm = RRD_ALGORITHM_ABSOLUTE;
109 break;
110
111 case PERF_COUNTER_TEXT:
112 case PERF_SAMPLE_BASE:
113 case PERF_AVERAGE_BASE:
114 case PERF_COUNTER_MULTI_BASE:
115 case PERF_RAW_BASE:
116 case PERF_COUNTER_NODATA:
117 case PERF_PRECISION_TIMESTAMP:
118 default:
119 break;
120 }
121
122 return rrddim_add(st, id, name, multiplier, divider, algorithm);
123 }
124
125 #define VALID_DELTA(cd) \
126 ((cd)->previous.Time > 0 && (cd)->current.Data >= (cd)->previous.Data && (cd)->current.Time > (cd)->previous.Time)
127
128 collected_number perflib_rrddim_set_by_pointer(RRDSET *st, RRDDIM *rd, COUNTER_DATA *cd)
129 {
130 ULONGLONG numerator = 0;
131 LONGLONG denominator = 0;
132 double doubleValue = 0.0;
133 collected_number value;
134
135 switch (cd->current.CounterType) {
136 case PERF_COUNTER_COUNTER:
137 case PERF_SAMPLE_COUNTER:
138 case PERF_COUNTER_BULK_COUNT:
139 // (N1 - N0) / ((D1 - D0) / F)
140 value = (collected_number)cd->current.Data;
141 break;
142
143 case PERF_COUNTER_QUEUELEN_TYPE:
144 case PERF_COUNTER_100NS_QUEUELEN_TYPE:
145 case PERF_COUNTER_OBJ_TIME_QUEUELEN_TYPE:
146 case PERF_COUNTER_LARGE_QUEUELEN_TYPE:
147 case PERF_AVERAGE_BULK: // normally not displayed
148 // (N1 - N0) / (D1 - D0)
149 value = (collected_number)cd->current.Data;
150 break;
151
152 case PERF_OBJ_TIME_TIMER:
153 case PERF_COUNTER_TIMER:
154 case PERF_100NSEC_TIMER:
155 case PERF_PRECISION_SYSTEM_TIMER:
156 case PERF_PRECISION_100NS_TIMER:
157 case PERF_PRECISION_OBJECT_TIMER:
158 case PERF_SAMPLE_FRACTION:
159 // 100 * (N1 - N0) / (D1 - D0)
160 value = (collected_number)cd->current.Data;
161 break;
162
163 case PERF_COUNTER_TIMER_INV:
164 case PERF_100NSEC_TIMER_INV:
165 // 100 * (1 - ((N1 - N0) / (D1 - D0)))
166 if (!VALID_DELTA(cd))
167 return 0;
168 numerator = cd->current.Data - cd->previous.Data;
169 denominator = cd->current.Time - cd->previous.Time;
170 doubleValue = 100.0 * (1.0 - ((double)numerator / (double)denominator));
171 // printf("Display value is (timer-inv): %f%%\n", doubleValue);
172 value = (collected_number)(doubleValue * COLLECTED_NUMBER_PRECISION);
173 break;
174
175 case PERF_COUNTER_MULTI_TIMER:
176 // 100 * ((N1 - N0) / ((D1 - D0) / TB)) / B1
177 if (!VALID_DELTA(cd) || !cd->current.Frequency || !cd->current.MultiCounterData)
178 return 0;
179 numerator = cd->current.Data - cd->previous.Data;
180 denominator = cd->current.Time - cd->previous.Time;
181 doubleValue = 100.0 * ((double)numerator / ((double)denominator / (double)cd->current.Frequency)) /
182 (double)cd->current.MultiCounterData;
183 // printf("Display value is (multi-timer): %f%%\n", doubleValue);
184 value = (collected_number)(doubleValue * COLLECTED_NUMBER_PRECISION);
185 break;
186
187 case PERF_100NSEC_MULTI_TIMER:
188 // 100 * ((N1 - N0) / (D1 - D0)) / B1
189 if (!VALID_DELTA(cd) || !cd->current.MultiCounterData)
190 return 0;
191 numerator = cd->current.Data - cd->previous.Data;
192 denominator = cd->current.Time - cd->previous.Time;
193 doubleValue = 100.0 * ((double)numerator / (double)denominator) / (double)cd->current.MultiCounterData;
194 // printf("Display value is (100ns multi-timer): %f%%\n", doubleValue);
195 value = (collected_number)(doubleValue * COLLECTED_NUMBER_PRECISION);
196 break;
197
198 case PERF_COUNTER_MULTI_TIMER_INV:
199 case PERF_100NSEC_MULTI_TIMER_INV:
200 // 100 * (B1 - ((N1 - N0) / (D1 - D0)))
201 if (!VALID_DELTA(cd) || !cd->current.MultiCounterData)
202 return 0;
203 numerator = cd->current.Data - cd->previous.Data;
204 denominator = cd->current.Time - cd->previous.Time;
205 doubleValue = 100.0 * ((double)cd->current.MultiCounterData - ((double)numerator / (double)denominator));
206 // printf("Display value is (multi-timer-inv): %f%%\n", doubleValue);
207 value = (collected_number)(doubleValue * COLLECTED_NUMBER_PRECISION);
208 break;
209
210 case PERF_COUNTER_RAWCOUNT:
211 case PERF_COUNTER_LARGE_RAWCOUNT:
212 // N as decimal
213 value = (collected_number)cd->current.Data;
214 break;
215
216 case PERF_COUNTER_RAWCOUNT_HEX:
217 case PERF_COUNTER_LARGE_RAWCOUNT_HEX:
218 // N as hexadecimal
219 value = (collected_number)cd->current.Data;
220 break;
221
222 case PERF_COUNTER_DELTA:
223 case PERF_COUNTER_LARGE_DELTA:
224 if (!VALID_DELTA(cd))
225 return 0;
226 value = (collected_number)(cd->current.Data - cd->previous.Data);
227 break;
228
229 case PERF_RAW_FRACTION:
230 case PERF_LARGE_RAW_FRACTION:
231 // 100 * N / B
232 if (!cd->current.Time)
233 return 0;
234 doubleValue = 100.0 * (double)cd->current.Data / (double)cd->current.Time;
235 // printf("Display value is (fraction): %f%%\n", doubleValue);
236 value = (collected_number)(doubleValue * COLLECTED_NUMBER_PRECISION);
237 break;
238
239 default:
240 return 0;
241 }
242
243 return rrddim_set_by_pointer(st, rd, value);
244 }
245
246 /*
247 double perflibCalculateValue(RAW_DATA *current, RAW_DATA *previous) {
248 ULONGLONG numerator = 0;
249 LONGLONG denominator = 0;
250 double doubleValue = 0.0;
251 DWORD dwordValue = 0;
252
253 if (NULL == previous) {
254 // Return error if the counter type requires two samples to calculate the value.
255 switch (current->CounterType) {
256 default:
257 if (PERF_DELTA_COUNTER != (current->CounterType & PERF_DELTA_COUNTER))
258 break;
259 __fallthrough;
260 // fallthrough
261
262 case PERF_AVERAGE_TIMER: // Special case.
263 case PERF_AVERAGE_BULK: // Special case.
264 // printf(" > The counter type requires two samples but only one sample was provided.\n");
265 return NAN;
266 }
267 }
268 else {
269 if (current->CounterType != previous->CounterType) {
270 // printf(" > The samples have inconsistent counter types.\n");
271 return NAN;
272 }
273
274 // Check for integer overflow or bad data from provider (the data from
275 // sample 2 must be greater than the data from sample 1).
276 if (current->Data < previous->Data)
277 {
278 // Can happen for various reasons. Commonly occurs with the Process counterset when
279 // multiple processes have the same name and one of them starts or stops.
280 // Normally you'll just drop the older sample and continue.
281 // printf("> current (%llu) is smaller than previous (%llu).\n", current->Data, previous->Data);
282 return NAN;
283 }
284 }
285
286 switch (current->CounterType) {
287 case PERF_COUNTER_COUNTER:
288 case PERF_SAMPLE_COUNTER:
289 case PERF_COUNTER_BULK_COUNT:
290 // (N1 - N0) / ((D1 - D0) / F)
291 numerator = current->Data - previous->Data;
292 denominator = current->Time - previous->Time;
293 dwordValue = (DWORD)(numerator / ((double)denominator / current->Frequency));
294 //printf("Display value is (counter): %lu%s\n", (unsigned long)dwordValue,
295 // (previous->CounterType == PERF_SAMPLE_COUNTER) ? "" : "/sec");
296 return (double)dwordValue;
297
298 case PERF_COUNTER_QUEUELEN_TYPE:
299 case PERF_COUNTER_100NS_QUEUELEN_TYPE:
300 case PERF_COUNTER_OBJ_TIME_QUEUELEN_TYPE:
301 case PERF_COUNTER_LARGE_QUEUELEN_TYPE:
302 case PERF_AVERAGE_BULK: // normally not displayed
303 // (N1 - N0) / (D1 - D0)
304 numerator = current->Data - previous->Data;
305 denominator = current->Time - previous->Time;
306 doubleValue = (double)numerator / denominator;
307 if (previous->CounterType != PERF_AVERAGE_BULK) {
308 // printf("Display value is (queuelen): %f\n", doubleValue);
309 return doubleValue;
310 }
311 return NAN;
312
313 case PERF_OBJ_TIME_TIMER:
314 case PERF_COUNTER_TIMER:
315 case PERF_100NSEC_TIMER:
316 case PERF_PRECISION_SYSTEM_TIMER:
317 case PERF_PRECISION_100NS_TIMER:
318 case PERF_PRECISION_OBJECT_TIMER:
319 case PERF_SAMPLE_FRACTION:
320 // 100 * (N1 - N0) / (D1 - D0)
321 numerator = current->Data - previous->Data;
322 denominator = current->Time - previous->Time;
323 doubleValue = (double)(100 * numerator) / denominator;
324 // printf("Display value is (timer): %f%%\n", doubleValue);
325 return doubleValue;
326
327 case PERF_COUNTER_TIMER_INV:
328 // 100 * (1 - ((N1 - N0) / (D1 - D0)))
329 numerator = current->Data - previous->Data;
330 denominator = current->Time - previous->Time;
331 doubleValue = 100 * (1 - ((double)numerator / denominator));
332 // printf("Display value is (timer-inv): %f%%\n", doubleValue);
333 return doubleValue;
334
335 case PERF_100NSEC_TIMER_INV:
336 // 100 * (1- (N1 - N0) / (D1 - D0))
337 numerator = current->Data - previous->Data;
338 denominator = current->Time - previous->Time;
339 doubleValue = 100 * (1 - (double)numerator / denominator);
340 // printf("Display value is (100ns-timer-inv): %f%%\n", doubleValue);
341 return doubleValue;
342
343 case PERF_COUNTER_MULTI_TIMER:
344 // 100 * ((N1 - N0) / ((D1 - D0) / TB)) / B1
345 numerator = current->Data - previous->Data;
346 denominator = current->Time - previous->Time;
347 denominator /= current->Frequency;
348 doubleValue = 100 * ((double)numerator / denominator) / current->MultiCounterData;
349 // printf("Display value is (multi-timer): %f%%\n", doubleValue);
350 return doubleValue;
351
352 case PERF_100NSEC_MULTI_TIMER:
353 // 100 * ((N1 - N0) / (D1 - D0)) / B1
354 numerator = current->Data - previous->Data;
355 denominator = current->Time - previous->Time;
356 doubleValue = 100 * ((double)numerator / (double)denominator) / (double)current->MultiCounterData;
357 // printf("Display value is (100ns multi-timer): %f%%\n", doubleValue);
358 return doubleValue;
359
360 case PERF_COUNTER_MULTI_TIMER_INV:
361 case PERF_100NSEC_MULTI_TIMER_INV:
362 // 100 * (B1 - ((N1 - N0) / (D1 - D0)))
363 numerator = current->Data - previous->Data;
364 denominator = current->Time - previous->Time;
365 doubleValue = 100.0 * ((double)current->MultiCounterData - ((double)numerator / (double)denominator));
366 // printf("Display value is (multi-timer-inv): %f%%\n", doubleValue);
367 return doubleValue;
368
369 case PERF_COUNTER_RAWCOUNT:
370 case PERF_COUNTER_LARGE_RAWCOUNT:
371 // N as decimal
372 // printf("Display value is (rawcount): %llu\n", current->Data);
373 return (double)current->Data;
374
375 case PERF_COUNTER_RAWCOUNT_HEX:
376 case PERF_COUNTER_LARGE_RAWCOUNT_HEX:
377 // N as hexadecimal
378 // printf("Display value is (hex): 0x%llx\n", current->Data);
379 return (double)current->Data;
380
381 case PERF_COUNTER_DELTA:
382 case PERF_COUNTER_LARGE_DELTA:
383 // N1 - N0
384 // printf("Display value is (delta): %llu\n", current->Data - previous->Data);
385 return (double)(current->Data - previous->Data);
386
387 case PERF_RAW_FRACTION:
388 case PERF_LARGE_RAW_FRACTION:
389 // 100 * N / B
390 doubleValue = 100.0 * (double)current->Data / (double)current->Time;
391 // printf("Display value is (fraction): %f%%\n", doubleValue);
392 return doubleValue;
393
394 case PERF_AVERAGE_TIMER:
395 // ((N1 - N0) / TB) / (B1 - B0)
396 numerator = current->Data - previous->Data;
397 denominator = current->Time - previous->Time;
398 doubleValue = (double)numerator / (double)current->Frequency / (double)denominator;
399 // printf("Display value is (average timer): %f seconds\n", doubleValue);
400 return doubleValue;
401
402 case PERF_ELAPSED_TIME:
403 // (D0 - N0) / F
404 doubleValue = (double)(current->Time - current->Data) / (double)current->Frequency;
405 // printf("Display value is (elapsed time): %f seconds\n", doubleValue);
406 return doubleValue;
407
408 case PERF_COUNTER_TEXT:
409 case PERF_SAMPLE_BASE:
410 case PERF_AVERAGE_BASE:
411 case PERF_COUNTER_MULTI_BASE:
412 case PERF_RAW_BASE:
413 case PERF_COUNTER_NODATA:
414 case PERF_PRECISION_TIMESTAMP:
415 // printf(" > Non-printing counter type: 0x%08x\n", current->CounterType);
416 return NAN;
417 break;
418
419 default:
420 // printf(" > Unrecognized counter type: 0x%08x\n", current->CounterType);
421 return NAN;
422 break;
423 }
424 }
425 */