global_statistics.c 36 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950
  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 dbengine_contexts = 0, counted_multihost_db = 0, i;
  445. rrd_rdlock();
  446. rrdhost_foreach_read(host) {
  447. if (host->rrd_memory_mode == RRD_MEMORY_MODE_DBENGINE && !rrdhost_flag_check(host, RRDHOST_FLAG_ARCHIVED)) {
  448. if (&multidb_ctx == host->rrdeng_ctx) {
  449. if (counted_multihost_db)
  450. continue; /* Only count multi-host DB once */
  451. counted_multihost_db = 1;
  452. }
  453. ++dbengine_contexts;
  454. /* get localhost's DB engine's statistics */
  455. rrdeng_get_37_statistics(host->rrdeng_ctx, local_stats_array);
  456. for (i = 0 ; i < RRDENG_NR_STATS ; ++i) {
  457. /* aggregate statistics across hosts */
  458. stats_array[i] += local_stats_array[i];
  459. }
  460. }
  461. }
  462. rrd_unlock();
  463. if (dbengine_contexts) {
  464. /* deduplicate global statistics by getting the ones from the last context */
  465. stats_array[30] = local_stats_array[30];
  466. stats_array[31] = local_stats_array[31];
  467. stats_array[32] = local_stats_array[32];
  468. stats_array[34] = local_stats_array[34];
  469. stats_array[36] = local_stats_array[36];
  470. // ----------------------------------------------------------------
  471. {
  472. static RRDSET *st_compression = NULL;
  473. static RRDDIM *rd_savings = NULL;
  474. if (unlikely(!st_compression)) {
  475. st_compression = rrdset_create_localhost(
  476. "netdata"
  477. , "dbengine_compression_ratio"
  478. , NULL
  479. , "dbengine"
  480. , NULL
  481. , "NetData DB engine data extents' compression savings ratio"
  482. , "percentage"
  483. , "netdata"
  484. , "stats"
  485. , 130502
  486. , localhost->rrd_update_every
  487. , RRDSET_TYPE_LINE
  488. );
  489. rd_savings = rrddim_add(st_compression, "savings", NULL, 1, 1000, RRD_ALGORITHM_ABSOLUTE);
  490. }
  491. else
  492. rrdset_next(st_compression);
  493. unsigned long long ratio;
  494. unsigned long long compressed_content_size = stats_array[12];
  495. unsigned long long content_size = stats_array[11];
  496. if (content_size) {
  497. // allow negative savings
  498. ratio = ((content_size - compressed_content_size) * 100 * 1000) / content_size;
  499. } else {
  500. ratio = 0;
  501. }
  502. rrddim_set_by_pointer(st_compression, rd_savings, ratio);
  503. rrdset_done(st_compression);
  504. }
  505. // ----------------------------------------------------------------
  506. {
  507. static RRDSET *st_pg_cache_hit_ratio = NULL;
  508. static RRDDIM *rd_hit_ratio = NULL;
  509. if (unlikely(!st_pg_cache_hit_ratio)) {
  510. st_pg_cache_hit_ratio = rrdset_create_localhost(
  511. "netdata"
  512. , "page_cache_hit_ratio"
  513. , NULL
  514. , "dbengine"
  515. , NULL
  516. , "NetData DB engine page cache hit ratio"
  517. , "percentage"
  518. , "netdata"
  519. , "stats"
  520. , 130503
  521. , localhost->rrd_update_every
  522. , RRDSET_TYPE_LINE
  523. );
  524. rd_hit_ratio = rrddim_add(st_pg_cache_hit_ratio, "ratio", NULL, 1, 1000, RRD_ALGORITHM_ABSOLUTE);
  525. }
  526. else
  527. rrdset_next(st_pg_cache_hit_ratio);
  528. static unsigned long long old_hits = 0;
  529. static unsigned long long old_misses = 0;
  530. unsigned long long hits = stats_array[7];
  531. unsigned long long misses = stats_array[8];
  532. unsigned long long hits_delta;
  533. unsigned long long misses_delta;
  534. unsigned long long ratio;
  535. hits_delta = hits - old_hits;
  536. misses_delta = misses - old_misses;
  537. old_hits = hits;
  538. old_misses = misses;
  539. if (hits_delta + misses_delta) {
  540. ratio = (hits_delta * 100 * 1000) / (hits_delta + misses_delta);
  541. } else {
  542. ratio = 0;
  543. }
  544. rrddim_set_by_pointer(st_pg_cache_hit_ratio, rd_hit_ratio, ratio);
  545. rrdset_done(st_pg_cache_hit_ratio);
  546. }
  547. // ----------------------------------------------------------------
  548. {
  549. static RRDSET *st_pg_cache_pages = NULL;
  550. static RRDDIM *rd_descriptors = NULL;
  551. static RRDDIM *rd_populated = NULL;
  552. static RRDDIM *rd_dirty = NULL;
  553. static RRDDIM *rd_backfills = NULL;
  554. static RRDDIM *rd_evictions = NULL;
  555. static RRDDIM *rd_used_by_collectors = NULL;
  556. if (unlikely(!st_pg_cache_pages)) {
  557. st_pg_cache_pages = rrdset_create_localhost(
  558. "netdata"
  559. , "page_cache_stats"
  560. , NULL
  561. , "dbengine"
  562. , NULL
  563. , "NetData dbengine page cache statistics"
  564. , "pages"
  565. , "netdata"
  566. , "stats"
  567. , 130504
  568. , localhost->rrd_update_every
  569. , RRDSET_TYPE_LINE
  570. );
  571. rd_descriptors = rrddim_add(st_pg_cache_pages, "descriptors", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
  572. rd_populated = rrddim_add(st_pg_cache_pages, "populated", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
  573. rd_dirty = rrddim_add(st_pg_cache_pages, "dirty", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
  574. rd_backfills = rrddim_add(st_pg_cache_pages, "backfills", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
  575. rd_evictions = rrddim_add(st_pg_cache_pages, "evictions", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
  576. rd_used_by_collectors = rrddim_add(st_pg_cache_pages, "used_by_collectors", NULL, 1, 1,
  577. RRD_ALGORITHM_ABSOLUTE);
  578. }
  579. else
  580. rrdset_next(st_pg_cache_pages);
  581. rrddim_set_by_pointer(st_pg_cache_pages, rd_descriptors, (collected_number)stats_array[27]);
  582. rrddim_set_by_pointer(st_pg_cache_pages, rd_populated, (collected_number)stats_array[3]);
  583. rrddim_set_by_pointer(st_pg_cache_pages, rd_dirty, (collected_number)stats_array[0] + stats_array[4]);
  584. rrddim_set_by_pointer(st_pg_cache_pages, rd_backfills, (collected_number)stats_array[9]);
  585. rrddim_set_by_pointer(st_pg_cache_pages, rd_evictions, (collected_number)stats_array[10]);
  586. rrddim_set_by_pointer(st_pg_cache_pages, rd_used_by_collectors, (collected_number)stats_array[0]);
  587. rrdset_done(st_pg_cache_pages);
  588. }
  589. // ----------------------------------------------------------------
  590. {
  591. static RRDSET *st_long_term_pages = NULL;
  592. static RRDDIM *rd_total = NULL;
  593. static RRDDIM *rd_insertions = NULL;
  594. static RRDDIM *rd_deletions = NULL;
  595. static RRDDIM *rd_flushing_pressure_deletions = NULL;
  596. if (unlikely(!st_long_term_pages)) {
  597. st_long_term_pages = rrdset_create_localhost(
  598. "netdata"
  599. , "dbengine_long_term_page_stats"
  600. , NULL
  601. , "dbengine"
  602. , NULL
  603. , "NetData dbengine long-term page statistics"
  604. , "pages"
  605. , "netdata"
  606. , "stats"
  607. , 130505
  608. , localhost->rrd_update_every
  609. , RRDSET_TYPE_LINE
  610. );
  611. rd_total = rrddim_add(st_long_term_pages, "total", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
  612. rd_insertions = rrddim_add(st_long_term_pages, "insertions", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
  613. rd_deletions = rrddim_add(st_long_term_pages, "deletions", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
  614. rd_flushing_pressure_deletions = rrddim_add(st_long_term_pages, "flushing_pressure_deletions", NULL, -1,
  615. 1, RRD_ALGORITHM_INCREMENTAL);
  616. }
  617. else
  618. rrdset_next(st_long_term_pages);
  619. rrddim_set_by_pointer(st_long_term_pages, rd_total, (collected_number)stats_array[2]);
  620. rrddim_set_by_pointer(st_long_term_pages, rd_insertions, (collected_number)stats_array[5]);
  621. rrddim_set_by_pointer(st_long_term_pages, rd_deletions, (collected_number)stats_array[6]);
  622. rrddim_set_by_pointer(st_long_term_pages, rd_flushing_pressure_deletions,
  623. (collected_number)stats_array[36]);
  624. rrdset_done(st_long_term_pages);
  625. }
  626. // ----------------------------------------------------------------
  627. {
  628. static RRDSET *st_io_stats = NULL;
  629. static RRDDIM *rd_reads = NULL;
  630. static RRDDIM *rd_writes = NULL;
  631. if (unlikely(!st_io_stats)) {
  632. st_io_stats = rrdset_create_localhost(
  633. "netdata"
  634. , "dbengine_io_throughput"
  635. , NULL
  636. , "dbengine"
  637. , NULL
  638. , "NetData DB engine I/O throughput"
  639. , "MiB/s"
  640. , "netdata"
  641. , "stats"
  642. , 130506
  643. , localhost->rrd_update_every
  644. , RRDSET_TYPE_LINE
  645. );
  646. rd_reads = rrddim_add(st_io_stats, "reads", NULL, 1, 1024 * 1024, RRD_ALGORITHM_INCREMENTAL);
  647. rd_writes = rrddim_add(st_io_stats, "writes", NULL, -1, 1024 * 1024, RRD_ALGORITHM_INCREMENTAL);
  648. }
  649. else
  650. rrdset_next(st_io_stats);
  651. rrddim_set_by_pointer(st_io_stats, rd_reads, (collected_number)stats_array[17]);
  652. rrddim_set_by_pointer(st_io_stats, rd_writes, (collected_number)stats_array[15]);
  653. rrdset_done(st_io_stats);
  654. }
  655. // ----------------------------------------------------------------
  656. {
  657. static RRDSET *st_io_stats = NULL;
  658. static RRDDIM *rd_reads = NULL;
  659. static RRDDIM *rd_writes = NULL;
  660. if (unlikely(!st_io_stats)) {
  661. st_io_stats = rrdset_create_localhost(
  662. "netdata"
  663. , "dbengine_io_operations"
  664. , NULL
  665. , "dbengine"
  666. , NULL
  667. , "NetData DB engine I/O operations"
  668. , "operations/s"
  669. , "netdata"
  670. , "stats"
  671. , 130507
  672. , localhost->rrd_update_every
  673. , RRDSET_TYPE_LINE
  674. );
  675. rd_reads = rrddim_add(st_io_stats, "reads", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
  676. rd_writes = rrddim_add(st_io_stats, "writes", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
  677. }
  678. else
  679. rrdset_next(st_io_stats);
  680. rrddim_set_by_pointer(st_io_stats, rd_reads, (collected_number)stats_array[18]);
  681. rrddim_set_by_pointer(st_io_stats, rd_writes, (collected_number)stats_array[16]);
  682. rrdset_done(st_io_stats);
  683. }
  684. // ----------------------------------------------------------------
  685. {
  686. static RRDSET *st_errors = NULL;
  687. static RRDDIM *rd_fs_errors = NULL;
  688. static RRDDIM *rd_io_errors = NULL;
  689. static RRDDIM *pg_cache_over_half_dirty_events = NULL;
  690. if (unlikely(!st_errors)) {
  691. st_errors = rrdset_create_localhost(
  692. "netdata"
  693. , "dbengine_global_errors"
  694. , NULL
  695. , "dbengine"
  696. , NULL
  697. , "NetData DB engine errors"
  698. , "errors/s"
  699. , "netdata"
  700. , "stats"
  701. , 130508
  702. , localhost->rrd_update_every
  703. , RRDSET_TYPE_LINE
  704. );
  705. rd_io_errors = rrddim_add(st_errors, "io_errors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
  706. rd_fs_errors = rrddim_add(st_errors, "fs_errors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
  707. pg_cache_over_half_dirty_events = rrddim_add(st_errors, "pg_cache_over_half_dirty_events", NULL, 1, 1,
  708. RRD_ALGORITHM_INCREMENTAL);
  709. }
  710. else
  711. rrdset_next(st_errors);
  712. rrddim_set_by_pointer(st_errors, rd_io_errors, (collected_number)stats_array[30]);
  713. rrddim_set_by_pointer(st_errors, rd_fs_errors, (collected_number)stats_array[31]);
  714. rrddim_set_by_pointer(st_errors, pg_cache_over_half_dirty_events, (collected_number)stats_array[34]);
  715. rrdset_done(st_errors);
  716. }
  717. // ----------------------------------------------------------------
  718. {
  719. static RRDSET *st_fd = NULL;
  720. static RRDDIM *rd_fd_current = NULL;
  721. static RRDDIM *rd_fd_max = NULL;
  722. if (unlikely(!st_fd)) {
  723. st_fd = rrdset_create_localhost(
  724. "netdata"
  725. , "dbengine_global_file_descriptors"
  726. , NULL
  727. , "dbengine"
  728. , NULL
  729. , "NetData DB engine File Descriptors"
  730. , "descriptors"
  731. , "netdata"
  732. , "stats"
  733. , 130509
  734. , localhost->rrd_update_every
  735. , RRDSET_TYPE_LINE
  736. );
  737. rd_fd_current = rrddim_add(st_fd, "current", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
  738. rd_fd_max = rrddim_add(st_fd, "max", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
  739. }
  740. else
  741. rrdset_next(st_fd);
  742. rrddim_set_by_pointer(st_fd, rd_fd_current, (collected_number)stats_array[32]);
  743. /* Careful here, modify this accordingly if the File-Descriptor budget ever changes */
  744. rrddim_set_by_pointer(st_fd, rd_fd_max, (collected_number)rlimit_nofile.rlim_cur / 4);
  745. rrdset_done(st_fd);
  746. }
  747. // ----------------------------------------------------------------
  748. {
  749. static RRDSET *st_ram_usage = NULL;
  750. static RRDDIM *rd_cached = NULL;
  751. static RRDDIM *rd_pinned = NULL;
  752. static RRDDIM *rd_metadata = NULL;
  753. collected_number cached_pages, pinned_pages, API_producers, populated_pages, metadata, pages_on_disk,
  754. page_cache_descriptors;
  755. if (unlikely(!st_ram_usage)) {
  756. st_ram_usage = rrdset_create_localhost(
  757. "netdata"
  758. , "dbengine_ram"
  759. , NULL
  760. , "dbengine"
  761. , NULL
  762. , "NetData DB engine RAM usage"
  763. , "MiB"
  764. , "netdata"
  765. , "stats"
  766. , 130510
  767. , localhost->rrd_update_every
  768. , RRDSET_TYPE_STACKED
  769. );
  770. rd_cached = rrddim_add(st_ram_usage, "cache", NULL, 1, 256, RRD_ALGORITHM_ABSOLUTE);
  771. rd_pinned = rrddim_add(st_ram_usage, "collectors", NULL, 1, 256, RRD_ALGORITHM_ABSOLUTE);
  772. rd_metadata = rrddim_add(st_ram_usage, "metadata", NULL, 1, 1048576, RRD_ALGORITHM_ABSOLUTE);
  773. }
  774. else
  775. rrdset_next(st_ram_usage);
  776. API_producers = (collected_number)stats_array[0];
  777. pages_on_disk = (collected_number)stats_array[2];
  778. populated_pages = (collected_number)stats_array[3];
  779. page_cache_descriptors = (collected_number)stats_array[27];
  780. if (API_producers * 2 > populated_pages) {
  781. pinned_pages = API_producers;
  782. } else{
  783. pinned_pages = API_producers * 2;
  784. }
  785. cached_pages = populated_pages - pinned_pages;
  786. metadata = page_cache_descriptors * sizeof(struct page_cache_descr);
  787. metadata += pages_on_disk * sizeof(struct rrdeng_page_descr);
  788. /* This is an empirical estimation for Judy array indexing and extent structures */
  789. metadata += pages_on_disk * 58;
  790. rrddim_set_by_pointer(st_ram_usage, rd_cached, cached_pages);
  791. rrddim_set_by_pointer(st_ram_usage, rd_pinned, pinned_pages);
  792. rrddim_set_by_pointer(st_ram_usage, rd_metadata, metadata);
  793. rrdset_done(st_ram_usage);
  794. }
  795. }
  796. #endif
  797. }