master
c 550 lines 22.3 KB
Raw
1 // SPDX-License-Identifier: GPL-3.0-or-later
2
3 #define PULSE_INTERNALS 1
4 #include "pulse-network.h"
5
6 #define PULSE_NETWORK_CHART_TITLE "Netdata Network Traffic"
7 #define PULSE_NETWORK_CHART_FAMILY "Network Traffic"
8 #define PULSE_NETWORK_CHART_CONTEXT "netdata.network"
9 #define PULSE_NETWORK_CHART_UNITS "kilobits/s"
10 #define PULSE_NETWORK_CHART_PRIORITY 130150
11
12 static struct network_statistics {
13 bool extended;
14 PAD64(uint64_t) api_bytes_received;
15 PAD64(uint64_t) api_bytes_sent;
16 PAD64(uint64_t) statsd_bytes_received;
17 PAD64(uint64_t) statsd_bytes_sent;
18 PAD64(uint64_t) stream_bytes_received;
19 PAD64(uint64_t) stream_bytes_sent;
20 } live_stats = { 0 };
21
22 // --------------------------------------------------------------------------------------------------------------------
23 // aclk time heatmap
24 // a similar history exists in dbengine cache.c
25
26 struct aclk_histogram_entry {
27 usec_t upto;
28 size_t count;
29 };
30
31 #define ACLK_TIME_HISTOGRAM_ENTRIES 19
32
33 static struct aclk_time_histogram {
34 struct aclk_histogram_entry array[ACLK_TIME_HISTOGRAM_ENTRIES];
35 } aclk_time_heatmap;
36
37 void aclk_time_histogram_init(void) {
38 struct aclk_time_histogram *h = &aclk_time_heatmap;
39
40 // the histogram MUST be all-inclusive for the possible sizes,
41 // so we start from 0, and the last value is UINT64_MAX.
42
43 usec_t values[ACLK_TIME_HISTOGRAM_ENTRIES] = {
44 // minimum
45 0,
46
47 // ms
48 10 * USEC_PER_MS,
49 50 * USEC_PER_MS, 100 * USEC_PER_MS, 200 * USEC_PER_MS, 350 * USEC_PER_MS,
50 500 * USEC_PER_MS, 750 * USEC_PER_MS,
51
52 // seconds
53 1 * USEC_PER_SEC, 2 * USEC_PER_SEC, 4 * USEC_PER_SEC, 8 * USEC_PER_SEC,
54 15 * USEC_PER_SEC, 30 * USEC_PER_SEC, 45 * USEC_PER_SEC,
55
56 // minutes
57 60 * USEC_PER_SEC, 120 * USEC_PER_SEC, 180 * USEC_PER_SEC,
58
59 // maximum
60 UINT64_MAX
61 };
62
63 usec_t last_value = 0;
64 for(size_t i = 0; i < ACLK_TIME_HISTOGRAM_ENTRIES; i++) {
65 if(i > 0 && values[i] == 0)
66 fatal("only the first value in the array can be zero");
67
68 if(i > 0 && values[i] <= last_value)
69 fatal("the values need to be sorted");
70
71 h->array[i].upto = values[i];
72 last_value = values[i];
73 }
74 }
75
76 static inline size_t aclk_time_histogram_slot(struct aclk_time_histogram *h, usec_t dt_ut) {
77 if(dt_ut <= h->array[0].upto)
78 return 0;
79
80 if(dt_ut >= h->array[_countof(h->array) - 1].upto)
81 return _countof(h->array) - 1;
82
83 // binary search for the right size
84 size_t low = 0, high = _countof(h->array) - 1;
85 while (low < high) {
86 size_t mid = low + (high - low) / 2;
87 if (dt_ut < h->array[mid].upto)
88 high = mid;
89 else
90 low = mid + 1;
91 }
92 return low - 1;
93 }
94
95 // Per-iteration PUBACK latency accumulators (microseconds)
96 static uint64_t aclk_ack_count = 0;
97 static uint64_t aclk_ack_sum_us = 0;
98 static uint64_t aclk_ack_min_us = UINT64_MAX;
99 static uint64_t aclk_ack_max_us = 0;
100
101 void pulse_aclk_sent_message_acked(usec_t publish_latency, size_t len __maybe_unused) {
102 if(!publish_latency) return;
103
104 // usec_t usec = now_monotonic_usec() - publish_latency;
105
106 size_t slot = aclk_time_histogram_slot(&aclk_time_heatmap, publish_latency);
107 internal_fatal(slot >= _countof(aclk_time_heatmap.array), "hey!");
108
109 __atomic_add_fetch(&aclk_time_heatmap.array[slot].count, 1, __ATOMIC_RELAXED);
110
111 // Track per-iteration min/avg/max in microseconds using atomics
112 __atomic_add_fetch(&aclk_ack_count, 1, __ATOMIC_RELAXED);
113 __atomic_add_fetch(&aclk_ack_sum_us, (uint64_t)publish_latency, __ATOMIC_RELAXED);
114
115 // atomic min update
116 uint64_t cur_min = __atomic_load_n(&aclk_ack_min_us, __ATOMIC_RELAXED);
117 while (publish_latency < cur_min &&
118 !__atomic_compare_exchange_n(&aclk_ack_min_us, &cur_min, (uint64_t)publish_latency, true, __ATOMIC_RELAXED, __ATOMIC_RELAXED)) {
119 ;
120 }
121 // atomic max update
122 uint64_t cur_max = __atomic_load_n(&aclk_ack_max_us, __ATOMIC_RELAXED);
123 while (publish_latency > cur_max &&
124 !__atomic_compare_exchange_n(&aclk_ack_max_us, &cur_max, (uint64_t)publish_latency, true, __ATOMIC_RELAXED, __ATOMIC_RELAXED)) {
125 ;
126 }
127 }
128
129 static void pulse_aclk_time_heatmap(void) {
130 static RRDSET *st;
131 static RRDDIM *rds[ACLK_TIME_HISTOGRAM_ENTRIES];
132
133 if(!st) {
134 st = rrdset_create_localhost(
135 "netdata",
136 "aclk_puback_latency",
137 NULL,
138 PULSE_NETWORK_CHART_FAMILY,
139 "netdata.aclk_puback_latency",
140 "Netdata ACLK PubACK Latency In Seconds",
141 "messages",
142 "netdata",
143 "pulse",
144 PULSE_NETWORK_CHART_PRIORITY + 1,
145 localhost->rrd_update_every,
146 RRDSET_TYPE_HEATMAP);
147
148 rds[0] = rrddim_add(st, "instant", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
149 for(size_t i = 1; i < _countof(rds) - 1 ;i++) {
150 char buf[350];
151 snprintf(buf, sizeof(buf), "%.2fs", (double)aclk_time_heatmap.array[i].upto / (double)USEC_PER_SEC);
152 // duration_snprintf(buf, sizeof(buf), aclk_time_heatmap.array[i].upto, "us", false);
153 rds[i] = rrddim_add(st, buf, NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
154 }
155 rds[_countof(rds) - 1] = rrddim_add(st, "+inf", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
156 }
157
158 for(size_t i = 0; i < _countof(rds) - 1 ;i++) {
159 size_t old_value = 0, new_value = 0;
160 __atomic_exchange(&aclk_time_heatmap.array[i].count, &new_value, &old_value, __ATOMIC_RELAXED);
161 rrddim_set_by_pointer(st, rds[i], (collected_number)old_value);
162 }
163
164 rrdset_done(st);
165 }
166
167 // --------------------------------------------------------------------------------------------------------------------
168
169 void pulse_web_server_received_bytes(size_t bytes) {
170 __atomic_add_fetch(&live_stats.api_bytes_received, bytes, __ATOMIC_RELAXED);
171 }
172
173 void pulse_web_server_sent_bytes(size_t bytes) {
174 __atomic_add_fetch(&live_stats.api_bytes_sent, bytes, __ATOMIC_RELAXED);
175 }
176
177 void pulse_statsd_received_bytes(size_t bytes) {
178 __atomic_add_fetch(&live_stats.statsd_bytes_received, bytes, __ATOMIC_RELAXED);
179 }
180
181 void pulse_statsd_sent_bytes(size_t bytes) {
182 __atomic_add_fetch(&live_stats.statsd_bytes_sent, bytes, __ATOMIC_RELAXED);
183 }
184
185 void pulse_stream_received_bytes(size_t bytes) {
186 __atomic_add_fetch(&live_stats.stream_bytes_received, bytes, __ATOMIC_RELAXED);
187 }
188
189 void pulse_stream_sent_bytes(size_t bytes) {
190 __atomic_add_fetch(&live_stats.stream_bytes_sent, bytes, __ATOMIC_RELAXED);
191 }
192
193 static inline void pulse_network_copy(struct network_statistics *gs) {
194 gs->api_bytes_received = __atomic_load_n(&live_stats.api_bytes_received, __ATOMIC_RELAXED);
195 gs->api_bytes_sent = __atomic_load_n(&live_stats.api_bytes_sent, __ATOMIC_RELAXED);
196
197 gs->statsd_bytes_received = __atomic_load_n(&live_stats.statsd_bytes_received, __ATOMIC_RELAXED);
198 gs->statsd_bytes_sent = __atomic_load_n(&live_stats.statsd_bytes_sent, __ATOMIC_RELAXED);
199
200 gs->stream_bytes_received = __atomic_load_n(&live_stats.stream_bytes_received, __ATOMIC_RELAXED);
201 gs->stream_bytes_sent = __atomic_load_n(&live_stats.stream_bytes_sent, __ATOMIC_RELAXED);
202 }
203
204 void pulse_network_do(bool extended __maybe_unused) {
205 static struct network_statistics gs;
206 pulse_network_copy(&gs);
207
208 if(gs.api_bytes_received || gs.api_bytes_sent) {
209 static RRDSET *st_bytes = NULL;
210 static RRDDIM *rd_in = NULL,
211 *rd_out = NULL;
212
213 if (unlikely(!st_bytes)) {
214 st_bytes = rrdset_create_localhost(
215 "netdata"
216 , "network_api"
217 , NULL
218 , PULSE_NETWORK_CHART_FAMILY
219 , PULSE_NETWORK_CHART_CONTEXT
220 , PULSE_NETWORK_CHART_TITLE
221 , PULSE_NETWORK_CHART_UNITS
222 , "netdata"
223 , "pulse"
224 , PULSE_NETWORK_CHART_PRIORITY
225 , localhost->rrd_update_every
226 , RRDSET_TYPE_AREA
227 );
228
229 rrdlabels_add(st_bytes->rrdlabels, "endpoint", "web-server", RRDLABEL_SRC_AUTO);
230
231 rd_in = rrddim_add(st_bytes, "in", NULL, 8, BITS_IN_A_KILOBIT, RRD_ALGORITHM_INCREMENTAL);
232 rd_out = rrddim_add(st_bytes, "out", NULL, -8, BITS_IN_A_KILOBIT, RRD_ALGORITHM_INCREMENTAL);
233 }
234
235 rrddim_set_by_pointer(st_bytes, rd_in, (collected_number) gs.api_bytes_received);
236 rrddim_set_by_pointer(st_bytes, rd_out, (collected_number) gs.api_bytes_sent);
237 rrdset_done(st_bytes);
238 }
239
240 if(gs.statsd_bytes_received || gs.statsd_bytes_sent) {
241 static RRDSET *st_bytes = NULL;
242 static RRDDIM *rd_in = NULL,
243 *rd_out = NULL;
244
245 if (unlikely(!st_bytes)) {
246 st_bytes = rrdset_create_localhost(
247 "netdata"
248 , "network_statsd"
249 , NULL
250 , PULSE_NETWORK_CHART_FAMILY
251 , PULSE_NETWORK_CHART_CONTEXT
252 , PULSE_NETWORK_CHART_TITLE
253 , PULSE_NETWORK_CHART_UNITS
254 , "netdata"
255 , "pulse"
256 , PULSE_NETWORK_CHART_PRIORITY
257 , localhost->rrd_update_every
258 , RRDSET_TYPE_AREA
259 );
260
261 rrdlabels_add(st_bytes->rrdlabels, "endpoint", "statsd", RRDLABEL_SRC_AUTO);
262
263 rd_in = rrddim_add(st_bytes, "in", NULL, 8, BITS_IN_A_KILOBIT, RRD_ALGORITHM_INCREMENTAL);
264 rd_out = rrddim_add(st_bytes, "out", NULL, -8, BITS_IN_A_KILOBIT, RRD_ALGORITHM_INCREMENTAL);
265 }
266
267 rrddim_set_by_pointer(st_bytes, rd_in, (collected_number) gs.statsd_bytes_received);
268 rrddim_set_by_pointer(st_bytes, rd_out, (collected_number) gs.statsd_bytes_sent);
269 rrdset_done(st_bytes);
270 }
271
272 if(gs.stream_bytes_received || gs.stream_bytes_sent) {
273 static RRDSET *st_bytes = NULL;
274 static RRDDIM *rd_in = NULL,
275 *rd_out = NULL;
276
277 if (unlikely(!st_bytes)) {
278 st_bytes = rrdset_create_localhost(
279 "netdata"
280 , "network_streaming"
281 , NULL
282 , PULSE_NETWORK_CHART_FAMILY
283 , PULSE_NETWORK_CHART_CONTEXT
284 , PULSE_NETWORK_CHART_TITLE
285 , PULSE_NETWORK_CHART_UNITS
286 , "netdata"
287 , "pulse"
288 , PULSE_NETWORK_CHART_PRIORITY
289 , localhost->rrd_update_every
290 , RRDSET_TYPE_AREA
291 );
292
293 rrdlabels_add(st_bytes->rrdlabels, "endpoint", "streaming", RRDLABEL_SRC_AUTO);
294
295 rd_in = rrddim_add(st_bytes, "in", NULL, 8, BITS_IN_A_KILOBIT, RRD_ALGORITHM_INCREMENTAL);
296 rd_out = rrddim_add(st_bytes, "out", NULL, -8, BITS_IN_A_KILOBIT, RRD_ALGORITHM_INCREMENTAL);
297 }
298
299 rrddim_set_by_pointer(st_bytes, rd_in, (collected_number) gs.stream_bytes_received);
300 rrddim_set_by_pointer(st_bytes, rd_out, (collected_number) gs.stream_bytes_sent);
301 rrdset_done(st_bytes);
302 }
303
304 if(aclk_online()) {
305 struct mqtt_wss_stats t = aclk_statistics();
306 if (t.bytes_rx || t.bytes_tx) {
307 static RRDSET *st_bytes = NULL;
308 static RRDDIM *rd_in = NULL, *rd_out = NULL;
309
310 if (unlikely(!st_bytes)) {
311 st_bytes = rrdset_create_localhost(
312 "netdata",
313 "network_aclk",
314 NULL,
315 PULSE_NETWORK_CHART_FAMILY,
316 PULSE_NETWORK_CHART_CONTEXT,
317 PULSE_NETWORK_CHART_TITLE,
318 PULSE_NETWORK_CHART_UNITS,
319 "netdata",
320 "pulse",
321 PULSE_NETWORK_CHART_PRIORITY,
322 localhost->rrd_update_every,
323 RRDSET_TYPE_AREA);
324
325 rrdlabels_add(st_bytes->rrdlabels, "endpoint", "aclk", RRDLABEL_SRC_AUTO);
326
327 rd_in = rrddim_add(st_bytes, "in", NULL, 8, BITS_IN_A_KILOBIT, RRD_ALGORITHM_INCREMENTAL);
328 rd_out = rrddim_add(st_bytes, "out", NULL, -8, BITS_IN_A_KILOBIT, RRD_ALGORITHM_INCREMENTAL);
329 }
330
331 rrddim_set_by_pointer(st_bytes, rd_in, (collected_number)t.bytes_rx);
332 rrddim_set_by_pointer(st_bytes, rd_out, (collected_number)t.bytes_tx);
333 rrdset_done(st_bytes);
334 }
335
336 pulse_aclk_time_heatmap();
337
338 if(extended) {
339 static RRDSET *st_aclk_queue_size = NULL;
340 static RRDDIM *rd_messages = NULL;
341 static RRDDIM *rd_puback_wait = NULL;
342
343 if (unlikely(!st_aclk_queue_size)) {
344 st_aclk_queue_size = rrdset_create_localhost(
345 "netdata",
346 "network_aclk_send_queue",
347 NULL,
348 PULSE_NETWORK_CHART_FAMILY,
349 "netdata.network_aclk_send_queue",
350 "Netdata ACLK Send Queue Size",
351 "messages",
352 "netdata",
353 "pulse",
354 PULSE_NETWORK_CHART_PRIORITY + 2,
355 localhost->rrd_update_every,
356 RRDSET_TYPE_AREA);
357
358 rrdlabels_add(st_aclk_queue_size->rrdlabels, "endpoint", "aclk", RRDLABEL_SRC_AUTO);
359
360 rd_messages = rrddim_add(st_aclk_queue_size, "messages", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
361 rd_puback_wait = rrddim_add(st_aclk_queue_size, "puback wait", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
362 }
363
364 rrddim_set_by_pointer(st_aclk_queue_size, rd_messages, (collected_number)t.mqtt.tx_messages_queued);
365 rrddim_set_by_pointer(st_aclk_queue_size, rd_puback_wait, (collected_number)t.mqtt.packets_waiting_puback);
366 rrdset_done(st_aclk_queue_size);
367 }
368
369 if(extended) {
370 static RRDSET *st_aclk_messages = NULL;
371 static RRDDIM *rd_in = NULL, *rd_out = NULL;
372
373 if (unlikely(!st_aclk_messages)) {
374 st_aclk_messages = rrdset_create_localhost(
375 "netdata",
376 "network_aclk_messages",
377 NULL,
378 PULSE_NETWORK_CHART_FAMILY,
379 "netdata.network_aclk_messages",
380 "Netdata ACLK Messages",
381 "messages/s",
382 "netdata",
383 "pulse",
384 PULSE_NETWORK_CHART_PRIORITY + 3,
385 localhost->rrd_update_every,
386 RRDSET_TYPE_AREA);
387
388 rrdlabels_add(st_aclk_messages->rrdlabels, "endpoint", "aclk", RRDLABEL_SRC_AUTO);
389
390 rd_in = rrddim_add(st_aclk_messages, "received", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
391 rd_out = rrddim_add(st_aclk_messages, "queued", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
392 }
393
394 rrddim_set_by_pointer(st_aclk_messages, rd_in, (collected_number)t.mqtt.rx_messages_rcvd);
395 rrddim_set_by_pointer(st_aclk_messages, rd_out, (collected_number)t.mqtt.tx_messages_sent);
396 rrdset_done(st_aclk_messages);
397 }
398
399 if(extended) {
400 // Bytes queued for send
401 static RRDSET *st_aclk_bytes = NULL;
402 static RRDDIM *rd_bytes = NULL;
403 if (unlikely(!st_aclk_bytes)) {
404 st_aclk_bytes = rrdset_create_localhost(
405 "netdata",
406 "network_aclk_send_queue_bytes",
407 NULL,
408 PULSE_NETWORK_CHART_FAMILY,
409 "netdata.network_aclk_send_queue_bytes",
410 "Netdata ACLK Send Queue Bytes",
411 "bytes",
412 "netdata",
413 "pulse",
414 PULSE_NETWORK_CHART_PRIORITY + 2,
415 localhost->rrd_update_every,
416 RRDSET_TYPE_LINE);
417 rrdlabels_add(st_aclk_bytes->rrdlabels, "endpoint", "aclk", RRDLABEL_SRC_AUTO);
418 rd_bytes = rrddim_add(st_aclk_bytes, "bytes", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
419 }
420 rrddim_set_by_pointer(st_aclk_bytes, rd_bytes, (collected_number)t.mqtt.tx_bytes_queued);
421 rrdset_done(st_aclk_bytes);
422 }
423
424 if(extended) {
425 // Max wait times for PUBACK and send queue (convert us->s via divisor)
426 static RRDSET *st_aclk_puback_wait = NULL;
427 static RRDDIM *rd_puback_max = NULL;
428 if (unlikely(!st_aclk_puback_wait)) {
429 st_aclk_puback_wait = rrdset_create_localhost(
430 "netdata",
431 "network_aclk_puback_wait",
432 NULL,
433 PULSE_NETWORK_CHART_FAMILY,
434 "netdata.network_aclk_puback_wait",
435 "Netdata ACLK PUBACK Max Wait",
436 "seconds",
437 "netdata",
438 "pulse",
439 PULSE_NETWORK_CHART_PRIORITY + 3,
440 localhost->rrd_update_every,
441 RRDSET_TYPE_LINE);
442 rrdlabels_add(st_aclk_puback_wait->rrdlabels, "endpoint", "aclk", RRDLABEL_SRC_AUTO);
443 rd_puback_max = rrddim_add(st_aclk_puback_wait, "max", NULL, 1, USEC_PER_SEC, RRD_ALGORITHM_ABSOLUTE);
444 }
445 rrddim_set_by_pointer(st_aclk_puback_wait, rd_puback_max, (collected_number)t.mqtt.max_puback_wait_us);
446 rrdset_done(st_aclk_puback_wait);
447 }
448
449 if(extended) {
450 static RRDSET *st_aclk_send_wait = NULL;
451 static RRDDIM *rd_overall = NULL, *rd_unsent = NULL, *rd_partial = NULL;
452 if (unlikely(!st_aclk_send_wait)) {
453 st_aclk_send_wait = rrdset_create_localhost(
454 "netdata",
455 "network_aclk_send_queue_wait",
456 NULL,
457 PULSE_NETWORK_CHART_FAMILY,
458 "netdata.network_aclk_send_queue_wait",
459 "Netdata ACLK Send Queue Wait (Overall/Unsent/Partial)",
460 "seconds",
461 "netdata",
462 "pulse",
463 PULSE_NETWORK_CHART_PRIORITY + 3,
464 localhost->rrd_update_every,
465 RRDSET_TYPE_LINE);
466 rrdlabels_add(st_aclk_send_wait->rrdlabels, "endpoint", "aclk", RRDLABEL_SRC_AUTO);
467 rd_overall = rrddim_add(st_aclk_send_wait, "overall", NULL, 1, USEC_PER_SEC, RRD_ALGORITHM_ABSOLUTE);
468 rd_unsent = rrddim_add(st_aclk_send_wait, "unsent", NULL, 1, USEC_PER_SEC, RRD_ALGORITHM_ABSOLUTE);
469 rd_partial = rrddim_add(st_aclk_send_wait, "partial", NULL, 1, USEC_PER_SEC, RRD_ALGORITHM_ABSOLUTE);
470 }
471 rrddim_set_by_pointer(st_aclk_send_wait, rd_overall, (collected_number)t.mqtt.max_send_queue_wait_us);
472 rrddim_set_by_pointer(st_aclk_send_wait, rd_unsent, (collected_number)t.mqtt.max_unsent_wait_us);
473 rrddim_set_by_pointer(st_aclk_send_wait, rd_partial, (collected_number)t.mqtt.max_partial_wait_us);
474 rrdset_done(st_aclk_send_wait);
475 }
476
477 // Publish PUBACK latency min/avg/max per iteration
478 {
479 static RRDSET *st_stats = NULL;
480 static RRDDIM *rd_min = NULL, *rd_avg = NULL, *rd_max = NULL;
481
482 // pull and reset accumulators
483 uint64_t count = __atomic_exchange_n(&aclk_ack_count, 0, __ATOMIC_RELAXED);
484 uint64_t sum_us = __atomic_exchange_n(&aclk_ack_sum_us, 0, __ATOMIC_RELAXED);
485 uint64_t min_us = __atomic_exchange_n(&aclk_ack_min_us, UINT64_MAX, __ATOMIC_RELAXED);
486 uint64_t max_us = __atomic_exchange_n(&aclk_ack_max_us, 0, __ATOMIC_RELAXED);
487
488 uint64_t avg_us = (count ? (sum_us / count) : 0);
489 if (min_us == UINT64_MAX) min_us = 0;
490
491 if (unlikely(!st_stats)) {
492 st_stats = rrdset_create_localhost(
493 "netdata",
494 "aclk_puback_latency_stats",
495 NULL,
496 PULSE_NETWORK_CHART_FAMILY,
497 "netdata.aclk_puback_latency_stats",
498 "Netdata ACLK PubACK Latency (Min/Avg/Max)",
499 "milliseconds",
500 "netdata",
501 "pulse",
502 PULSE_NETWORK_CHART_PRIORITY + 4,
503 localhost->rrd_update_every,
504 RRDSET_TYPE_LINE);
505 rd_min = rrddim_add(st_stats, "min", NULL, 1, USEC_PER_MS, RRD_ALGORITHM_ABSOLUTE);
506 rd_avg = rrddim_add(st_stats, "avg", NULL, 1, USEC_PER_MS, RRD_ALGORITHM_ABSOLUTE);
507 rd_max = rrddim_add(st_stats, "max", NULL, 1, USEC_PER_MS, RRD_ALGORITHM_ABSOLUTE);
508 }
509
510 rrddim_set_by_pointer(st_stats, rd_min, (collected_number)min_us);
511 rrddim_set_by_pointer(st_stats, rd_avg, (collected_number)avg_us);
512 rrddim_set_by_pointer(st_stats, rd_max, (collected_number)max_us);
513 rrdset_done(st_stats);
514 }
515
516 if(extended) {
517 static RRDSET *st_aclk_buffer = NULL;
518 static RRDDIM *rd_aclk_buffer_used = NULL;
519 static RRDDIM *rd_aclk_buffer_free = NULL;
520 static RRDDIM *rd_aclk_buffer_size = NULL;
521
522 if (unlikely(!st_aclk_buffer)) {
523 st_aclk_buffer = rrdset_create_localhost(
524 "netdata",
525 "network_aclk_buffer_usage",
526 NULL,
527 PULSE_NETWORK_CHART_FAMILY,
528 "netdata.network_aclk_buffer_usage",
529 "Netdata ACLK Buffer Usage",
530 "bytes",
531 "netdata",
532 "pulse",
533 PULSE_NETWORK_CHART_PRIORITY + 5,
534 localhost->rrd_update_every,
535 RRDSET_TYPE_AREA);
536
537 rrdlabels_add(st_aclk_buffer->rrdlabels, "endpoint", "aclk", RRDLABEL_SRC_AUTO);
538
539 rd_aclk_buffer_used = rrddim_add(st_aclk_buffer, "used", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
540 rd_aclk_buffer_free = rrddim_add(st_aclk_buffer, "free", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
541 rd_aclk_buffer_size = rrddim_add(st_aclk_buffer, "current limit", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
542 }
543
544 rrddim_set_by_pointer(st_aclk_buffer, rd_aclk_buffer_used, (collected_number)t.mqtt.tx_buffer_used);
545 rrddim_set_by_pointer(st_aclk_buffer, rd_aclk_buffer_free, (collected_number)t.mqtt.tx_buffer_free);
546 rrddim_set_by_pointer(st_aclk_buffer, rd_aclk_buffer_size, (collected_number)t.mqtt.tx_buffer_size);
547 rrdset_done(st_aclk_buffer);
548 }
549 }
550 }