global_statistics.c 36 KB

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