global_statistics.c 36 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945
  1. // SPDX-License-Identifier: GPL-3.0-or-later
  2. #include "common.h"
  3. #define GLOBAL_STATS_RESET_WEB_USEC_MAX 0x01
  4. static struct global_statistics {
  5. volatile uint16_t connected_clients;
  6. volatile uint64_t web_requests;
  7. volatile uint64_t web_usec;
  8. volatile uint64_t web_usec_max;
  9. volatile uint64_t bytes_received;
  10. volatile uint64_t bytes_sent;
  11. volatile uint64_t content_size;
  12. volatile uint64_t compressed_content_size;
  13. volatile uint64_t web_client_count;
  14. volatile uint64_t rrdr_queries_made;
  15. volatile uint64_t rrdr_db_points_read;
  16. volatile uint64_t rrdr_result_points_generated;
  17. } global_statistics = {
  18. .connected_clients = 0,
  19. .web_requests = 0,
  20. .web_usec = 0,
  21. .bytes_received = 0,
  22. .bytes_sent = 0,
  23. .content_size = 0,
  24. .compressed_content_size = 0,
  25. .web_client_count = 1,
  26. .rrdr_queries_made = 0,
  27. .rrdr_db_points_read = 0,
  28. .rrdr_result_points_generated = 0,
  29. };
  30. #if defined(HAVE_C___ATOMIC) && !defined(NETDATA_NO_ATOMIC_INSTRUCTIONS)
  31. #else
  32. netdata_mutex_t global_statistics_mutex = NETDATA_MUTEX_INITIALIZER;
  33. static inline void global_statistics_lock(void) {
  34. netdata_mutex_lock(&global_statistics_mutex);
  35. }
  36. static inline void global_statistics_unlock(void) {
  37. netdata_mutex_unlock(&global_statistics_mutex);
  38. }
  39. #endif
  40. void rrdr_query_completed(uint64_t db_points_read, uint64_t result_points_generated) {
  41. #if defined(HAVE_C___ATOMIC) && !defined(NETDATA_NO_ATOMIC_INSTRUCTIONS)
  42. __atomic_fetch_add(&global_statistics.rrdr_queries_made, 1, __ATOMIC_SEQ_CST);
  43. __atomic_fetch_add(&global_statistics.rrdr_db_points_read, db_points_read, __ATOMIC_SEQ_CST);
  44. __atomic_fetch_add(&global_statistics.rrdr_result_points_generated, result_points_generated, __ATOMIC_SEQ_CST);
  45. #else
  46. #warning NOT using atomic operations - using locks for global statistics
  47. if (web_server_is_multithreaded)
  48. global_statistics_lock();
  49. global_statistics.rrdr_queries_made++;
  50. global_statistics.rrdr_db_points_read += db_points_read;
  51. global_statistics.rrdr_result_points_generated += result_points_generated;
  52. if (web_server_is_multithreaded)
  53. global_statistics_unlock();
  54. #endif
  55. }
  56. void finished_web_request_statistics(uint64_t dt,
  57. uint64_t bytes_received,
  58. uint64_t bytes_sent,
  59. uint64_t content_size,
  60. uint64_t compressed_content_size) {
  61. #if defined(HAVE_C___ATOMIC) && !defined(NETDATA_NO_ATOMIC_INSTRUCTIONS)
  62. uint64_t old_web_usec_max = global_statistics.web_usec_max;
  63. while(dt > old_web_usec_max)
  64. __atomic_compare_exchange(&global_statistics.web_usec_max, &old_web_usec_max, &dt, 1, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST);
  65. __atomic_fetch_add(&global_statistics.web_requests, 1, __ATOMIC_SEQ_CST);
  66. __atomic_fetch_add(&global_statistics.web_usec, dt, __ATOMIC_SEQ_CST);
  67. __atomic_fetch_add(&global_statistics.bytes_received, bytes_received, __ATOMIC_SEQ_CST);
  68. __atomic_fetch_add(&global_statistics.bytes_sent, bytes_sent, __ATOMIC_SEQ_CST);
  69. __atomic_fetch_add(&global_statistics.content_size, content_size, __ATOMIC_SEQ_CST);
  70. __atomic_fetch_add(&global_statistics.compressed_content_size, compressed_content_size, __ATOMIC_SEQ_CST);
  71. #else
  72. #warning NOT using atomic operations - using locks for global statistics
  73. if (web_server_is_multithreaded)
  74. global_statistics_lock();
  75. if (dt > global_statistics.web_usec_max)
  76. global_statistics.web_usec_max = dt;
  77. global_statistics.web_requests++;
  78. global_statistics.web_usec += dt;
  79. global_statistics.bytes_received += bytes_received;
  80. global_statistics.bytes_sent += bytes_sent;
  81. global_statistics.content_size += content_size;
  82. global_statistics.compressed_content_size += compressed_content_size;
  83. if (web_server_is_multithreaded)
  84. global_statistics_unlock();
  85. #endif
  86. }
  87. uint64_t web_client_connected(void) {
  88. #if defined(HAVE_C___ATOMIC) && !defined(NETDATA_NO_ATOMIC_INSTRUCTIONS)
  89. __atomic_fetch_add(&global_statistics.connected_clients, 1, __ATOMIC_SEQ_CST);
  90. uint64_t id = __atomic_fetch_add(&global_statistics.web_client_count, 1, __ATOMIC_SEQ_CST);
  91. #else
  92. if (web_server_is_multithreaded)
  93. global_statistics_lock();
  94. global_statistics.connected_clients++;
  95. uint64_t id = global_statistics.web_client_count++;
  96. if (web_server_is_multithreaded)
  97. global_statistics_unlock();
  98. #endif
  99. return id;
  100. }
  101. void web_client_disconnected(void) {
  102. #if defined(HAVE_C___ATOMIC) && !defined(NETDATA_NO_ATOMIC_INSTRUCTIONS)
  103. __atomic_fetch_sub(&global_statistics.connected_clients, 1, __ATOMIC_SEQ_CST);
  104. #else
  105. if (web_server_is_multithreaded)
  106. global_statistics_lock();
  107. global_statistics.connected_clients--;
  108. if (web_server_is_multithreaded)
  109. global_statistics_unlock();
  110. #endif
  111. }
  112. static inline void global_statistics_copy(struct global_statistics *gs, uint8_t options) {
  113. #if defined(HAVE_C___ATOMIC) && !defined(NETDATA_NO_ATOMIC_INSTRUCTIONS)
  114. gs->connected_clients = __atomic_fetch_add(&global_statistics.connected_clients, 0, __ATOMIC_SEQ_CST);
  115. gs->web_requests = __atomic_fetch_add(&global_statistics.web_requests, 0, __ATOMIC_SEQ_CST);
  116. gs->web_usec = __atomic_fetch_add(&global_statistics.web_usec, 0, __ATOMIC_SEQ_CST);
  117. gs->web_usec_max = __atomic_fetch_add(&global_statistics.web_usec_max, 0, __ATOMIC_SEQ_CST);
  118. gs->bytes_received = __atomic_fetch_add(&global_statistics.bytes_received, 0, __ATOMIC_SEQ_CST);
  119. gs->bytes_sent = __atomic_fetch_add(&global_statistics.bytes_sent, 0, __ATOMIC_SEQ_CST);
  120. gs->content_size = __atomic_fetch_add(&global_statistics.content_size, 0, __ATOMIC_SEQ_CST);
  121. gs->compressed_content_size = __atomic_fetch_add(&global_statistics.compressed_content_size, 0, __ATOMIC_SEQ_CST);
  122. gs->web_client_count = __atomic_fetch_add(&global_statistics.web_client_count, 0, __ATOMIC_SEQ_CST);
  123. gs->rrdr_queries_made = __atomic_fetch_add(&global_statistics.rrdr_queries_made, 0, __ATOMIC_SEQ_CST);
  124. gs->rrdr_db_points_read = __atomic_fetch_add(&global_statistics.rrdr_db_points_read, 0, __ATOMIC_SEQ_CST);
  125. gs->rrdr_result_points_generated = __atomic_fetch_add(&global_statistics.rrdr_result_points_generated, 0, __ATOMIC_SEQ_CST);
  126. if(options & GLOBAL_STATS_RESET_WEB_USEC_MAX) {
  127. uint64_t n = 0;
  128. __atomic_compare_exchange(&global_statistics.web_usec_max, &gs->web_usec_max, &n, 1, __ATOMIC_SEQ_CST,
  129. __ATOMIC_SEQ_CST);
  130. }
  131. #else
  132. global_statistics_lock();
  133. memcpy(gs, (const void *)&global_statistics, sizeof(struct global_statistics));
  134. if (options & GLOBAL_STATS_RESET_WEB_USEC_MAX)
  135. global_statistics.web_usec_max = 0;
  136. global_statistics_unlock();
  137. #endif
  138. }
  139. void global_statistics_charts(void) {
  140. static unsigned long long old_web_requests = 0,
  141. old_web_usec = 0,
  142. old_content_size = 0,
  143. old_compressed_content_size = 0;
  144. static collected_number compression_ratio = -1,
  145. average_response_time = -1;
  146. struct global_statistics gs;
  147. struct rusage me, thread;
  148. global_statistics_copy(&gs, GLOBAL_STATS_RESET_WEB_USEC_MAX);
  149. getrusage(RUSAGE_THREAD, &thread);
  150. getrusage(RUSAGE_SELF, &me);
  151. {
  152. static RRDSET *st_cpu_thread = NULL;
  153. static RRDDIM *rd_cpu_thread_user = NULL,
  154. *rd_cpu_thread_system = NULL;
  155. #ifdef __FreeBSD__
  156. if (unlikely(!st_cpu_thread)) {
  157. st_cpu_thread = rrdset_create_localhost(
  158. "netdata"
  159. , "plugin_freebsd_cpu"
  160. , NULL
  161. , "freebsd"
  162. , NULL
  163. , "NetData FreeBSD Plugin CPU usage"
  164. , "milliseconds/s"
  165. , "netdata"
  166. , "stats"
  167. , 132000
  168. , localhost->rrd_update_every
  169. , RRDSET_TYPE_STACKED
  170. );
  171. #else
  172. if (unlikely(!st_cpu_thread)) {
  173. st_cpu_thread = rrdset_create_localhost(
  174. "netdata"
  175. , "plugin_proc_cpu"
  176. , NULL
  177. , "proc"
  178. , NULL
  179. , "NetData Proc Plugin CPU usage"
  180. , "milliseconds/s"
  181. , "netdata"
  182. , "stats"
  183. , 132000
  184. , localhost->rrd_update_every
  185. , RRDSET_TYPE_STACKED
  186. );
  187. #endif
  188. rd_cpu_thread_user = rrddim_add(st_cpu_thread, "user", NULL, 1, 1000, RRD_ALGORITHM_INCREMENTAL);
  189. rd_cpu_thread_system = rrddim_add(st_cpu_thread, "system", NULL, 1, 1000, RRD_ALGORITHM_INCREMENTAL);
  190. }
  191. else
  192. rrdset_next(st_cpu_thread);
  193. rrddim_set_by_pointer(st_cpu_thread, rd_cpu_thread_user, thread.ru_utime.tv_sec * 1000000ULL + thread.ru_utime.tv_usec);
  194. rrddim_set_by_pointer(st_cpu_thread, rd_cpu_thread_system, thread.ru_stime.tv_sec * 1000000ULL + thread.ru_stime.tv_usec);
  195. rrdset_done(st_cpu_thread);
  196. }
  197. // ----------------------------------------------------------------
  198. {
  199. static RRDSET *st_cpu = NULL;
  200. static RRDDIM *rd_cpu_user = NULL,
  201. *rd_cpu_system = NULL;
  202. if (unlikely(!st_cpu)) {
  203. st_cpu = rrdset_create_localhost(
  204. "netdata"
  205. , "server_cpu"
  206. , NULL
  207. , "netdata"
  208. , NULL
  209. , "NetData CPU usage"
  210. , "milliseconds/s"
  211. , "netdata"
  212. , "stats"
  213. , 130000
  214. , localhost->rrd_update_every
  215. , RRDSET_TYPE_STACKED
  216. );
  217. rd_cpu_user = rrddim_add(st_cpu, "user", NULL, 1, 1000, RRD_ALGORITHM_INCREMENTAL);
  218. rd_cpu_system = rrddim_add(st_cpu, "system", NULL, 1, 1000, RRD_ALGORITHM_INCREMENTAL);
  219. }
  220. else
  221. rrdset_next(st_cpu);
  222. rrddim_set_by_pointer(st_cpu, rd_cpu_user, me.ru_utime.tv_sec * 1000000ULL + me.ru_utime.tv_usec);
  223. rrddim_set_by_pointer(st_cpu, rd_cpu_system, me.ru_stime.tv_sec * 1000000ULL + me.ru_stime.tv_usec);
  224. rrdset_done(st_cpu);
  225. }
  226. // ----------------------------------------------------------------
  227. {
  228. static RRDSET *st_clients = NULL;
  229. static RRDDIM *rd_clients = NULL;
  230. if (unlikely(!st_clients)) {
  231. st_clients = rrdset_create_localhost(
  232. "netdata"
  233. , "clients"
  234. , NULL
  235. , "netdata"
  236. , NULL
  237. , "NetData Web Clients"
  238. , "connected clients"
  239. , "netdata"
  240. , "stats"
  241. , 130200
  242. , localhost->rrd_update_every
  243. , RRDSET_TYPE_LINE
  244. );
  245. rd_clients = rrddim_add(st_clients, "clients", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
  246. }
  247. else
  248. rrdset_next(st_clients);
  249. rrddim_set_by_pointer(st_clients, rd_clients, gs.connected_clients);
  250. rrdset_done(st_clients);
  251. }
  252. // ----------------------------------------------------------------
  253. {
  254. static RRDSET *st_reqs = NULL;
  255. static RRDDIM *rd_requests = NULL;
  256. if (unlikely(!st_reqs)) {
  257. st_reqs = rrdset_create_localhost(
  258. "netdata"
  259. , "requests"
  260. , NULL
  261. , "netdata"
  262. , NULL
  263. , "NetData Web Requests"
  264. , "requests/s"
  265. , "netdata"
  266. , "stats"
  267. , 130300
  268. , localhost->rrd_update_every
  269. , RRDSET_TYPE_LINE
  270. );
  271. rd_requests = rrddim_add(st_reqs, "requests", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
  272. }
  273. else
  274. rrdset_next(st_reqs);
  275. rrddim_set_by_pointer(st_reqs, rd_requests, (collected_number) gs.web_requests);
  276. rrdset_done(st_reqs);
  277. }
  278. // ----------------------------------------------------------------
  279. {
  280. static RRDSET *st_bytes = NULL;
  281. static RRDDIM *rd_in = NULL,
  282. *rd_out = NULL;
  283. if (unlikely(!st_bytes)) {
  284. st_bytes = rrdset_create_localhost(
  285. "netdata"
  286. , "net"
  287. , NULL
  288. , "netdata"
  289. , NULL
  290. , "NetData Network Traffic"
  291. , "kilobits/s"
  292. , "netdata"
  293. , "stats"
  294. , 130000
  295. , localhost->rrd_update_every
  296. , RRDSET_TYPE_AREA
  297. );
  298. rd_in = rrddim_add(st_bytes, "in", NULL, 8, BITS_IN_A_KILOBIT, RRD_ALGORITHM_INCREMENTAL);
  299. rd_out = rrddim_add(st_bytes, "out", NULL, -8, BITS_IN_A_KILOBIT, RRD_ALGORITHM_INCREMENTAL);
  300. }
  301. else
  302. rrdset_next(st_bytes);
  303. rrddim_set_by_pointer(st_bytes, rd_in, (collected_number) gs.bytes_received);
  304. rrddim_set_by_pointer(st_bytes, rd_out, (collected_number) gs.bytes_sent);
  305. rrdset_done(st_bytes);
  306. }
  307. // ----------------------------------------------------------------
  308. {
  309. static RRDSET *st_duration = NULL;
  310. static RRDDIM *rd_average = NULL,
  311. *rd_max = NULL;
  312. if (unlikely(!st_duration)) {
  313. st_duration = rrdset_create_localhost(
  314. "netdata"
  315. , "response_time"
  316. , NULL
  317. , "netdata"
  318. , NULL
  319. , "NetData API Response Time"
  320. , "milliseconds/request"
  321. , "netdata"
  322. , "stats"
  323. , 130400
  324. , localhost->rrd_update_every
  325. , RRDSET_TYPE_LINE
  326. );
  327. rd_average = rrddim_add(st_duration, "average", NULL, 1, 1000, RRD_ALGORITHM_ABSOLUTE);
  328. rd_max = rrddim_add(st_duration, "max", NULL, 1, 1000, RRD_ALGORITHM_ABSOLUTE);
  329. }
  330. else
  331. rrdset_next(st_duration);
  332. uint64_t gweb_usec = gs.web_usec;
  333. uint64_t gweb_requests = gs.web_requests;
  334. uint64_t web_usec = (gweb_usec >= old_web_usec) ? gweb_usec - old_web_usec : 0;
  335. uint64_t web_requests = (gweb_requests >= old_web_requests) ? gweb_requests - old_web_requests : 0;
  336. old_web_usec = gweb_usec;
  337. old_web_requests = gweb_requests;
  338. if (web_requests)
  339. average_response_time = (collected_number) (web_usec / web_requests);
  340. if (unlikely(average_response_time != -1))
  341. rrddim_set_by_pointer(st_duration, rd_average, average_response_time);
  342. else
  343. rrddim_set_by_pointer(st_duration, rd_average, 0);
  344. rrddim_set_by_pointer(st_duration, rd_max, ((gs.web_usec_max)?(collected_number)gs.web_usec_max:average_response_time));
  345. rrdset_done(st_duration);
  346. }
  347. // ----------------------------------------------------------------
  348. {
  349. static RRDSET *st_compression = NULL;
  350. static RRDDIM *rd_savings = NULL;
  351. if (unlikely(!st_compression)) {
  352. st_compression = rrdset_create_localhost(
  353. "netdata"
  354. , "compression_ratio"
  355. , NULL
  356. , "netdata"
  357. , NULL
  358. , "NetData API Responses Compression Savings Ratio"
  359. , "percentage"
  360. , "netdata"
  361. , "stats"
  362. , 130500
  363. , localhost->rrd_update_every
  364. , RRDSET_TYPE_LINE
  365. );
  366. rd_savings = rrddim_add(st_compression, "savings", NULL, 1, 1000, RRD_ALGORITHM_ABSOLUTE);
  367. }
  368. else
  369. rrdset_next(st_compression);
  370. // since we don't lock here to read the global statistics
  371. // read the smaller value first
  372. unsigned long long gcompressed_content_size = gs.compressed_content_size;
  373. unsigned long long gcontent_size = gs.content_size;
  374. unsigned long long compressed_content_size = gcompressed_content_size - old_compressed_content_size;
  375. unsigned long long content_size = gcontent_size - old_content_size;
  376. old_compressed_content_size = gcompressed_content_size;
  377. old_content_size = gcontent_size;
  378. if (content_size && content_size >= compressed_content_size)
  379. compression_ratio = ((content_size - compressed_content_size) * 100 * 1000) / content_size;
  380. if (compression_ratio != -1)
  381. rrddim_set_by_pointer(st_compression, rd_savings, compression_ratio);
  382. rrdset_done(st_compression);
  383. }
  384. // ----------------------------------------------------------------
  385. if(gs.rrdr_queries_made) {
  386. static RRDSET *st_rrdr_queries = NULL;
  387. static RRDDIM *rd_queries = NULL;
  388. if (unlikely(!st_rrdr_queries)) {
  389. st_rrdr_queries = rrdset_create_localhost(
  390. "netdata"
  391. , "queries"
  392. , NULL
  393. , "queries"
  394. , NULL
  395. , "NetData API Queries"
  396. , "queries/s"
  397. , "netdata"
  398. , "stats"
  399. , 130500
  400. , localhost->rrd_update_every
  401. , RRDSET_TYPE_LINE
  402. );
  403. rd_queries = rrddim_add(st_rrdr_queries, "queries", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
  404. }
  405. else
  406. rrdset_next(st_rrdr_queries);
  407. rrddim_set_by_pointer(st_rrdr_queries, rd_queries, (collected_number)gs.rrdr_queries_made);
  408. rrdset_done(st_rrdr_queries);
  409. }
  410. // ----------------------------------------------------------------
  411. if(gs.rrdr_db_points_read || gs.rrdr_result_points_generated) {
  412. static RRDSET *st_rrdr_points = NULL;
  413. static RRDDIM *rd_points_read = NULL;
  414. static RRDDIM *rd_points_generated = NULL;
  415. if (unlikely(!st_rrdr_points)) {
  416. st_rrdr_points = rrdset_create_localhost(
  417. "netdata"
  418. , "db_points"
  419. , NULL
  420. , "queries"
  421. , NULL
  422. , "NetData API Points"
  423. , "points/s"
  424. , "netdata"
  425. , "stats"
  426. , 130501
  427. , localhost->rrd_update_every
  428. , RRDSET_TYPE_AREA
  429. );
  430. rd_points_read = rrddim_add(st_rrdr_points, "read", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
  431. rd_points_generated = rrddim_add(st_rrdr_points, "generated", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
  432. }
  433. else
  434. rrdset_next(st_rrdr_points);
  435. rrddim_set_by_pointer(st_rrdr_points, rd_points_read, (collected_number)gs.rrdr_db_points_read);
  436. rrddim_set_by_pointer(st_rrdr_points, rd_points_generated, (collected_number)gs.rrdr_result_points_generated);
  437. rrdset_done(st_rrdr_points);
  438. }
  439. // ----------------------------------------------------------------
  440. #ifdef ENABLE_DBENGINE
  441. RRDHOST *host;
  442. unsigned long long stats_array[RRDENG_NR_STATS] = {0};
  443. unsigned long long local_stats_array[RRDENG_NR_STATS];
  444. unsigned hosts_with_dbengine = 0, i;
  445. rrd_rdlock();
  446. rrdhost_foreach_read(host) {
  447. if (host->rrd_memory_mode == RRD_MEMORY_MODE_DBENGINE) {
  448. ++hosts_with_dbengine;
  449. /* get localhost's DB engine's statistics */
  450. rrdeng_get_37_statistics(host->rrdeng_ctx, local_stats_array);
  451. for (i = 0 ; i < RRDENG_NR_STATS ; ++i) {
  452. /* aggregate statistics across hosts */
  453. stats_array[i] += local_stats_array[i];
  454. }
  455. }
  456. }
  457. rrd_unlock();
  458. if (hosts_with_dbengine) {
  459. /* deduplicate global statistics by getting the ones from the last host */
  460. stats_array[30] = local_stats_array[30];
  461. stats_array[31] = local_stats_array[31];
  462. stats_array[32] = local_stats_array[32];
  463. stats_array[34] = local_stats_array[34];
  464. stats_array[36] = local_stats_array[36];
  465. // ----------------------------------------------------------------
  466. {
  467. static RRDSET *st_compression = NULL;
  468. static RRDDIM *rd_savings = NULL;
  469. if (unlikely(!st_compression)) {
  470. st_compression = rrdset_create_localhost(
  471. "netdata"
  472. , "dbengine_compression_ratio"
  473. , NULL
  474. , "dbengine"
  475. , NULL
  476. , "NetData DB engine data extents' compression savings ratio"
  477. , "percentage"
  478. , "netdata"
  479. , "stats"
  480. , 130502
  481. , localhost->rrd_update_every
  482. , RRDSET_TYPE_LINE
  483. );
  484. rd_savings = rrddim_add(st_compression, "savings", NULL, 1, 1000, RRD_ALGORITHM_ABSOLUTE);
  485. }
  486. else
  487. rrdset_next(st_compression);
  488. unsigned long long ratio;
  489. unsigned long long compressed_content_size = stats_array[12];
  490. unsigned long long content_size = stats_array[11];
  491. if (content_size) {
  492. // allow negative savings
  493. ratio = ((content_size - compressed_content_size) * 100 * 1000) / content_size;
  494. } else {
  495. ratio = 0;
  496. }
  497. rrddim_set_by_pointer(st_compression, rd_savings, ratio);
  498. rrdset_done(st_compression);
  499. }
  500. // ----------------------------------------------------------------
  501. {
  502. static RRDSET *st_pg_cache_hit_ratio = NULL;
  503. static RRDDIM *rd_hit_ratio = NULL;
  504. if (unlikely(!st_pg_cache_hit_ratio)) {
  505. st_pg_cache_hit_ratio = rrdset_create_localhost(
  506. "netdata"
  507. , "page_cache_hit_ratio"
  508. , NULL
  509. , "dbengine"
  510. , NULL
  511. , "NetData DB engine page cache hit ratio"
  512. , "percentage"
  513. , "netdata"
  514. , "stats"
  515. , 130503
  516. , localhost->rrd_update_every
  517. , RRDSET_TYPE_LINE
  518. );
  519. rd_hit_ratio = rrddim_add(st_pg_cache_hit_ratio, "ratio", NULL, 1, 1000, RRD_ALGORITHM_ABSOLUTE);
  520. }
  521. else
  522. rrdset_next(st_pg_cache_hit_ratio);
  523. static unsigned long long old_hits = 0;
  524. static unsigned long long old_misses = 0;
  525. unsigned long long hits = stats_array[7];
  526. unsigned long long misses = stats_array[8];
  527. unsigned long long hits_delta;
  528. unsigned long long misses_delta;
  529. unsigned long long ratio;
  530. hits_delta = hits - old_hits;
  531. misses_delta = misses - old_misses;
  532. old_hits = hits;
  533. old_misses = misses;
  534. if (hits_delta + misses_delta) {
  535. ratio = (hits_delta * 100 * 1000) / (hits_delta + misses_delta);
  536. } else {
  537. ratio = 0;
  538. }
  539. rrddim_set_by_pointer(st_pg_cache_hit_ratio, rd_hit_ratio, ratio);
  540. rrdset_done(st_pg_cache_hit_ratio);
  541. }
  542. // ----------------------------------------------------------------
  543. {
  544. static RRDSET *st_pg_cache_pages = NULL;
  545. static RRDDIM *rd_descriptors = NULL;
  546. static RRDDIM *rd_populated = NULL;
  547. static RRDDIM *rd_dirty = NULL;
  548. static RRDDIM *rd_backfills = NULL;
  549. static RRDDIM *rd_evictions = NULL;
  550. static RRDDIM *rd_used_by_collectors = NULL;
  551. if (unlikely(!st_pg_cache_pages)) {
  552. st_pg_cache_pages = rrdset_create_localhost(
  553. "netdata"
  554. , "page_cache_stats"
  555. , NULL
  556. , "dbengine"
  557. , NULL
  558. , "NetData dbengine page cache statistics"
  559. , "pages"
  560. , "netdata"
  561. , "stats"
  562. , 130504
  563. , localhost->rrd_update_every
  564. , RRDSET_TYPE_LINE
  565. );
  566. rd_descriptors = rrddim_add(st_pg_cache_pages, "descriptors", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
  567. rd_populated = rrddim_add(st_pg_cache_pages, "populated", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
  568. rd_dirty = rrddim_add(st_pg_cache_pages, "dirty", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
  569. rd_backfills = rrddim_add(st_pg_cache_pages, "backfills", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
  570. rd_evictions = rrddim_add(st_pg_cache_pages, "evictions", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
  571. rd_used_by_collectors = rrddim_add(st_pg_cache_pages, "used_by_collectors", NULL, 1, 1,
  572. RRD_ALGORITHM_ABSOLUTE);
  573. }
  574. else
  575. rrdset_next(st_pg_cache_pages);
  576. rrddim_set_by_pointer(st_pg_cache_pages, rd_descriptors, (collected_number)stats_array[27]);
  577. rrddim_set_by_pointer(st_pg_cache_pages, rd_populated, (collected_number)stats_array[3]);
  578. rrddim_set_by_pointer(st_pg_cache_pages, rd_dirty, (collected_number)stats_array[0] + stats_array[4]);
  579. rrddim_set_by_pointer(st_pg_cache_pages, rd_backfills, (collected_number)stats_array[9]);
  580. rrddim_set_by_pointer(st_pg_cache_pages, rd_evictions, (collected_number)stats_array[10]);
  581. rrddim_set_by_pointer(st_pg_cache_pages, rd_used_by_collectors, (collected_number)stats_array[0]);
  582. rrdset_done(st_pg_cache_pages);
  583. }
  584. // ----------------------------------------------------------------
  585. {
  586. static RRDSET *st_long_term_pages = NULL;
  587. static RRDDIM *rd_total = NULL;
  588. static RRDDIM *rd_insertions = NULL;
  589. static RRDDIM *rd_deletions = NULL;
  590. static RRDDIM *rd_flushing_pressure_deletions = NULL;
  591. if (unlikely(!st_long_term_pages)) {
  592. st_long_term_pages = rrdset_create_localhost(
  593. "netdata"
  594. , "dbengine_long_term_page_stats"
  595. , NULL
  596. , "dbengine"
  597. , NULL
  598. , "NetData dbengine long-term page statistics"
  599. , "pages"
  600. , "netdata"
  601. , "stats"
  602. , 130505
  603. , localhost->rrd_update_every
  604. , RRDSET_TYPE_LINE
  605. );
  606. rd_total = rrddim_add(st_long_term_pages, "total", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
  607. rd_insertions = rrddim_add(st_long_term_pages, "insertions", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
  608. rd_deletions = rrddim_add(st_long_term_pages, "deletions", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
  609. rd_flushing_pressure_deletions = rrddim_add(st_long_term_pages, "flushing_pressure_deletions", NULL, -1,
  610. 1, RRD_ALGORITHM_INCREMENTAL);
  611. }
  612. else
  613. rrdset_next(st_long_term_pages);
  614. rrddim_set_by_pointer(st_long_term_pages, rd_total, (collected_number)stats_array[2]);
  615. rrddim_set_by_pointer(st_long_term_pages, rd_insertions, (collected_number)stats_array[5]);
  616. rrddim_set_by_pointer(st_long_term_pages, rd_deletions, (collected_number)stats_array[6]);
  617. rrddim_set_by_pointer(st_long_term_pages, rd_flushing_pressure_deletions,
  618. (collected_number)stats_array[36]);
  619. rrdset_done(st_long_term_pages);
  620. }
  621. // ----------------------------------------------------------------
  622. {
  623. static RRDSET *st_io_stats = NULL;
  624. static RRDDIM *rd_reads = NULL;
  625. static RRDDIM *rd_writes = NULL;
  626. if (unlikely(!st_io_stats)) {
  627. st_io_stats = rrdset_create_localhost(
  628. "netdata"
  629. , "dbengine_io_throughput"
  630. , NULL
  631. , "dbengine"
  632. , NULL
  633. , "NetData DB engine I/O throughput"
  634. , "MiB/s"
  635. , "netdata"
  636. , "stats"
  637. , 130506
  638. , localhost->rrd_update_every
  639. , RRDSET_TYPE_LINE
  640. );
  641. rd_reads = rrddim_add(st_io_stats, "reads", NULL, 1, 1024 * 1024, RRD_ALGORITHM_INCREMENTAL);
  642. rd_writes = rrddim_add(st_io_stats, "writes", NULL, -1, 1024 * 1024, RRD_ALGORITHM_INCREMENTAL);
  643. }
  644. else
  645. rrdset_next(st_io_stats);
  646. rrddim_set_by_pointer(st_io_stats, rd_reads, (collected_number)stats_array[17]);
  647. rrddim_set_by_pointer(st_io_stats, rd_writes, (collected_number)stats_array[15]);
  648. rrdset_done(st_io_stats);
  649. }
  650. // ----------------------------------------------------------------
  651. {
  652. static RRDSET *st_io_stats = NULL;
  653. static RRDDIM *rd_reads = NULL;
  654. static RRDDIM *rd_writes = NULL;
  655. if (unlikely(!st_io_stats)) {
  656. st_io_stats = rrdset_create_localhost(
  657. "netdata"
  658. , "dbengine_io_operations"
  659. , NULL
  660. , "dbengine"
  661. , NULL
  662. , "NetData DB engine I/O operations"
  663. , "operations/s"
  664. , "netdata"
  665. , "stats"
  666. , 130507
  667. , localhost->rrd_update_every
  668. , RRDSET_TYPE_LINE
  669. );
  670. rd_reads = rrddim_add(st_io_stats, "reads", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
  671. rd_writes = rrddim_add(st_io_stats, "writes", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
  672. }
  673. else
  674. rrdset_next(st_io_stats);
  675. rrddim_set_by_pointer(st_io_stats, rd_reads, (collected_number)stats_array[18]);
  676. rrddim_set_by_pointer(st_io_stats, rd_writes, (collected_number)stats_array[16]);
  677. rrdset_done(st_io_stats);
  678. }
  679. // ----------------------------------------------------------------
  680. {
  681. static RRDSET *st_errors = NULL;
  682. static RRDDIM *rd_fs_errors = NULL;
  683. static RRDDIM *rd_io_errors = NULL;
  684. static RRDDIM *pg_cache_over_half_dirty_events = NULL;
  685. if (unlikely(!st_errors)) {
  686. st_errors = rrdset_create_localhost(
  687. "netdata"
  688. , "dbengine_global_errors"
  689. , NULL
  690. , "dbengine"
  691. , NULL
  692. , "NetData DB engine errors"
  693. , "errors/s"
  694. , "netdata"
  695. , "stats"
  696. , 130508
  697. , localhost->rrd_update_every
  698. , RRDSET_TYPE_LINE
  699. );
  700. rd_io_errors = rrddim_add(st_errors, "io_errors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
  701. rd_fs_errors = rrddim_add(st_errors, "fs_errors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
  702. pg_cache_over_half_dirty_events = rrddim_add(st_errors, "pg_cache_over_half_dirty_events", NULL, 1, 1,
  703. RRD_ALGORITHM_INCREMENTAL);
  704. }
  705. else
  706. rrdset_next(st_errors);
  707. rrddim_set_by_pointer(st_errors, rd_io_errors, (collected_number)stats_array[30]);
  708. rrddim_set_by_pointer(st_errors, rd_fs_errors, (collected_number)stats_array[31]);
  709. rrddim_set_by_pointer(st_errors, pg_cache_over_half_dirty_events, (collected_number)stats_array[34]);
  710. rrdset_done(st_errors);
  711. }
  712. // ----------------------------------------------------------------
  713. {
  714. static RRDSET *st_fd = NULL;
  715. static RRDDIM *rd_fd_current = NULL;
  716. static RRDDIM *rd_fd_max = NULL;
  717. if (unlikely(!st_fd)) {
  718. st_fd = rrdset_create_localhost(
  719. "netdata"
  720. , "dbengine_global_file_descriptors"
  721. , NULL
  722. , "dbengine"
  723. , NULL
  724. , "NetData DB engine File Descriptors"
  725. , "descriptors"
  726. , "netdata"
  727. , "stats"
  728. , 130509
  729. , localhost->rrd_update_every
  730. , RRDSET_TYPE_LINE
  731. );
  732. rd_fd_current = rrddim_add(st_fd, "current", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
  733. rd_fd_max = rrddim_add(st_fd, "max", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
  734. }
  735. else
  736. rrdset_next(st_fd);
  737. rrddim_set_by_pointer(st_fd, rd_fd_current, (collected_number)stats_array[32]);
  738. /* Careful here, modify this accordingly if the File-Descriptor budget ever changes */
  739. rrddim_set_by_pointer(st_fd, rd_fd_max, (collected_number)rlimit_nofile.rlim_cur / 4);
  740. rrdset_done(st_fd);
  741. }
  742. // ----------------------------------------------------------------
  743. {
  744. static RRDSET *st_ram_usage = NULL;
  745. static RRDDIM *rd_cached = NULL;
  746. static RRDDIM *rd_pinned = NULL;
  747. static RRDDIM *rd_metadata = NULL;
  748. collected_number cached_pages, pinned_pages, API_producers, populated_pages, metadata, pages_on_disk,
  749. page_cache_descriptors;
  750. if (unlikely(!st_ram_usage)) {
  751. st_ram_usage = rrdset_create_localhost(
  752. "netdata"
  753. , "dbengine_ram"
  754. , NULL
  755. , "dbengine"
  756. , NULL
  757. , "NetData DB engine RAM usage"
  758. , "MiB"
  759. , "netdata"
  760. , "stats"
  761. , 130510
  762. , localhost->rrd_update_every
  763. , RRDSET_TYPE_STACKED
  764. );
  765. rd_cached = rrddim_add(st_ram_usage, "cache", NULL, 1, 256, RRD_ALGORITHM_ABSOLUTE);
  766. rd_pinned = rrddim_add(st_ram_usage, "collectors", NULL, 1, 256, RRD_ALGORITHM_ABSOLUTE);
  767. rd_metadata = rrddim_add(st_ram_usage, "metadata", NULL, 1, 1048576, RRD_ALGORITHM_ABSOLUTE);
  768. }
  769. else
  770. rrdset_next(st_ram_usage);
  771. API_producers = (collected_number)stats_array[0];
  772. pages_on_disk = (collected_number)stats_array[2];
  773. populated_pages = (collected_number)stats_array[3];
  774. page_cache_descriptors = (collected_number)stats_array[27];
  775. if (API_producers * 2 > populated_pages) {
  776. pinned_pages = API_producers;
  777. } else{
  778. pinned_pages = API_producers * 2;
  779. }
  780. cached_pages = populated_pages - pinned_pages;
  781. metadata = page_cache_descriptors * sizeof(struct page_cache_descr);
  782. metadata += pages_on_disk * sizeof(struct rrdeng_page_descr);
  783. /* This is an empirical estimation for Judy array indexing and extent structures */
  784. metadata += pages_on_disk * 58;
  785. rrddim_set_by_pointer(st_ram_usage, rd_cached, cached_pages);
  786. rrddim_set_by_pointer(st_ram_usage, rd_pinned, pinned_pages);
  787. rrddim_set_by_pointer(st_ram_usage, rd_metadata, metadata);
  788. rrdset_done(st_ram_usage);
  789. }
  790. }
  791. #endif
  792. }