ebpf_dcstat.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613
  1. // SPDX-License-Identifier: GPL-3.0-or-later
  2. #include "ebpf.h"
  3. #include "ebpf_dcstat.h"
  4. static char *dcstat_counter_dimension_name[NETDATA_DCSTAT_IDX_END] = { "ratio", "reference", "slow", "miss" };
  5. static netdata_syscall_stat_t dcstat_counter_aggregated_data[NETDATA_DCSTAT_IDX_END];
  6. static netdata_publish_syscall_t dcstat_counter_publish_aggregated[NETDATA_DCSTAT_IDX_END];
  7. static ebpf_data_t dcstat_data;
  8. netdata_dcstat_pid_t *dcstat_vector = NULL;
  9. netdata_publish_dcstat_t **dcstat_pid = NULL;
  10. static struct bpf_link **probe_links = NULL;
  11. static struct bpf_object *objects = NULL;
  12. static int *map_fd = NULL;
  13. static netdata_idx_t dcstat_hash_values[NETDATA_DCSTAT_IDX_END];
  14. static netdata_idx_t *dcstat_values = NULL;
  15. static int read_thread_closed = 1;
  16. struct config dcstat_config = { .first_section = NULL,
  17. .last_section = NULL,
  18. .mutex = NETDATA_MUTEX_INITIALIZER,
  19. .index = { .avl_tree = { .root = NULL, .compar = appconfig_section_compare },
  20. .rwlock = AVL_LOCK_INITIALIZER } };
  21. struct netdata_static_thread dcstat_threads = {"DCSTAT KERNEL",
  22. NULL, NULL, 1, NULL,
  23. NULL, NULL};
  24. static ebpf_local_maps_t dcstat_maps[] = {{.name = "dcstat_pid", .internal_input = ND_EBPF_DEFAULT_PID_SIZE,
  25. .user_input = 0},
  26. {.name = NULL, .internal_input = 0, .user_input = 0}};
  27. static ebpf_specify_name_t dc_optional_name[] = { {.program_name = "netdata_lookup_fast",
  28. .function_to_attach = "lookup_fast",
  29. .optional = NULL,
  30. .retprobe = CONFIG_BOOLEAN_NO},
  31. {.program_name = NULL}};
  32. /*****************************************************************
  33. *
  34. * COMMON FUNCTIONS
  35. *
  36. *****************************************************************/
  37. /**
  38. * Update publish
  39. *
  40. * Update publish values before to write dimension.
  41. *
  42. * @param out strcuture that will receive data.
  43. * @param cache_access number of access to directory cache.
  44. * @param not_found number of files not found on the file system
  45. */
  46. void dcstat_update_publish(netdata_publish_dcstat_t *out, uint64_t cache_access, uint64_t not_found)
  47. {
  48. calculated_number successful_access = (calculated_number) (((long long)cache_access) - ((long long)not_found));
  49. calculated_number ratio = (cache_access) ? successful_access/(calculated_number)cache_access : 0;
  50. out->ratio = (long long )(ratio*100);
  51. }
  52. /*****************************************************************
  53. *
  54. * FUNCTIONS TO CLOSE THE THREAD
  55. *
  56. *****************************************************************/
  57. /**
  58. * Clean PID structures
  59. *
  60. * Clean the allocated structures.
  61. */
  62. void clean_dcstat_pid_structures() {
  63. struct pid_stat *pids = root_of_pids;
  64. while (pids) {
  65. freez(dcstat_pid[pids->pid]);
  66. pids = pids->next;
  67. }
  68. }
  69. /**
  70. * Clean names
  71. *
  72. * Clean the optional names allocated during startup.
  73. */
  74. void ebpf_dcstat_clean_names()
  75. {
  76. size_t i = 0;
  77. while (dc_optional_name[i].program_name) {
  78. freez(dc_optional_name[i].optional);
  79. i++;
  80. }
  81. }
  82. /**
  83. * Clean up the main thread.
  84. *
  85. * @param ptr thread data.
  86. */
  87. static void ebpf_dcstat_cleanup(void *ptr)
  88. {
  89. ebpf_module_t *em = (ebpf_module_t *)ptr;
  90. if (!em->enabled)
  91. return;
  92. heartbeat_t hb;
  93. heartbeat_init(&hb);
  94. uint32_t tick = 2 * USEC_PER_MS;
  95. while (!read_thread_closed) {
  96. usec_t dt = heartbeat_next(&hb, tick);
  97. UNUSED(dt);
  98. }
  99. freez(dcstat_vector);
  100. freez(dcstat_values);
  101. ebpf_cleanup_publish_syscall(dcstat_counter_publish_aggregated);
  102. ebpf_dcstat_clean_names();
  103. if (probe_links) {
  104. struct bpf_program *prog;
  105. size_t i = 0 ;
  106. bpf_object__for_each_program(prog, objects) {
  107. bpf_link__destroy(probe_links[i]);
  108. i++;
  109. }
  110. bpf_object__close(objects);
  111. }
  112. }
  113. /*****************************************************************
  114. *
  115. * APPS
  116. *
  117. *****************************************************************/
  118. /**
  119. * Create apps charts
  120. *
  121. * Call ebpf_create_chart to create the charts on apps submenu.
  122. *
  123. * @param em a pointer to the structure with the default values.
  124. */
  125. void ebpf_dcstat_create_apps_charts(struct ebpf_module *em, void *ptr)
  126. {
  127. UNUSED(em);
  128. struct target *root = ptr;
  129. ebpf_create_charts_on_apps(NETDATA_DC_HIT_CHART,
  130. "Percentage of files listed inside directory cache",
  131. EBPF_COMMON_DIMENSION_PERCENTAGE,
  132. NETDATA_APPS_DCSTAT_GROUP,
  133. NETDATA_EBPF_CHART_TYPE_LINE,
  134. 20100,
  135. ebpf_algorithms[NETDATA_EBPF_ABSOLUTE_IDX],
  136. root);
  137. ebpf_create_charts_on_apps(NETDATA_DC_REFERENCE_CHART,
  138. "Count file access.",
  139. EBPF_COMMON_DIMENSION_FILES,
  140. NETDATA_APPS_DCSTAT_GROUP,
  141. NETDATA_EBPF_CHART_TYPE_STACKED,
  142. 20101,
  143. ebpf_algorithms[NETDATA_EBPF_ABSOLUTE_IDX],
  144. root);
  145. ebpf_create_charts_on_apps(NETDATA_DC_REQUEST_NOT_CACHE_CHART,
  146. "Access to files that were not present inside directory cache.",
  147. EBPF_COMMON_DIMENSION_FILES,
  148. NETDATA_APPS_DCSTAT_GROUP,
  149. NETDATA_EBPF_CHART_TYPE_STACKED,
  150. 20102,
  151. ebpf_algorithms[NETDATA_EBPF_ABSOLUTE_IDX],
  152. root);
  153. ebpf_create_charts_on_apps(NETDATA_DC_REQUEST_NOT_FOUND_CHART,
  154. "Number of requests for files that were not found on filesystem.",
  155. EBPF_COMMON_DIMENSION_FILES,
  156. NETDATA_APPS_DCSTAT_GROUP,
  157. NETDATA_EBPF_CHART_TYPE_STACKED,
  158. 20103,
  159. ebpf_algorithms[NETDATA_EBPF_ABSOLUTE_IDX],
  160. root);
  161. }
  162. /*****************************************************************
  163. *
  164. * MAIN LOOP
  165. *
  166. *****************************************************************/
  167. /**
  168. * Apps Accumulator
  169. *
  170. * Sum all values read from kernel and store in the first address.
  171. *
  172. * @param out the vector with read values.
  173. */
  174. static void dcstat_apps_accumulator(netdata_dcstat_pid_t *out)
  175. {
  176. int i, end = (running_on_kernel >= NETDATA_KERNEL_V4_15) ? ebpf_nprocs : 1;
  177. netdata_dcstat_pid_t *total = &out[0];
  178. for (i = 1; i < end; i++) {
  179. netdata_dcstat_pid_t *w = &out[i];
  180. total->cache_access += w->cache_access;
  181. total->file_system += w->file_system;
  182. total->not_found += w->not_found;
  183. }
  184. }
  185. /**
  186. * Save PID values
  187. *
  188. * Save the current values inside the structure
  189. *
  190. * @param out vector used to plot charts
  191. * @param publish vector with values read from hash tables.
  192. */
  193. static inline void dcstat_save_pid_values(netdata_publish_dcstat_t *out, netdata_dcstat_pid_t *publish)
  194. {
  195. memcpy(&out->curr, &publish[0], sizeof(netdata_dcstat_pid_t));
  196. }
  197. /**
  198. * Fill PID
  199. *
  200. * Fill PID structures
  201. *
  202. * @param current_pid pid that we are collecting data
  203. * @param out values read from hash tables;
  204. */
  205. static void dcstat_fill_pid(uint32_t current_pid, netdata_dcstat_pid_t *publish)
  206. {
  207. netdata_publish_dcstat_t *curr = dcstat_pid[current_pid];
  208. if (!curr) {
  209. curr = callocz(1, sizeof(netdata_publish_dcstat_t));
  210. dcstat_pid[current_pid] = curr;
  211. }
  212. dcstat_save_pid_values(curr, publish);
  213. }
  214. /**
  215. * Read APPS table
  216. *
  217. * Read the apps table and store data inside the structure.
  218. */
  219. static void read_apps_table()
  220. {
  221. netdata_dcstat_pid_t *cv = dcstat_vector;
  222. uint32_t key;
  223. struct pid_stat *pids = root_of_pids;
  224. int fd = map_fd[NETDATA_DCSTAT_PID_STATS];
  225. size_t length = sizeof(netdata_dcstat_pid_t)*ebpf_nprocs;
  226. while (pids) {
  227. key = pids->pid;
  228. if (bpf_map_lookup_elem(fd, &key, cv)) {
  229. pids = pids->next;
  230. continue;
  231. }
  232. dcstat_apps_accumulator(cv);
  233. dcstat_fill_pid(key, cv);
  234. // We are cleaning to avoid passing data read from one process to other.
  235. memset(cv, 0, length);
  236. pids = pids->next;
  237. }
  238. }
  239. /**
  240. * Read global table
  241. *
  242. * Read the table with number of calls for all functions
  243. */
  244. static void read_global_table()
  245. {
  246. uint32_t idx;
  247. netdata_idx_t *val = dcstat_hash_values;
  248. netdata_idx_t *stored = dcstat_values;
  249. int fd = map_fd[NETDATA_DCSTAT_GLOBAL_STATS];
  250. for (idx = NETDATA_KEY_DC_REFERENCE; idx < NETDATA_DIRECTORY_CACHE_END; idx++) {
  251. if (!bpf_map_lookup_elem(fd, &idx, stored)) {
  252. int i;
  253. int end = ebpf_nprocs;
  254. netdata_idx_t total = 0;
  255. for (i = 0; i < end; i++)
  256. total += stored[i];
  257. val[idx] = total;
  258. }
  259. }
  260. }
  261. /**
  262. * DCstat read hash
  263. *
  264. * This is the thread callback.
  265. * This thread is necessary, because we cannot freeze the whole plugin to read the data.
  266. *
  267. * @param ptr It is a NULL value for this thread.
  268. *
  269. * @return It always returns NULL.
  270. */
  271. void *ebpf_dcstat_read_hash(void *ptr)
  272. {
  273. read_thread_closed = 0;
  274. heartbeat_t hb;
  275. heartbeat_init(&hb);
  276. ebpf_module_t *em = (ebpf_module_t *)ptr;
  277. usec_t step = NETDATA_LATENCY_DCSTAT_SLEEP_MS * em->update_time;
  278. while (!close_ebpf_plugin) {
  279. usec_t dt = heartbeat_next(&hb, step);
  280. (void)dt;
  281. read_global_table();
  282. }
  283. read_thread_closed = 1;
  284. return NULL;
  285. }
  286. /**
  287. * Cachestat sum PIDs
  288. *
  289. * Sum values for all PIDs associated to a group
  290. *
  291. * @param publish output structure.
  292. * @param root structure with listed IPs
  293. */
  294. void ebpf_dcstat_sum_pids(netdata_publish_dcstat_t *publish, struct pid_on_target *root)
  295. {
  296. memset(&publish->curr, 0, sizeof(netdata_dcstat_pid_t));
  297. netdata_dcstat_pid_t *dst = &publish->curr;
  298. while (root) {
  299. int32_t pid = root->pid;
  300. netdata_publish_dcstat_t *w = dcstat_pid[pid];
  301. if (w) {
  302. netdata_dcstat_pid_t *src = &w->curr;
  303. dst->cache_access += src->cache_access;
  304. dst->file_system += src->file_system;
  305. dst->not_found += src->not_found;
  306. }
  307. root = root->next;
  308. }
  309. }
  310. /**
  311. * Send data to Netdata calling auxiliar functions.
  312. *
  313. * @param root the target list.
  314. */
  315. void ebpf_dcache_send_apps_data(struct target *root)
  316. {
  317. struct target *w;
  318. collected_number value;
  319. write_begin_chart(NETDATA_APPS_FAMILY, NETDATA_DC_HIT_CHART);
  320. for (w = root; w; w = w->next) {
  321. if (unlikely(w->exposed && w->processes)) {
  322. ebpf_dcstat_sum_pids(&w->dcstat, w->root_pid);
  323. uint64_t cache = w->dcstat.curr.cache_access;
  324. uint64_t not_found = w->dcstat.curr.not_found;
  325. dcstat_update_publish(&w->dcstat, cache, not_found);
  326. value = (collected_number) w->dcstat.ratio;
  327. write_chart_dimension(w->name, value);
  328. }
  329. }
  330. write_end_chart();
  331. write_begin_chart(NETDATA_APPS_FAMILY, NETDATA_DC_REFERENCE_CHART);
  332. for (w = root; w; w = w->next) {
  333. if (unlikely(w->exposed && w->processes)) {
  334. if (w->dcstat.curr.cache_access < w->dcstat.prev.cache_access) {
  335. w->dcstat.prev.cache_access = 0;
  336. }
  337. w->dcstat.cache_access = (long long)w->dcstat.curr.cache_access - (long long)w->dcstat.prev.cache_access;
  338. value = (collected_number) w->dcstat.cache_access;
  339. write_chart_dimension(w->name, value);
  340. w->dcstat.prev.cache_access = w->dcstat.curr.cache_access;
  341. }
  342. }
  343. write_end_chart();
  344. write_begin_chart(NETDATA_APPS_FAMILY, NETDATA_DC_REQUEST_NOT_CACHE_CHART);
  345. for (w = root; w; w = w->next) {
  346. if (unlikely(w->exposed && w->processes)) {
  347. if (w->dcstat.curr.file_system < w->dcstat.prev.file_system) {
  348. w->dcstat.prev.file_system = 0;
  349. }
  350. value = (collected_number) (!w->dcstat.cache_access) ? 0 :
  351. (long long )w->dcstat.curr.file_system - (long long)w->dcstat.prev.file_system;
  352. write_chart_dimension(w->name, value);
  353. w->dcstat.prev.file_system = w->dcstat.curr.file_system;
  354. }
  355. }
  356. write_end_chart();
  357. write_begin_chart(NETDATA_APPS_FAMILY, NETDATA_DC_REQUEST_NOT_FOUND_CHART);
  358. for (w = root; w; w = w->next) {
  359. if (unlikely(w->exposed && w->processes)) {
  360. if (w->dcstat.curr.not_found < w->dcstat.prev.not_found) {
  361. w->dcstat.prev.not_found = 0;
  362. }
  363. value = (collected_number) (!w->dcstat.cache_access) ? 0 :
  364. (long long)w->dcstat.curr.not_found - (long long)w->dcstat.prev.not_found;
  365. write_chart_dimension(w->name, value);
  366. w->dcstat.prev.not_found = w->dcstat.curr.not_found;
  367. }
  368. }
  369. write_end_chart();
  370. }
  371. /**
  372. * Send global
  373. *
  374. * Send global charts to Netdata
  375. */
  376. static void dcstat_send_global(netdata_publish_dcstat_t *publish)
  377. {
  378. dcstat_update_publish(publish, dcstat_hash_values[NETDATA_KEY_DC_REFERENCE],
  379. dcstat_hash_values[NETDATA_KEY_DC_MISS]);
  380. netdata_publish_syscall_t *ptr = dcstat_counter_publish_aggregated;
  381. netdata_idx_t value = dcstat_hash_values[NETDATA_KEY_DC_REFERENCE];
  382. if (value != ptr[NETDATA_DCSTAT_IDX_REFERENCE].pcall) {
  383. ptr[NETDATA_DCSTAT_IDX_REFERENCE].ncall = value - ptr[NETDATA_DCSTAT_IDX_REFERENCE].pcall;
  384. ptr[NETDATA_DCSTAT_IDX_REFERENCE].pcall = value;
  385. value = dcstat_hash_values[NETDATA_KEY_DC_SLOW];
  386. ptr[NETDATA_DCSTAT_IDX_SLOW].ncall = value - ptr[NETDATA_DCSTAT_IDX_SLOW].pcall;
  387. ptr[NETDATA_DCSTAT_IDX_SLOW].pcall = value;
  388. value = dcstat_hash_values[NETDATA_KEY_DC_MISS];
  389. ptr[NETDATA_DCSTAT_IDX_MISS].ncall = value - ptr[NETDATA_DCSTAT_IDX_MISS].pcall;
  390. ptr[NETDATA_DCSTAT_IDX_MISS].pcall = value;
  391. } else {
  392. ptr[NETDATA_DCSTAT_IDX_REFERENCE].ncall = 0;
  393. ptr[NETDATA_DCSTAT_IDX_SLOW].ncall = 0;
  394. ptr[NETDATA_DCSTAT_IDX_MISS].ncall = 0;
  395. }
  396. ebpf_one_dimension_write_charts(NETDATA_FILESYSTEM_FAMILY, NETDATA_DC_HIT_CHART,
  397. ptr[NETDATA_DCSTAT_IDX_RATIO].dimension, publish->ratio);
  398. write_count_chart(
  399. NETDATA_DC_REFERENCE_CHART, NETDATA_FILESYSTEM_FAMILY,
  400. &dcstat_counter_publish_aggregated[NETDATA_DCSTAT_IDX_REFERENCE], 3);
  401. }
  402. /**
  403. * Main loop for this collector.
  404. */
  405. static void dcstat_collector(ebpf_module_t *em)
  406. {
  407. dcstat_threads.thread = mallocz(sizeof(netdata_thread_t));
  408. dcstat_threads.start_routine = ebpf_dcstat_read_hash;
  409. map_fd = dcstat_data.map_fd;
  410. netdata_thread_create(dcstat_threads.thread, dcstat_threads.name, NETDATA_THREAD_OPTION_JOINABLE,
  411. ebpf_dcstat_read_hash, em);
  412. netdata_publish_dcstat_t publish;
  413. memset(&publish, 0, sizeof(publish));
  414. int apps = em->apps_charts;
  415. while (!close_ebpf_plugin) {
  416. pthread_mutex_lock(&collect_data_mutex);
  417. pthread_cond_wait(&collect_data_cond_var, &collect_data_mutex);
  418. if (apps)
  419. read_apps_table();
  420. pthread_mutex_lock(&lock);
  421. dcstat_send_global(&publish);
  422. if (apps)
  423. ebpf_dcache_send_apps_data(apps_groups_root_target);
  424. pthread_mutex_unlock(&lock);
  425. pthread_mutex_unlock(&collect_data_mutex);
  426. }
  427. }
  428. /*****************************************************************
  429. *
  430. * INITIALIZE THREAD
  431. *
  432. *****************************************************************/
  433. /**
  434. * Create filesystem charts
  435. *
  436. * Call ebpf_create_chart to create the charts for the collector.
  437. */
  438. static void ebpf_create_filesystem_charts()
  439. {
  440. ebpf_create_chart(NETDATA_FILESYSTEM_FAMILY, NETDATA_DC_HIT_CHART,
  441. "Percentage of files listed inside directory cache",
  442. EBPF_COMMON_DIMENSION_PERCENTAGE, NETDATA_DIRECTORY_FILESYSTEM_SUBMENU,
  443. NULL,
  444. NETDATA_EBPF_CHART_TYPE_LINE,
  445. 21200,
  446. ebpf_create_global_dimension,
  447. dcstat_counter_publish_aggregated, 1);
  448. ebpf_create_chart(NETDATA_FILESYSTEM_FAMILY, NETDATA_DC_REFERENCE_CHART,
  449. "Variables used to calculate hit ratio.",
  450. EBPF_COMMON_DIMENSION_FILES, NETDATA_DIRECTORY_FILESYSTEM_SUBMENU,
  451. NULL,
  452. NETDATA_EBPF_CHART_TYPE_LINE,
  453. 21201,
  454. ebpf_create_global_dimension,
  455. &dcstat_counter_publish_aggregated[NETDATA_DCSTAT_IDX_REFERENCE], 3);
  456. fflush(stdout);
  457. }
  458. /**
  459. * Allocate vectors used with this thread.
  460. *
  461. * We are not testing the return, because callocz does this and shutdown the software
  462. * case it was not possible to allocate.
  463. *
  464. * @param length is the length for the vectors used inside the collector.
  465. */
  466. static void ebpf_dcstat_allocate_global_vectors(size_t length)
  467. {
  468. dcstat_pid = callocz((size_t)pid_max, sizeof(netdata_publish_dcstat_t *));
  469. dcstat_vector = callocz((size_t)ebpf_nprocs, sizeof(netdata_dcstat_pid_t));
  470. dcstat_values = callocz((size_t)ebpf_nprocs, sizeof(netdata_idx_t));
  471. memset(dcstat_counter_aggregated_data, 0, length*sizeof(netdata_syscall_stat_t));
  472. memset(dcstat_counter_publish_aggregated, 0, length*sizeof(netdata_publish_syscall_t));
  473. }
  474. /*****************************************************************
  475. *
  476. * MAIN THREAD
  477. *
  478. *****************************************************************/
  479. /**
  480. * Directory Cache thread
  481. *
  482. * Thread used to make dcstat thread
  483. *
  484. * @param ptr a pointer to `struct ebpf_module`
  485. *
  486. * @return It always returns NULL
  487. */
  488. void *ebpf_dcstat_thread(void *ptr)
  489. {
  490. netdata_thread_cleanup_push(ebpf_dcstat_cleanup, ptr);
  491. ebpf_module_t *em = (ebpf_module_t *)ptr;
  492. em->maps = dcstat_maps;
  493. fill_ebpf_data(&dcstat_data);
  494. ebpf_update_pid_table(&dcstat_maps[0], em);
  495. ebpf_update_names(dc_optional_name, em);
  496. if (!em->enabled)
  497. goto enddcstat;
  498. ebpf_dcstat_allocate_global_vectors(NETDATA_DCSTAT_IDX_END);
  499. pthread_mutex_lock(&lock);
  500. probe_links = ebpf_load_program(ebpf_plugin_dir, em, kernel_string, &objects, dcstat_data.map_fd);
  501. if (!probe_links) {
  502. pthread_mutex_unlock(&lock);
  503. goto enddcstat;
  504. }
  505. int algorithms[NETDATA_DCSTAT_IDX_END] = {
  506. NETDATA_EBPF_ABSOLUTE_IDX, NETDATA_EBPF_ABSOLUTE_IDX, NETDATA_EBPF_ABSOLUTE_IDX,
  507. NETDATA_EBPF_ABSOLUTE_IDX
  508. };
  509. ebpf_global_labels(dcstat_counter_aggregated_data, dcstat_counter_publish_aggregated,
  510. dcstat_counter_dimension_name, dcstat_counter_dimension_name,
  511. algorithms, NETDATA_DCSTAT_IDX_END);
  512. ebpf_create_filesystem_charts();
  513. pthread_mutex_unlock(&lock);
  514. dcstat_collector(em);
  515. enddcstat:
  516. netdata_thread_cleanup_pop(1);
  517. return NULL;
  518. }