perflib-rrd.c 16 KB

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