@cryptotaxi247 / netdata-1 / commits / 2cbced292

eBPF mdflush (#11681)

* mdflush: initial agent-side collector. * mdflush: fix x-axis name. * mdflush: fix issue where we iteration doesnt occur. * mdflush: update flush prio to match health. health seems to be global just as flush is, so keep them together. * mdflush: vsn bump. * mdflush: add reference to bcc tool. * mdflush: add more docs. * mdflush: change family name to indicate ebpf. * mdflush: remove "count" word in chart. * mdflush: change mdstat prios so flush comes after health.

Uman Shahzad committed Oct 23, 2021 at 21:16 UTC 2cbced292aa58c8b76a286add3bbbcbe273b333f
15 files changed +424 -10
CMakeLists.txt
+2
@@ -496,6 +496,8 @@ set(EBPF_PROCESS_PLUGIN_FILES
496 collectors/ebpf.plugin/ebpf_fd.h
497 collectors/ebpf.plugin/ebpf_hardirq.c
498 collectors/ebpf.plugin/ebpf_hardirq.h
499 + collectors/ebpf.plugin/ebpf_mdflush.c
500 + collectors/ebpf.plugin/ebpf_mdflush.h
501 collectors/ebpf.plugin/ebpf_mount.c
502 collectors/ebpf.plugin/ebpf_mount.h
503 collectors/ebpf.plugin/ebpf_filesystem.c
Makefile.am
+2
@@ -302,6 +302,8 @@ EBPF_PLUGIN_FILES = \
302 collectors/ebpf.plugin/ebpf_filesystem.h \
303 collectors/ebpf.plugin/ebpf_hardirq.c \
304 collectors/ebpf.plugin/ebpf_hardirq.h \
305 + collectors/ebpf.plugin/ebpf_mdflush.c \
306 + collectors/ebpf.plugin/ebpf_mdflush.h \
307 collectors/ebpf.plugin/ebpf_mount.c \
308 collectors/ebpf.plugin/ebpf_mount.h \
309 collectors/ebpf.plugin/ebpf_oomkill.c \
collectors/all.h
+7 -6
@@ -133,12 +133,13 @@
133 // MDSTAT
134
135 #define NETDATA_CHART_PRIO_MDSTAT_HEALTH 2100
136 -#define NETDATA_CHART_PRIO_MDSTAT_NONREDUNDANT 2101
137 -#define NETDATA_CHART_PRIO_MDSTAT_DISKS 2102 // 5 charts per raid
138 -#define NETDATA_CHART_PRIO_MDSTAT_MISMATCH 2103
139 -#define NETDATA_CHART_PRIO_MDSTAT_OPERATION 2104
140 -#define NETDATA_CHART_PRIO_MDSTAT_FINISH 2105
141 -#define NETDATA_CHART_PRIO_MDSTAT_SPEED 2106
136 +#define NETDATA_CHART_PRIO_MDSTAT_FLUSH 2101
137 +#define NETDATA_CHART_PRIO_MDSTAT_NONREDUNDANT 2105
138 +#define NETDATA_CHART_PRIO_MDSTAT_DISKS 2106 // 5 charts per raid
139 +#define NETDATA_CHART_PRIO_MDSTAT_MISMATCH 2107
140 +#define NETDATA_CHART_PRIO_MDSTAT_OPERATION 2108
141 +#define NETDATA_CHART_PRIO_MDSTAT_FINISH 2109
142 +#define NETDATA_CHART_PRIO_MDSTAT_SPEED 2110
143
144 // Filesystem
145 #define NETDATA_CHART_PRIO_FILESYSTEM_VFS_CLEAN 2150
collectors/ebpf.plugin/Makefile.am
+1
@@ -29,6 +29,7 @@ dist_ebpfconfig_DATA = \
29 ebpf.d/fd.conf \
30 ebpf.d/filesystem.conf \
31 ebpf.d/hardirq.conf \
32 + ebpf.d/mdflush.conf \
33 ebpf.d/mount.conf \
34 ebpf.d/network.conf \
35 ebpf.d/oomkill.conf \
collectors/ebpf.plugin/README.md
+16
@@ -116,6 +116,20 @@ This chart monitors calls demonstrating commits from filesystem caches to disk.
116 This chart shows calls to `sync_file_range(2)` which synchronizes file segments with disk. This is the most dangerous
117 syscall to synchronize data according to its manual.
118
119 +### MD flush
120 +
121 +The eBPF plugin shows multi-device flushes happening in real time. This can be
122 +used to explain some spikes happening in
123 +[disk latency](docs/agent/collectors/ebpf.plugin#disk) charts.
124 +
125 +By default, MD flush is disabled. To enable it, configure your
126 +`/etc/netdata/ebpf.d.conf` file as:
127 +
128 +```conf
129 +[global]
130 + mdflush = yes
131 +```
132 +
133 ### Disk
134
135 The eBPF plugin also shows a chart in the Disk section when the `disk` thread is enabled. This will create the
@@ -399,6 +413,8 @@ You can also enable the following eBPF programs:
413 - `disk` : This eBPF program creates charts that show information about disk latency independent of filesystem.
414 - `filesystem` : This eBPF program creates charts that show information about some filesystem latency.
415 - `swap` : This eBPF program creates charts that show information about swap access.
416 +- `mdflush`: This eBPF program creates charts that show information about
417 + multi-device software flushes.
418
419 ## Thread configuration
420
collectors/ebpf.plugin/ebpf.c
+24
@@ -158,6 +158,11 @@ ebpf_module_t ebpf_modules[] = {
158 .apps_routine = ebpf_shm_create_apps_charts, .maps = NULL,
159 .pid_map_size = ND_EBPF_DEFAULT_PID_SIZE, .names = NULL, .cfg = &shm_config,
160 .config_file = NETDATA_DIRECTORY_SHM_CONFIG_FILE},
161 + { .thread_name = "mdflush", .config_name = "mdflush", .enabled = 0, .start_routine = ebpf_mdflush_thread,
162 + .update_every = EBPF_DEFAULT_UPDATE_EVERY, .global_charts = 1, .apps_charts = CONFIG_BOOLEAN_NO,
163 + .cgroup_charts = CONFIG_BOOLEAN_NO, .mode = MODE_ENTRY, .optional = 0, .apps_routine = NULL, .maps = NULL,
164 + .pid_map_size = ND_EBPF_DEFAULT_PID_SIZE, .names = NULL, .cfg = &mdflush_config,
165 + .config_file = NETDATA_DIRECTORY_MDFLUSH_CONFIG_FILE},
166 { .thread_name = NULL, .enabled = 0, .start_routine = NULL, .update_every = EBPF_DEFAULT_UPDATE_EVERY,
167 .global_charts = 0, .apps_charts = CONFIG_BOOLEAN_NO, .cgroup_charts = CONFIG_BOOLEAN_NO,
168 .mode = MODE_ENTRY, .optional = 0, .apps_routine = NULL, .maps = NULL, .pid_map_size = 0, .names = NULL,
@@ -803,6 +808,8 @@ void ebpf_print_help()
808 "\n"
809 " [-]-hardirq Enable chart related to hard IRQ latency.\n"
810 "\n"
811 + " [-]-mdflush Enable charts related to multi-device flush.\n"
812 + "\n"
813 " [-]-mount Enable charts related to mount monitoring.\n"
814 "\n"
815 " [-]-net Enable network viewer charts.\n"
@@ -1259,6 +1266,13 @@ static void read_collector_values(int *disable_apps, int *disable_cgroups, int u
1266 started++;
1267 }
1268
1269 + enabled = appconfig_get_boolean(&collector_config, EBPF_PROGRAMS_SECTION, "mdflush",
1270 + CONFIG_BOOLEAN_NO);
1271 + if (enabled) {
1272 + ebpf_enable_chart(EBPF_MODULE_MDFLUSH_IDX, *disable_apps, *disable_cgroups);
1273 + started++;
1274 + }
1275 +
1276 if (!started){
1277 ebpf_enable_all_charts(*disable_apps, *disable_cgroups);
1278 // Read network viewer section
@@ -1370,6 +1384,7 @@ static void ebpf_parse_args(int argc, char **argv)
1384 {"softirq", no_argument, 0, 0 },
1385 {"oomkill", no_argument, 0, 0 },
1386 {"shm", no_argument, 0, 0 },
1387 + {"mdflush", no_argument, 0, 0 },
1388 /* INSERT NEW THREADS BEFORE THIS COMMENT TO KEEP COMPATIBILITY WITH enum ebpf_module_indexes */
1389 {"all", no_argument, 0, 0 },
1390 {"version", no_argument, 0, 0 },
@@ -1511,6 +1526,13 @@ static void ebpf_parse_args(int argc, char **argv)
1526 select_threads |= 1<<EBPF_MODULE_SHM_IDX;
1527 #ifdef NETDATA_INTERNAL_CHECKS
1528 info("EBPF enabling \"SHM\" chart, because it was started with the option \"[-]-shm\".");
1529 +#endif
1530 + break;
1531 + }
1532 + case EBPF_MODULE_MDFLUSH_IDX: {
1533 + select_threads |= 1<<EBPF_MODULE_MDFLUSH_IDX;
1534 +#ifdef NETDATA_INTERNAL_CHECKS
1535 + info("EBPF enabling \"MDFLUSH\" chart, because it was started with the option \"[-]-mdflush\".");
1536 #endif
1537 break;
1538 }
@@ -1813,6 +1835,8 @@ int main(int argc, char **argv)
1835 NULL, NULL, ebpf_modules[EBPF_MODULE_OOMKILL_IDX].start_routine},
1836 {"EBPF SHM" , NULL, NULL, 1,
1837 NULL, NULL, ebpf_modules[EBPF_MODULE_SHM_IDX].start_routine},
1838 + {"EBPF MDFLUSH" , NULL, NULL, 1,
1839 + NULL, NULL, ebpf_modules[EBPF_MODULE_MDFLUSH_IDX].start_routine},
1840 {NULL , NULL, NULL, 0,
1841 NULL, NULL, NULL}
1842 };
collectors/ebpf.plugin/ebpf.d.conf
+2
@@ -31,6 +31,7 @@
31 # `dcstat` : Make charts for kernel functions related to directory cache.
32 # `disk` : Monitor I/O latencies for disks
33 # `fd` : This eBPF program creates charts that show information about file manipulation.
34 +# `mdflush` : Monitors flush counts for multi-devices.
35 # `mount` : Monitor calls for syscalls mount and umount
36 # `filesystem`: Monitor calls for functions used to manipulate specific filesystems
37 # `hardirq` : Monitor latency of serving hardware interrupt requests (hard IRQs).
@@ -51,6 +52,7 @@
52 fd = yes
53 filesystem = no
54 hardirq = yes
55 + mdflush = no
56 mount = yes
57 oomkill = yes
58 process = yes
collectors/ebpf.plugin/ebpf.d/mdflush.conf new
+7
@@ -0,0 +1,7 @@
1 +# The `ebpf load mode` option accepts the following values :
2 +# `entry` : The eBPF collector only monitors calls for the functions, and does not show charts related to errors.
3 +# `return : In the `return` mode, the eBPF collector monitors the same kernel functions as `entry`, but also creates
4 +# new charts for the return of these functions, such as errors.
5 +#[global]
6 +# ebpf load mode = entry
7 +# update every = 1
collectors/ebpf.plugin/ebpf.h
+1
@@ -90,6 +90,7 @@ enum ebpf_main_index {
90 EBPF_MODULE_SOFTIRQ_IDX,
91 EBPF_MODULE_OOMKILL_IDX,
92 EBPF_MODULE_SHM_IDX,
93 + EBPF_MODULE_MDFLUSH_IDX,
94 /* THREADS MUST BE INCLUDED BEFORE THIS COMMENT */
95 EBPF_OPTION_ALL_CHARTS,
96 EBPF_OPTION_VERSION,
collectors/ebpf.plugin/ebpf_apps.h
+1
@@ -24,6 +24,7 @@
24 #include "ebpf_filesystem.h"
25 #include "ebpf_hardirq.h"
26 #include "ebpf_cachestat.h"
27 +#include "ebpf_mdflush.h"
28 #include "ebpf_mount.h"
29 #include "ebpf_oomkill.h"
30 #include "ebpf_shm.h"
collectors/ebpf.plugin/ebpf_mdflush.c new
+312
@@ -0,0 +1,312 @@
1 +// SPDX-License-Identifier: GPL-3.0-or-later
2 +
3 +#include "ebpf.h"
4 +#include "ebpf_mdflush.h"
5 +
6 +struct config mdflush_config = { .first_section = NULL,
7 + .last_section = NULL,
8 + .mutex = NETDATA_MUTEX_INITIALIZER,
9 + .index = { .avl_tree = { .root = NULL, .compar = appconfig_section_compare },
10 + .rwlock = AVL_LOCK_INITIALIZER } };
11 +
12 +#define MDFLUSH_MAP_COUNT 0
13 +static ebpf_local_maps_t mdflush_maps[] = {
14 + {
15 + .name = "tbl_mdflush",
16 + .internal_input = 1024,
17 + .user_input = 0,
18 + .type = NETDATA_EBPF_MAP_STATIC,
19 + .map_fd = ND_EBPF_MAP_FD_NOT_INITIALIZED
20 + },
21 + /* end */
22 + {
23 + .name = NULL,
24 + .internal_input = 0,
25 + .user_input = 0,
26 + .type = NETDATA_EBPF_MAP_CONTROLLER,
27 + .map_fd = ND_EBPF_MAP_FD_NOT_INITIALIZED
28 + }
29 +};
30 +
31 +// store for "published" data from the reader thread, which the collector
32 +// thread will write to netdata agent.
33 +static avl_tree_lock mdflush_pub;
34 +
35 +// tmp store for mdflush values we get from a per-CPU eBPF map.
36 +static mdflush_ebpf_val_t *mdflush_ebpf_vals = NULL;
37 +
38 +static struct bpf_link **probe_links = NULL;
39 +static struct bpf_object *objects = NULL;
40 +
41 +static int read_thread_closed = 1;
42 +
43 +static struct netdata_static_thread mdflush_threads = {"MDFLUSH KERNEL",
44 + NULL, NULL, 1, NULL,
45 + NULL, NULL };
46 +
47 +/**
48 + * Clean up the main thread.
49 + *
50 + * @param ptr thread data.
51 + */
52 +static void mdflush_cleanup(void *ptr)
53 +{
54 + ebpf_module_t *em = (ebpf_module_t *)ptr;
55 + if (!em->enabled) {
56 + return;
57 + }
58 +
59 + heartbeat_t hb;
60 + heartbeat_init(&hb);
61 + uint32_t tick = 1 * USEC_PER_MS;
62 + while (!read_thread_closed) {
63 + usec_t dt = heartbeat_next(&hb, tick);
64 + UNUSED(dt);
65 + }
66 +
67 + freez(mdflush_ebpf_vals);
68 + freez(mdflush_threads.thread);
69 +
70 + if (probe_links) {
71 + struct bpf_program *prog;
72 + size_t i = 0 ;
73 + bpf_object__for_each_program(prog, objects) {
74 + bpf_link__destroy(probe_links[i]);
75 + i++;
76 + }
77 + bpf_object__close(objects);
78 + }
79 +}
80 +
81 +/**
82 + * Compare mdflush values.
83 + *
84 + * @param a `netdata_mdflush_t *`.
85 + * @param b `netdata_mdflush_t *`.
86 + *
87 + * @return 0 if a==b, 1 if a>b, -1 if a<b.
88 +*/
89 +static int mdflush_val_cmp(void *a, void *b)
90 +{
91 + netdata_mdflush_t *ptr1 = a;
92 + netdata_mdflush_t *ptr2 = b;
93 +
94 + if (ptr1->unit > ptr2->unit) {
95 + return 1;
96 + }
97 + else if (ptr1->unit < ptr2->unit) {
98 + return -1;
99 + }
100 + else {
101 + return 0;
102 + }
103 +}
104 +
105 +static void mdflush_read_count_map()
106 +{
107 + int mapfd = mdflush_maps[MDFLUSH_MAP_COUNT].map_fd;
108 + mdflush_ebpf_key_t curr_key = (uint32_t)-1;
109 + mdflush_ebpf_key_t key = (uint32_t)-1;
110 + netdata_mdflush_t search_v;
111 + netdata_mdflush_t *v = NULL;
112 +
113 + while (bpf_map_get_next_key(mapfd, &curr_key, &key) == 0) {
114 + curr_key = key;
115 +
116 + // get val for this key.
117 + int test = bpf_map_lookup_elem(mapfd, &key, mdflush_ebpf_vals);
118 + if (unlikely(test < 0)) {
119 + continue;
120 + }
121 +
122 + // is this record saved yet?
123 + //
124 + // if not, make a new one, mark it as unsaved for now, and continue; we
125 + // will insert it at the end after all of its values are correctly set,
126 + // so that we can safely publish it to the collector within a single,
127 + // short locked operation.
128 + //
129 + // otherwise simply continue; we will only update the flush count,
130 + // which can be republished safely without a lock.
131 + //
132 + // NOTE: lock isn't strictly necessary for this initial search, as only
133 + // this thread does writing, but the AVL is using a read-write lock so
134 + // there is no congestion.
135 + bool v_is_new = false;
136 + search_v.unit = key;
137 + v = (netdata_mdflush_t *)avl_search_lock(
138 + &mdflush_pub,
139 + (avl_t *)&search_v
140 + );
141 + if (unlikely(v == NULL)) {
142 + // flush count can only be added reliably at a later time.
143 + // when they're added, only then will we AVL insert.
144 + v = callocz(1, sizeof(netdata_mdflush_t));
145 + v->unit = key;
146 + sprintf(v->disk_name, "md%u", key);
147 + v->dim_exists = false;
148 +
149 + v_is_new = true;
150 + }
151 +
152 + // we must add up count value for this record across all CPUs.
153 + uint64_t total_cnt = 0;
154 + int i;
155 + int end = (running_on_kernel < NETDATA_KERNEL_V4_15) ? 1 : ebpf_nprocs;
156 + for (i = 0; i < end; i++) {
157 + total_cnt += mdflush_ebpf_vals[i];
158 + }
159 +
160 + // can now safely publish count for existing records.
161 + v->cnt = total_cnt;
162 +
163 + // can now safely publish new record.
164 + if (v_is_new) {
165 + avl_t *check = avl_insert_lock(&mdflush_pub, (avl_t *)v);
166 + if (check != (avl_t *)v) {
167 + error("Internal error, cannot insert the AVL tree.");
168 + }
169 + }
170 + }
171 +}
172 +
173 +/**
174 + * Read eBPF maps for mdflush.
175 + */
176 +static void *mdflush_reader(void *ptr)
177 +{
178 + read_thread_closed = 0;
179 +
180 + heartbeat_t hb;
181 + heartbeat_init(&hb);
182 +
183 + ebpf_module_t *em = (ebpf_module_t *)ptr;
184 +
185 + usec_t step = NETDATA_MDFLUSH_SLEEP_MS * em->update_every;
186 + while (!close_ebpf_plugin) {
187 + usec_t dt = heartbeat_next(&hb, step);
188 + UNUSED(dt);
189 +
190 + mdflush_read_count_map();
191 + }
192 +
193 + read_thread_closed = 1;
194 + return NULL;
195 +}
196 +
197 +static void mdflush_create_charts(int update_every)
198 +{
199 + ebpf_create_chart(
200 + "mdstat",
201 + "mdstat_flush",
202 + "MD flushes",
203 + "flushes",
204 + "flush (eBPF)",
205 + "md.flush",
206 + NETDATA_EBPF_CHART_TYPE_STACKED,
207 + NETDATA_CHART_PRIO_MDSTAT_FLUSH,
208 + NULL, NULL, 0, update_every,
209 + NETDATA_EBPF_MODULE_NAME_MDFLUSH
210 + );
211 +
212 + fflush(stdout);
213 +}
214 +
215 +// callback for avl tree traversal on `mdflush_pub`.
216 +static int mdflush_write_dims(void *entry, void *data)
217 +{
218 + UNUSED(data);
219 +
220 + netdata_mdflush_t *v = entry;
221 +
222 + // records get dynamically added in, so add the dim if we haven't yet.
223 + if (!v->dim_exists) {
224 + ebpf_write_global_dimension(
225 + v->disk_name, v->disk_name,
226 + ebpf_algorithms[NETDATA_EBPF_INCREMENTAL_IDX]
227 + );
228 + v->dim_exists = true;
229 + }
230 +
231 + write_chart_dimension(v->disk_name, v->cnt);
232 +
233 + return 1;
234 +}
235 +
236 +/**
237 +* Main loop for this collector.
238 +*/
239 +static void mdflush_collector(ebpf_module_t *em)
240 +{
241 + mdflush_ebpf_vals = callocz(ebpf_nprocs, sizeof(mdflush_ebpf_val_t));
242 +
243 + avl_init_lock(&mdflush_pub, mdflush_val_cmp);
244 +
245 + // create reader thread.
246 + mdflush_threads.thread = mallocz(sizeof(netdata_thread_t));
247 + mdflush_threads.start_routine = mdflush_reader;
248 + netdata_thread_create(
249 + mdflush_threads.thread,
250 + mdflush_threads.name,
251 + NETDATA_THREAD_OPTION_JOINABLE,
252 + mdflush_reader,
253 + em
254 + );
255 +
256 + // create chart and static dims.
257 + pthread_mutex_lock(&lock);
258 + mdflush_create_charts(em->update_every);
259 + pthread_mutex_unlock(&lock);
260 +
261 + // loop and read from published data until ebpf plugin is closed.
262 + int update_every = em->update_every;
263 + int counter = update_every - 1;
264 + while (!close_ebpf_plugin) {
265 + pthread_mutex_lock(&collect_data_mutex);
266 + pthread_cond_wait(&collect_data_cond_var, &collect_data_mutex);
267 +
268 + if (++counter == update_every) {
269 + counter = 0;
270 + pthread_mutex_lock(&lock);
271 +
272 + // write dims now for all hitherto discovered devices.
273 + write_begin_chart("mdstat", "mdstat_flush");
274 + avl_traverse_lock(&mdflush_pub, mdflush_write_dims, NULL);
275 + write_end_chart();
276 +
277 + pthread_mutex_unlock(&lock);
278 + }
279 +
280 + pthread_mutex_unlock(&collect_data_mutex);
281 + }
282 +}
283 +
284 +/**
285 + * mdflush thread.
286 + *
287 + * @param ptr a `ebpf_module_t *`.
288 + * @return always NULL.
289 + */
290 +void *ebpf_mdflush_thread(void *ptr)
291 +{
292 + netdata_thread_cleanup_push(mdflush_cleanup, ptr);
293 +
294 + ebpf_module_t *em = (ebpf_module_t *)ptr;
295 + em->maps = mdflush_maps;
296 +
297 + if (!em->enabled) {
298 + goto endmdflush;
299 + }
300 +
301 + probe_links = ebpf_load_program(ebpf_plugin_dir, em, kernel_string, &objects);
302 + if (!probe_links) {
303 + goto endmdflush;
304 + }
305 +
306 + mdflush_collector(em);
307 +
308 +endmdflush:
309 + netdata_thread_cleanup_pop(1);
310 +
311 + return NULL;
312 +}
collectors/ebpf.plugin/ebpf_mdflush.h new
+42
@@ -0,0 +1,42 @@
1 +// SPDX-License-Identifier: GPL-3.0-or-later
2 +
3 +#ifndef NETDATA_EBPF_MDFLUSH_H
4 +#define NETDATA_EBPF_MDFLUSH_H 1
5 +
6 +// Module name
7 +#define NETDATA_EBPF_MODULE_NAME_MDFLUSH "mdflush"
8 +
9 +#define NETDATA_MDFLUSH_SLEEP_MS 850000ULL
10 +
11 +// charts
12 +#define NETDATA_MDFLUSH_GLOBAL_CHART "mdflush"
13 +
14 +// configuration file
15 +#define NETDATA_DIRECTORY_MDFLUSH_CONFIG_FILE "mdflush.conf"
16 +
17 +// copy of mdflush types from kernel-collectors repo.
18 +typedef uint32_t mdflush_ebpf_key_t;
19 +typedef uint64_t mdflush_ebpf_val_t;
20 +
21 +typedef struct netdata_mdflush {
22 + // must be at top for simplified AVL tree usage.
23 + // if it's not at the top, we need to use `containerof` for almost all ops.
24 + avl_t avl;
25 +
26 + // key & name of device.
27 + // the name is generated by the key, usually as `md<unit>`.
28 + uint32_t unit;
29 + char disk_name[32];
30 +
31 + // have we defined the dimension for this device yet?
32 + bool dim_exists;
33 +
34 + // incremental flush count value.
35 + uint64_t cnt;
36 +} netdata_mdflush_t;
37 +
38 +extern void *ebpf_mdflush_thread(void *ptr);
39 +
40 +extern struct config mdflush_config;
41 +
42 +#endif
packaging/ebpf.checksums
+3 -3
@@ -1,3 +1,3 @@
1 -ec330d7529b5d94e705dba88494d4721a59f9f7d8e4cadff59ede8489e1dd5c3 netdata-kernel-collector-glibc-v0.8.3.tar.xz
2 -c6dbf522ae1fc3930701db1567ac6abb9cc944b0d3f7dd5ab2a2edd511816a3f netdata-kernel-collector-musl-v0.8.3.tar.xz
3 -3d29ccd9690253dec8727fe94a2a04f64686a7fd3c93eb4f382445f56dc249c7 netdata-kernel-collector-static-v0.8.3.tar.xz
1 +e5a4e49fcfcb1602aec5c770de773e91918836b24ac7de2d817bc8a6d106dbcf netdata-kernel-collector-glibc-v0.8.4.tar.xz
2 +beb57f51c6c8178e9a16f7e8370c55d0f29f20f1d4e9546a5e097e647192514c netdata-kernel-collector-musl-v0.8.4.tar.xz
3 +9ee4ca483b7575f9e9c74dc61ec0ab7af3abf1a6404f191e0ac092500842b8a7 netdata-kernel-collector-static-v0.8.4.tar.xz
packaging/ebpf.version
+1 -1
@@ -1 +1 @@
1 -v0.8.3
1 +v0.8.4
web/gui/dashboard_info.js
+3
@@ -1606,6 +1606,9 @@ netdataDashboard.context = {
1606 'software issues should never cause such a mismatch. '+
1607 'For details, see <a href="https://man7.org/linux/man-pages/man4/md.4.html" target="_blank">md(4)</a>.'
1608 },
1609 + 'md.flush': {
1610 + info: 'Number of flush counts per MD array. Based on the eBPF <a href="https://github.com/iovisor/bcc/blob/master/tools/mdflush_example.txt" target="_blank">mdflush</a> from BCC tools.'
1611 + },
1612
1613 // ------------------------------------------------------------------------
1614 // IP