global_statistics.c 36 KB

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