ebpf_shm.c 37 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102
  1. // SPDX-License-Identifier: GPL-3.0-or-later
  2. #include "ebpf.h"
  3. #include "ebpf_shm.h"
  4. static char *shm_dimension_name[NETDATA_SHM_END] = { "get", "at", "dt", "ctl" };
  5. static netdata_syscall_stat_t shm_aggregated_data[NETDATA_SHM_END];
  6. static netdata_publish_syscall_t shm_publish_aggregated[NETDATA_SHM_END];
  7. netdata_publish_shm_t *shm_vector = NULL;
  8. static netdata_idx_t shm_hash_values[NETDATA_SHM_END];
  9. static netdata_idx_t *shm_values = NULL;
  10. struct config shm_config = { .first_section = NULL,
  11. .last_section = NULL,
  12. .mutex = NETDATA_MUTEX_INITIALIZER,
  13. .index = { .avl_tree = { .root = NULL, .compar = appconfig_section_compare },
  14. .rwlock = AVL_LOCK_INITIALIZER } };
  15. static ebpf_local_maps_t shm_maps[] = {{.name = "tbl_pid_shm", .internal_input = ND_EBPF_DEFAULT_PID_SIZE,
  16. .user_input = 0,
  17. .type = NETDATA_EBPF_MAP_RESIZABLE | NETDATA_EBPF_MAP_PID,
  18. .map_fd = ND_EBPF_MAP_FD_NOT_INITIALIZED,
  19. #ifdef LIBBPF_MAJOR_VERSION
  20. .map_type = BPF_MAP_TYPE_PERCPU_HASH
  21. #endif
  22. },
  23. {.name = "shm_ctrl", .internal_input = NETDATA_CONTROLLER_END,
  24. .user_input = 0,
  25. .type = NETDATA_EBPF_MAP_CONTROLLER,
  26. .map_fd = ND_EBPF_MAP_FD_NOT_INITIALIZED,
  27. #ifdef LIBBPF_MAJOR_VERSION
  28. .map_type = BPF_MAP_TYPE_PERCPU_ARRAY
  29. #endif
  30. },
  31. {.name = "tbl_shm", .internal_input = NETDATA_SHM_END,
  32. .user_input = 0,
  33. .type = NETDATA_EBPF_MAP_STATIC,
  34. .map_fd = ND_EBPF_MAP_FD_NOT_INITIALIZED,
  35. #ifdef LIBBPF_MAJOR_VERSION
  36. .map_type = BPF_MAP_TYPE_PERCPU_ARRAY
  37. #endif
  38. },
  39. {.name = NULL, .internal_input = 0, .user_input = 0}};
  40. netdata_ebpf_targets_t shm_targets[] = { {.name = "shmget", .mode = EBPF_LOAD_TRAMPOLINE},
  41. {.name = "shmat", .mode = EBPF_LOAD_TRAMPOLINE},
  42. {.name = "shmdt", .mode = EBPF_LOAD_TRAMPOLINE},
  43. {.name = "shmctl", .mode = EBPF_LOAD_TRAMPOLINE},
  44. {.name = NULL, .mode = EBPF_LOAD_TRAMPOLINE}};
  45. #ifdef LIBBPF_MAJOR_VERSION
  46. /*****************************************************************
  47. *
  48. * BTF FUNCTIONS
  49. *
  50. *****************************************************************/
  51. /*
  52. * Disable tracepoint
  53. *
  54. * Disable all tracepoints to use exclusively another method.
  55. *
  56. * @param obj is the main structure for bpf objects.
  57. */
  58. static void ebpf_shm_disable_tracepoint(struct shm_bpf *obj)
  59. {
  60. bpf_program__set_autoload(obj->progs.netdata_syscall_shmget, false);
  61. bpf_program__set_autoload(obj->progs.netdata_syscall_shmat, false);
  62. bpf_program__set_autoload(obj->progs.netdata_syscall_shmdt, false);
  63. bpf_program__set_autoload(obj->progs.netdata_syscall_shmctl, false);
  64. }
  65. /*
  66. * Disable probe
  67. *
  68. * Disable all probes to use exclusively another method.
  69. *
  70. * @param obj is the main structure for bpf objects.
  71. */
  72. static void ebpf_disable_probe(struct shm_bpf *obj)
  73. {
  74. bpf_program__set_autoload(obj->progs.netdata_shmget_probe, false);
  75. bpf_program__set_autoload(obj->progs.netdata_shmat_probe, false);
  76. bpf_program__set_autoload(obj->progs.netdata_shmdt_probe, false);
  77. bpf_program__set_autoload(obj->progs.netdata_shmctl_probe, false);
  78. bpf_program__set_autoload(obj->progs.netdata_shm_release_task_probe, false);
  79. }
  80. /*
  81. * Disable trampoline
  82. *
  83. * Disable all trampoline to use exclusively another method.
  84. *
  85. * @param obj is the main structure for bpf objects.
  86. */
  87. static void ebpf_disable_trampoline(struct shm_bpf *obj)
  88. {
  89. bpf_program__set_autoload(obj->progs.netdata_shmget_fentry, false);
  90. bpf_program__set_autoload(obj->progs.netdata_shmat_fentry, false);
  91. bpf_program__set_autoload(obj->progs.netdata_shmdt_fentry, false);
  92. bpf_program__set_autoload(obj->progs.netdata_shmctl_fentry, false);
  93. bpf_program__set_autoload(obj->progs.netdata_shm_release_task_fentry, false);
  94. }
  95. /**
  96. * Set trampoline target
  97. *
  98. * Set the targets we will monitor.
  99. *
  100. * @param obj is the main structure for bpf objects.
  101. */
  102. static void ebpf_set_trampoline_target(struct shm_bpf *obj)
  103. {
  104. char syscall[NETDATA_EBPF_MAX_SYSCALL_LENGTH + 1];
  105. ebpf_select_host_prefix(syscall, NETDATA_EBPF_MAX_SYSCALL_LENGTH,
  106. shm_targets[NETDATA_KEY_SHMGET_CALL].name, running_on_kernel);
  107. bpf_program__set_attach_target(obj->progs.netdata_shmget_fentry, 0,
  108. syscall);
  109. ebpf_select_host_prefix(syscall, NETDATA_EBPF_MAX_SYSCALL_LENGTH,
  110. shm_targets[NETDATA_KEY_SHMAT_CALL].name, running_on_kernel);
  111. bpf_program__set_attach_target(obj->progs.netdata_shmat_fentry, 0,
  112. syscall);
  113. ebpf_select_host_prefix(syscall, NETDATA_EBPF_MAX_SYSCALL_LENGTH,
  114. shm_targets[NETDATA_KEY_SHMDT_CALL].name, running_on_kernel);
  115. bpf_program__set_attach_target(obj->progs.netdata_shmdt_fentry, 0,
  116. syscall);
  117. ebpf_select_host_prefix(syscall, NETDATA_EBPF_MAX_SYSCALL_LENGTH,
  118. shm_targets[NETDATA_KEY_SHMCTL_CALL].name, running_on_kernel);
  119. bpf_program__set_attach_target(obj->progs.netdata_shmctl_fentry, 0,
  120. syscall);
  121. bpf_program__set_attach_target(obj->progs.netdata_shm_release_task_fentry, 0,
  122. EBPF_COMMON_FNCT_CLEAN_UP);
  123. }
  124. /**
  125. * SHM Attach Probe
  126. *
  127. * Attach probes to target
  128. *
  129. * @param obj is the main structure for bpf objects.
  130. *
  131. * @return It returns 0 on success and -1 otherwise.
  132. */
  133. static int ebpf_shm_attach_probe(struct shm_bpf *obj)
  134. {
  135. char syscall[NETDATA_EBPF_MAX_SYSCALL_LENGTH + 1];
  136. ebpf_select_host_prefix(syscall, NETDATA_EBPF_MAX_SYSCALL_LENGTH,
  137. shm_targets[NETDATA_KEY_SHMGET_CALL].name, running_on_kernel);
  138. obj->links.netdata_shmget_probe = bpf_program__attach_kprobe(obj->progs.netdata_shmget_probe,
  139. false, syscall);
  140. int ret = (int)libbpf_get_error(obj->links.netdata_shmget_probe);
  141. if (ret)
  142. return -1;
  143. ebpf_select_host_prefix(syscall, NETDATA_EBPF_MAX_SYSCALL_LENGTH,
  144. shm_targets[NETDATA_KEY_SHMAT_CALL].name, running_on_kernel);
  145. obj->links.netdata_shmat_probe = bpf_program__attach_kprobe(obj->progs.netdata_shmat_probe,
  146. false, syscall);
  147. ret = (int)libbpf_get_error(obj->links.netdata_shmat_probe);
  148. if (ret)
  149. return -1;
  150. ebpf_select_host_prefix(syscall, NETDATA_EBPF_MAX_SYSCALL_LENGTH,
  151. shm_targets[NETDATA_KEY_SHMDT_CALL].name, running_on_kernel);
  152. obj->links.netdata_shmdt_probe = bpf_program__attach_kprobe(obj->progs.netdata_shmdt_probe,
  153. false, syscall);
  154. ret = (int)libbpf_get_error(obj->links.netdata_shmdt_probe);
  155. if (ret)
  156. return -1;
  157. ebpf_select_host_prefix(syscall, NETDATA_EBPF_MAX_SYSCALL_LENGTH,
  158. shm_targets[NETDATA_KEY_SHMCTL_CALL].name, running_on_kernel);
  159. obj->links.netdata_shmctl_probe = bpf_program__attach_kprobe(obj->progs.netdata_shmctl_probe,
  160. false, syscall);
  161. ret = (int)libbpf_get_error(obj->links.netdata_shmctl_probe);
  162. if (ret)
  163. return -1;
  164. obj->links.netdata_shm_release_task_probe = bpf_program__attach_kprobe(obj->progs.netdata_shm_release_task_probe,
  165. false, EBPF_COMMON_FNCT_CLEAN_UP);
  166. ret = (int)libbpf_get_error(obj->links.netdata_shm_release_task_probe);
  167. if (ret)
  168. return -1;
  169. return 0;
  170. }
  171. /**
  172. * Set hash tables
  173. *
  174. * Set the values for maps according the value given by kernel.
  175. */
  176. static void ebpf_shm_set_hash_tables(struct shm_bpf *obj)
  177. {
  178. shm_maps[NETDATA_PID_SHM_TABLE].map_fd = bpf_map__fd(obj->maps.tbl_pid_shm);
  179. shm_maps[NETDATA_SHM_CONTROLLER].map_fd = bpf_map__fd(obj->maps.shm_ctrl);
  180. shm_maps[NETDATA_SHM_GLOBAL_TABLE].map_fd = bpf_map__fd(obj->maps.tbl_shm);
  181. }
  182. /**
  183. * Disable Release Task
  184. *
  185. * Disable release task when apps is not enabled.
  186. *
  187. * @param obj is the main structure for bpf objects.
  188. */
  189. static void ebpf_shm_disable_release_task(struct shm_bpf *obj)
  190. {
  191. bpf_program__set_autoload(obj->progs.netdata_shm_release_task_probe, false);
  192. bpf_program__set_autoload(obj->progs.netdata_shm_release_task_fentry, false);
  193. }
  194. /**
  195. * Adjust Map Size
  196. *
  197. * Resize maps according input from users.
  198. *
  199. * @param obj is the main structure for bpf objects.
  200. * @param em structure with configuration
  201. */
  202. static void ebpf_shm_adjust_map(struct shm_bpf *obj, ebpf_module_t *em)
  203. {
  204. ebpf_update_map_size(obj->maps.tbl_pid_shm, &shm_maps[NETDATA_PID_SHM_TABLE],
  205. em, bpf_map__name(obj->maps.tbl_pid_shm));
  206. ebpf_update_map_type(obj->maps.tbl_shm, &shm_maps[NETDATA_SHM_GLOBAL_TABLE]);
  207. ebpf_update_map_type(obj->maps.tbl_pid_shm, &shm_maps[NETDATA_PID_SHM_TABLE]);
  208. ebpf_update_map_type(obj->maps.shm_ctrl, &shm_maps[NETDATA_SHM_CONTROLLER]);
  209. }
  210. /**
  211. * Load and attach
  212. *
  213. * Load and attach the eBPF code in kernel.
  214. *
  215. * @param obj is the main structure for bpf objects.
  216. * @param em structure with configuration
  217. *
  218. * @return it returns 0 on success and -1 otherwise
  219. */
  220. static inline int ebpf_shm_load_and_attach(struct shm_bpf *obj, ebpf_module_t *em)
  221. {
  222. netdata_ebpf_targets_t *shmt = em->targets;
  223. netdata_ebpf_program_loaded_t test = shmt[NETDATA_KEY_SHMGET_CALL].mode;
  224. // We are testing only one, because all will have the same behavior
  225. if (test == EBPF_LOAD_TRAMPOLINE ) {
  226. ebpf_shm_disable_tracepoint(obj);
  227. ebpf_disable_probe(obj);
  228. ebpf_set_trampoline_target(obj);
  229. } else if (test == EBPF_LOAD_PROBE || test == EBPF_LOAD_RETPROBE ) {
  230. ebpf_shm_disable_tracepoint(obj);
  231. ebpf_disable_trampoline(obj);
  232. } else {
  233. ebpf_disable_probe(obj);
  234. ebpf_disable_trampoline(obj);
  235. }
  236. ebpf_shm_adjust_map(obj, em);
  237. if (!em->apps_charts && !em->cgroup_charts)
  238. ebpf_shm_disable_release_task(obj);
  239. int ret = shm_bpf__load(obj);
  240. if (!ret) {
  241. if (test != EBPF_LOAD_PROBE && test != EBPF_LOAD_RETPROBE)
  242. shm_bpf__attach(obj);
  243. else
  244. ret = ebpf_shm_attach_probe(obj);
  245. if (!ret)
  246. ebpf_shm_set_hash_tables(obj);
  247. }
  248. return ret;
  249. }
  250. #endif
  251. /*****************************************************************
  252. * FUNCTIONS TO CLOSE THE THREAD
  253. *****************************************************************/
  254. /**
  255. * SHM Exit
  256. *
  257. * Cancel child thread.
  258. *
  259. * @param ptr thread data.
  260. */
  261. static void ebpf_shm_exit(void *ptr)
  262. {
  263. ebpf_module_t *em = (ebpf_module_t *)ptr;
  264. #ifdef LIBBPF_MAJOR_VERSION
  265. if (shm_bpf_obj)
  266. shm_bpf__destroy(shm_bpf_obj);
  267. #endif
  268. if (em->objects)
  269. ebpf_unload_legacy_code(em->objects, em->probe_links);
  270. pthread_mutex_lock(&ebpf_exit_cleanup);
  271. em->enabled = NETDATA_THREAD_EBPF_STOPPED;
  272. pthread_mutex_unlock(&ebpf_exit_cleanup);
  273. }
  274. /*****************************************************************
  275. * COLLECTOR THREAD
  276. *****************************************************************/
  277. /**
  278. * Apps Accumulator
  279. *
  280. * Sum all values read from kernel and store in the first address.
  281. *
  282. * @param out the vector with read values.
  283. * @param maps_per_core do I need to read all cores?
  284. */
  285. static void shm_apps_accumulator(netdata_publish_shm_t *out, int maps_per_core)
  286. {
  287. int i, end = (maps_per_core) ? ebpf_nprocs : 1;
  288. netdata_publish_shm_t *total = &out[0];
  289. for (i = 1; i < end; i++) {
  290. netdata_publish_shm_t *w = &out[i];
  291. total->get += w->get;
  292. total->at += w->at;
  293. total->dt += w->dt;
  294. total->ctl += w->ctl;
  295. }
  296. }
  297. /**
  298. * Fill PID
  299. *
  300. * Fill PID structures
  301. *
  302. * @param current_pid pid that we are collecting data
  303. * @param out values read from hash tables;
  304. */
  305. static void shm_fill_pid(uint32_t current_pid, netdata_publish_shm_t *publish)
  306. {
  307. netdata_publish_shm_t *curr = shm_pid[current_pid];
  308. if (!curr) {
  309. curr = ebpf_shm_stat_get( );
  310. shm_pid[current_pid] = curr;
  311. }
  312. memcpy(curr, publish, sizeof(netdata_publish_shm_t));
  313. }
  314. /**
  315. * Update cgroup
  316. *
  317. * Update cgroup data based in
  318. *
  319. * @param maps_per_core do I need to read all cores?
  320. */
  321. static void ebpf_update_shm_cgroup(int maps_per_core)
  322. {
  323. netdata_publish_shm_t *cv = shm_vector;
  324. int fd = shm_maps[NETDATA_PID_SHM_TABLE].map_fd;
  325. size_t length = sizeof(netdata_publish_shm_t);
  326. if (maps_per_core)
  327. length *= ebpf_nprocs;
  328. ebpf_cgroup_target_t *ect;
  329. memset(cv, 0, length);
  330. pthread_mutex_lock(&mutex_cgroup_shm);
  331. for (ect = ebpf_cgroup_pids; ect; ect = ect->next) {
  332. struct pid_on_target2 *pids;
  333. for (pids = ect->pids; pids; pids = pids->next) {
  334. int pid = pids->pid;
  335. netdata_publish_shm_t *out = &pids->shm;
  336. if (likely(shm_pid) && shm_pid[pid]) {
  337. netdata_publish_shm_t *in = shm_pid[pid];
  338. memcpy(out, in, sizeof(netdata_publish_shm_t));
  339. } else {
  340. if (!bpf_map_lookup_elem(fd, &pid, cv)) {
  341. shm_apps_accumulator(cv, maps_per_core);
  342. memcpy(out, cv, sizeof(netdata_publish_shm_t));
  343. // now that we've consumed the value, zero it out in the map.
  344. memset(cv, 0, length);
  345. bpf_map_update_elem(fd, &pid, cv, BPF_EXIST);
  346. }
  347. }
  348. }
  349. }
  350. pthread_mutex_unlock(&mutex_cgroup_shm);
  351. }
  352. /**
  353. * Read APPS table
  354. *
  355. * Read the apps table and store data inside the structure.
  356. *
  357. * @param maps_per_core do I need to read all cores?
  358. */
  359. static void read_shm_apps_table(int maps_per_core)
  360. {
  361. netdata_publish_shm_t *cv = shm_vector;
  362. uint32_t key;
  363. struct ebpf_pid_stat *pids = ebpf_root_of_pids;
  364. int fd = shm_maps[NETDATA_PID_SHM_TABLE].map_fd;
  365. size_t length = sizeof(netdata_publish_shm_t);
  366. if (maps_per_core)
  367. length *= ebpf_nprocs;
  368. while (pids) {
  369. key = pids->pid;
  370. if (bpf_map_lookup_elem(fd, &key, cv)) {
  371. pids = pids->next;
  372. continue;
  373. }
  374. shm_apps_accumulator(cv, maps_per_core);
  375. shm_fill_pid(key, cv);
  376. // now that we've consumed the value, zero it out in the map.
  377. memset(cv, 0, length);
  378. bpf_map_update_elem(fd, &key, cv, BPF_EXIST);
  379. pids = pids->next;
  380. }
  381. }
  382. /**
  383. * Send global charts to netdata agent.
  384. */
  385. static void shm_send_global()
  386. {
  387. write_begin_chart(NETDATA_EBPF_SYSTEM_GROUP, NETDATA_SHM_GLOBAL_CHART);
  388. write_chart_dimension(
  389. shm_publish_aggregated[NETDATA_KEY_SHMGET_CALL].dimension,
  390. (long long) shm_hash_values[NETDATA_KEY_SHMGET_CALL]
  391. );
  392. write_chart_dimension(
  393. shm_publish_aggregated[NETDATA_KEY_SHMAT_CALL].dimension,
  394. (long long) shm_hash_values[NETDATA_KEY_SHMAT_CALL]
  395. );
  396. write_chart_dimension(
  397. shm_publish_aggregated[NETDATA_KEY_SHMDT_CALL].dimension,
  398. (long long) shm_hash_values[NETDATA_KEY_SHMDT_CALL]
  399. );
  400. write_chart_dimension(
  401. shm_publish_aggregated[NETDATA_KEY_SHMCTL_CALL].dimension,
  402. (long long) shm_hash_values[NETDATA_KEY_SHMCTL_CALL]
  403. );
  404. write_end_chart();
  405. }
  406. /**
  407. * Read global counter
  408. *
  409. * Read the table with number of calls for all functions
  410. *
  411. * @param maps_per_core do I need to read all cores?
  412. */
  413. static void ebpf_shm_read_global_table(int maps_per_core)
  414. {
  415. netdata_idx_t *stored = shm_values;
  416. netdata_idx_t *val = shm_hash_values;
  417. int fd = shm_maps[NETDATA_SHM_GLOBAL_TABLE].map_fd;
  418. size_t length = sizeof(netdata_idx_t);
  419. if (maps_per_core)
  420. length *= ebpf_nprocs;
  421. uint32_t i, end = NETDATA_SHM_END;
  422. for (i = NETDATA_KEY_SHMGET_CALL; i < end; i++) {
  423. if (!bpf_map_lookup_elem(fd, &i, stored)) {
  424. int j;
  425. int last = (maps_per_core) ? ebpf_nprocs : 1;
  426. netdata_idx_t total = 0;
  427. for (j = 0; j < last; j++)
  428. total += stored[j];
  429. val[i] = total;
  430. memset(stored, 0 , length);
  431. }
  432. }
  433. }
  434. /**
  435. * Sum values for all targets.
  436. */
  437. static void ebpf_shm_sum_pids(netdata_publish_shm_t *shm, struct ebpf_pid_on_target *root)
  438. {
  439. while (root) {
  440. int32_t pid = root->pid;
  441. netdata_publish_shm_t *w = shm_pid[pid];
  442. if (w) {
  443. shm->get += w->get;
  444. shm->at += w->at;
  445. shm->dt += w->dt;
  446. shm->ctl += w->ctl;
  447. // reset for next collection.
  448. w->get = 0;
  449. w->at = 0;
  450. w->dt = 0;
  451. w->ctl = 0;
  452. }
  453. root = root->next;
  454. }
  455. }
  456. /**
  457. * Send data to Netdata calling auxiliary functions.
  458. *
  459. * @param root the target list.
  460. */
  461. void ebpf_shm_send_apps_data(struct ebpf_target *root)
  462. {
  463. struct ebpf_target *w;
  464. for (w = root; w; w = w->next) {
  465. if (unlikely(w->exposed && w->processes)) {
  466. ebpf_shm_sum_pids(&w->shm, w->root_pid);
  467. }
  468. }
  469. write_begin_chart(NETDATA_APPS_FAMILY, NETDATA_SHMGET_CHART);
  470. for (w = root; w; w = w->next) {
  471. if (unlikely(w->exposed && w->processes)) {
  472. write_chart_dimension(w->name, (long long) w->shm.get);
  473. }
  474. }
  475. write_end_chart();
  476. write_begin_chart(NETDATA_APPS_FAMILY, NETDATA_SHMAT_CHART);
  477. for (w = root; w; w = w->next) {
  478. if (unlikely(w->exposed && w->processes)) {
  479. write_chart_dimension(w->name, (long long) w->shm.at);
  480. }
  481. }
  482. write_end_chart();
  483. write_begin_chart(NETDATA_APPS_FAMILY, NETDATA_SHMDT_CHART);
  484. for (w = root; w; w = w->next) {
  485. if (unlikely(w->exposed && w->processes)) {
  486. write_chart_dimension(w->name, (long long) w->shm.dt);
  487. }
  488. }
  489. write_end_chart();
  490. write_begin_chart(NETDATA_APPS_FAMILY, NETDATA_SHMCTL_CHART);
  491. for (w = root; w; w = w->next) {
  492. if (unlikely(w->exposed && w->processes)) {
  493. write_chart_dimension(w->name, (long long) w->shm.ctl);
  494. }
  495. }
  496. write_end_chart();
  497. }
  498. /**
  499. * Sum values for all targets.
  500. */
  501. static void ebpf_shm_sum_cgroup_pids(netdata_publish_shm_t *shm, struct pid_on_target2 *root)
  502. {
  503. netdata_publish_shm_t shmv;
  504. memset(&shmv, 0, sizeof(shmv));
  505. while (root) {
  506. netdata_publish_shm_t *w = &root->shm;
  507. shmv.get += w->get;
  508. shmv.at += w->at;
  509. shmv.dt += w->dt;
  510. shmv.ctl += w->ctl;
  511. root = root->next;
  512. }
  513. memcpy(shm, &shmv, sizeof(shmv));
  514. }
  515. /**
  516. * Create specific shared memory charts
  517. *
  518. * Create charts for cgroup/application.
  519. *
  520. * @param type the chart type.
  521. * @param update_every value to overwrite the update frequency set by the server.
  522. */
  523. static void ebpf_create_specific_shm_charts(char *type, int update_every)
  524. {
  525. ebpf_create_chart(type, NETDATA_SHMGET_CHART,
  526. "Calls to syscall <code>shmget(2)</code>.",
  527. EBPF_COMMON_DIMENSION_CALL,
  528. NETDATA_APPS_IPC_SHM_GROUP,
  529. NETDATA_CGROUP_SHM_GET_CONTEXT,
  530. NETDATA_EBPF_CHART_TYPE_LINE,
  531. NETDATA_CHART_PRIO_CGROUPS_CONTAINERS + 5800,
  532. ebpf_create_global_dimension,
  533. &shm_publish_aggregated[NETDATA_KEY_SHMGET_CALL],
  534. 1,
  535. update_every,
  536. NETDATA_EBPF_MODULE_NAME_SHM);
  537. ebpf_create_chart(type, NETDATA_SHMAT_CHART,
  538. "Calls to syscall <code>shmat(2)</code>.",
  539. EBPF_COMMON_DIMENSION_CALL,
  540. NETDATA_APPS_IPC_SHM_GROUP,
  541. NETDATA_CGROUP_SHM_AT_CONTEXT,
  542. NETDATA_EBPF_CHART_TYPE_LINE,
  543. NETDATA_CHART_PRIO_CGROUPS_CONTAINERS + 5801,
  544. ebpf_create_global_dimension,
  545. &shm_publish_aggregated[NETDATA_KEY_SHMAT_CALL],
  546. 1,
  547. update_every,
  548. NETDATA_EBPF_MODULE_NAME_SHM);
  549. ebpf_create_chart(type, NETDATA_SHMDT_CHART,
  550. "Calls to syscall <code>shmdt(2)</code>.",
  551. EBPF_COMMON_DIMENSION_CALL,
  552. NETDATA_APPS_IPC_SHM_GROUP,
  553. NETDATA_CGROUP_SHM_DT_CONTEXT,
  554. NETDATA_EBPF_CHART_TYPE_LINE,
  555. NETDATA_CHART_PRIO_CGROUPS_CONTAINERS + 5802,
  556. ebpf_create_global_dimension,
  557. &shm_publish_aggregated[NETDATA_KEY_SHMDT_CALL],
  558. 1,
  559. update_every,
  560. NETDATA_EBPF_MODULE_NAME_SHM);
  561. ebpf_create_chart(type, NETDATA_SHMCTL_CHART,
  562. "Calls to syscall <code>shmctl(2)</code>.",
  563. EBPF_COMMON_DIMENSION_CALL,
  564. NETDATA_APPS_IPC_SHM_GROUP,
  565. NETDATA_CGROUP_SHM_CTL_CONTEXT,
  566. NETDATA_EBPF_CHART_TYPE_LINE,
  567. NETDATA_CHART_PRIO_CGROUPS_CONTAINERS + 5803,
  568. ebpf_create_global_dimension,
  569. &shm_publish_aggregated[NETDATA_KEY_SHMCTL_CALL],
  570. 1,
  571. update_every,
  572. NETDATA_EBPF_MODULE_NAME_SHM);
  573. }
  574. /**
  575. * Obsolete specific shared memory charts
  576. *
  577. * Obsolete charts for cgroup/application.
  578. *
  579. * @param type the chart type.
  580. * @param update_every value to overwrite the update frequency set by the server.
  581. */
  582. static void ebpf_obsolete_specific_shm_charts(char *type, int update_every)
  583. {
  584. ebpf_write_chart_obsolete(type, NETDATA_SHMGET_CHART,
  585. "Calls to syscall <code>shmget(2)</code>.",
  586. EBPF_COMMON_DIMENSION_CALL,
  587. NETDATA_APPS_IPC_SHM_GROUP,
  588. NETDATA_EBPF_CHART_TYPE_LINE, NETDATA_CGROUP_SHM_GET_CONTEXT,
  589. NETDATA_CHART_PRIO_CGROUPS_CONTAINERS + 5800, update_every);
  590. ebpf_write_chart_obsolete(type, NETDATA_SHMAT_CHART,
  591. "Calls to syscall <code>shmat(2)</code>.",
  592. EBPF_COMMON_DIMENSION_CALL,
  593. NETDATA_APPS_IPC_SHM_GROUP,
  594. NETDATA_EBPF_CHART_TYPE_LINE, NETDATA_CGROUP_SHM_AT_CONTEXT,
  595. NETDATA_CHART_PRIO_CGROUPS_CONTAINERS + 5801, update_every);
  596. ebpf_write_chart_obsolete(type, NETDATA_SHMDT_CHART,
  597. "Calls to syscall <code>shmdt(2)</code>.",
  598. EBPF_COMMON_DIMENSION_CALL,
  599. NETDATA_APPS_IPC_SHM_GROUP,
  600. NETDATA_EBPF_CHART_TYPE_LINE, NETDATA_CGROUP_SHM_DT_CONTEXT,
  601. NETDATA_CHART_PRIO_CGROUPS_CONTAINERS + 5802, update_every);
  602. ebpf_write_chart_obsolete(type, NETDATA_SHMCTL_CHART,
  603. "Calls to syscall <code>shmctl(2)</code>.",
  604. EBPF_COMMON_DIMENSION_CALL,
  605. NETDATA_APPS_IPC_SHM_GROUP,
  606. NETDATA_EBPF_CHART_TYPE_LINE, NETDATA_CGROUP_SHM_CTL_CONTEXT,
  607. NETDATA_CHART_PRIO_CGROUPS_CONTAINERS + 5803, update_every);
  608. }
  609. /**
  610. * Create Systemd Swap Charts
  611. *
  612. * Create charts when systemd is enabled
  613. *
  614. * @param update_every value to overwrite the update frequency set by the server.
  615. **/
  616. static void ebpf_create_systemd_shm_charts(int update_every)
  617. {
  618. ebpf_create_charts_on_systemd(NETDATA_SHMGET_CHART,
  619. "Calls to syscall <code>shmget(2)</code>.",
  620. EBPF_COMMON_DIMENSION_CALL,
  621. NETDATA_APPS_IPC_SHM_GROUP,
  622. NETDATA_EBPF_CHART_TYPE_STACKED,
  623. 20191,
  624. ebpf_algorithms[NETDATA_EBPF_INCREMENTAL_IDX],
  625. NETDATA_SYSTEMD_SHM_GET_CONTEXT, NETDATA_EBPF_MODULE_NAME_SHM, update_every);
  626. ebpf_create_charts_on_systemd(NETDATA_SHMAT_CHART,
  627. "Calls to syscall <code>shmat(2)</code>.",
  628. EBPF_COMMON_DIMENSION_CALL,
  629. NETDATA_APPS_IPC_SHM_GROUP,
  630. NETDATA_EBPF_CHART_TYPE_STACKED,
  631. 20192,
  632. ebpf_algorithms[NETDATA_EBPF_INCREMENTAL_IDX],
  633. NETDATA_SYSTEMD_SHM_AT_CONTEXT, NETDATA_EBPF_MODULE_NAME_SHM, update_every);
  634. ebpf_create_charts_on_systemd(NETDATA_SHMDT_CHART,
  635. "Calls to syscall <code>shmdt(2)</code>.",
  636. EBPF_COMMON_DIMENSION_CALL,
  637. NETDATA_APPS_IPC_SHM_GROUP,
  638. NETDATA_EBPF_CHART_TYPE_STACKED,
  639. 20193,
  640. ebpf_algorithms[NETDATA_EBPF_INCREMENTAL_IDX],
  641. NETDATA_SYSTEMD_SHM_DT_CONTEXT, NETDATA_EBPF_MODULE_NAME_SHM, update_every);
  642. ebpf_create_charts_on_systemd(NETDATA_SHMCTL_CHART,
  643. "Calls to syscall <code>shmctl(2)</code>.",
  644. EBPF_COMMON_DIMENSION_CALL,
  645. NETDATA_APPS_IPC_SHM_GROUP,
  646. NETDATA_EBPF_CHART_TYPE_STACKED,
  647. 20193,
  648. ebpf_algorithms[NETDATA_EBPF_INCREMENTAL_IDX],
  649. NETDATA_SYSTEMD_SHM_CTL_CONTEXT, NETDATA_EBPF_MODULE_NAME_SHM, update_every);
  650. }
  651. /**
  652. * Send Systemd charts
  653. *
  654. * Send collected data to Netdata.
  655. */
  656. static void ebpf_send_systemd_shm_charts()
  657. {
  658. ebpf_cgroup_target_t *ect;
  659. write_begin_chart(NETDATA_SERVICE_FAMILY, NETDATA_SHMGET_CHART);
  660. for (ect = ebpf_cgroup_pids; ect; ect = ect->next) {
  661. if (unlikely(ect->systemd) && unlikely(ect->updated)) {
  662. write_chart_dimension(ect->name, (long long)ect->publish_shm.get);
  663. }
  664. }
  665. write_end_chart();
  666. write_begin_chart(NETDATA_SERVICE_FAMILY, NETDATA_SHMAT_CHART);
  667. for (ect = ebpf_cgroup_pids; ect; ect = ect->next) {
  668. if (unlikely(ect->systemd) && unlikely(ect->updated)) {
  669. write_chart_dimension(ect->name, (long long)ect->publish_shm.at);
  670. }
  671. }
  672. write_end_chart();
  673. write_begin_chart(NETDATA_SERVICE_FAMILY, NETDATA_SHMDT_CHART);
  674. for (ect = ebpf_cgroup_pids; ect; ect = ect->next) {
  675. if (unlikely(ect->systemd) && unlikely(ect->updated)) {
  676. write_chart_dimension(ect->name, (long long)ect->publish_shm.dt);
  677. }
  678. }
  679. write_end_chart();
  680. write_begin_chart(NETDATA_SERVICE_FAMILY, NETDATA_SHMCTL_CHART);
  681. for (ect = ebpf_cgroup_pids; ect; ect = ect->next) {
  682. if (unlikely(ect->systemd) && unlikely(ect->updated)) {
  683. write_chart_dimension(ect->name, (long long)ect->publish_shm.ctl);
  684. }
  685. }
  686. write_end_chart();
  687. }
  688. /*
  689. * Send Specific Shared memory data
  690. *
  691. * Send data for specific cgroup/apps.
  692. *
  693. * @param type chart type
  694. * @param values structure with values that will be sent to netdata
  695. */
  696. static void ebpf_send_specific_shm_data(char *type, netdata_publish_shm_t *values)
  697. {
  698. write_begin_chart(type, NETDATA_SHMGET_CHART);
  699. write_chart_dimension(shm_publish_aggregated[NETDATA_KEY_SHMGET_CALL].name, (long long)values->get);
  700. write_end_chart();
  701. write_begin_chart(type, NETDATA_SHMAT_CHART);
  702. write_chart_dimension(shm_publish_aggregated[NETDATA_KEY_SHMAT_CALL].name, (long long)values->at);
  703. write_end_chart();
  704. write_begin_chart(type, NETDATA_SHMDT_CHART);
  705. write_chart_dimension(shm_publish_aggregated[NETDATA_KEY_SHMDT_CALL].name, (long long)values->dt);
  706. write_end_chart();
  707. write_begin_chart(type, NETDATA_SHMCTL_CHART);
  708. write_chart_dimension(shm_publish_aggregated[NETDATA_KEY_SHMCTL_CALL].name, (long long)values->ctl);
  709. write_end_chart();
  710. }
  711. /**
  712. * Send data to Netdata calling auxiliary functions.
  713. *
  714. * @param update_every value to overwrite the update frequency set by the server.
  715. */
  716. void ebpf_shm_send_cgroup_data(int update_every)
  717. {
  718. if (!ebpf_cgroup_pids)
  719. return;
  720. pthread_mutex_lock(&mutex_cgroup_shm);
  721. ebpf_cgroup_target_t *ect;
  722. for (ect = ebpf_cgroup_pids; ect ; ect = ect->next) {
  723. ebpf_shm_sum_cgroup_pids(&ect->publish_shm, ect->pids);
  724. }
  725. int has_systemd = shm_ebpf_cgroup.header->systemd_enabled;
  726. if (has_systemd) {
  727. if (send_cgroup_chart) {
  728. ebpf_create_systemd_shm_charts(update_every);
  729. }
  730. ebpf_send_systemd_shm_charts();
  731. }
  732. for (ect = ebpf_cgroup_pids; ect ; ect = ect->next) {
  733. if (ect->systemd)
  734. continue;
  735. if (!(ect->flags & NETDATA_EBPF_CGROUP_HAS_SHM_CHART) && ect->updated) {
  736. ebpf_create_specific_shm_charts(ect->name, update_every);
  737. ect->flags |= NETDATA_EBPF_CGROUP_HAS_SHM_CHART;
  738. }
  739. if (ect->flags & NETDATA_EBPF_CGROUP_HAS_SHM_CHART) {
  740. if (ect->updated) {
  741. ebpf_send_specific_shm_data(ect->name, &ect->publish_shm);
  742. } else {
  743. ebpf_obsolete_specific_shm_charts(ect->name, update_every);
  744. ect->flags &= ~NETDATA_EBPF_CGROUP_HAS_SWAP_CHART;
  745. }
  746. }
  747. }
  748. pthread_mutex_unlock(&mutex_cgroup_shm);
  749. }
  750. /**
  751. * Main loop for this collector.
  752. */
  753. static void shm_collector(ebpf_module_t *em)
  754. {
  755. int cgroups = em->cgroup_charts;
  756. int update_every = em->update_every;
  757. heartbeat_t hb;
  758. heartbeat_init(&hb);
  759. int counter = update_every - 1;
  760. int maps_per_core = em->maps_per_core;
  761. while (!ebpf_exit_plugin) {
  762. (void)heartbeat_next(&hb, USEC_PER_SEC);
  763. if (ebpf_exit_plugin || ++counter != update_every)
  764. continue;
  765. counter = 0;
  766. netdata_apps_integration_flags_t apps = em->apps_charts;
  767. ebpf_shm_read_global_table(maps_per_core);
  768. pthread_mutex_lock(&collect_data_mutex);
  769. if (apps) {
  770. read_shm_apps_table(maps_per_core);
  771. }
  772. if (cgroups) {
  773. ebpf_update_shm_cgroup(maps_per_core);
  774. }
  775. pthread_mutex_lock(&lock);
  776. shm_send_global();
  777. if (apps & NETDATA_EBPF_APPS_FLAG_CHART_CREATED) {
  778. ebpf_shm_send_apps_data(apps_groups_root_target);
  779. }
  780. #ifdef NETDATA_DEV_MODE
  781. if (ebpf_aral_shm_pid)
  782. ebpf_send_data_aral_chart(ebpf_aral_shm_pid, em);
  783. #endif
  784. if (cgroups) {
  785. ebpf_shm_send_cgroup_data(update_every);
  786. }
  787. pthread_mutex_unlock(&lock);
  788. pthread_mutex_unlock(&collect_data_mutex);
  789. }
  790. }
  791. /*****************************************************************
  792. * INITIALIZE THREAD
  793. *****************************************************************/
  794. /**
  795. * Create apps charts
  796. *
  797. * Call ebpf_create_chart to create the charts on apps submenu.
  798. *
  799. * @param em a pointer to the structure with the default values.
  800. */
  801. void ebpf_shm_create_apps_charts(struct ebpf_module *em, void *ptr)
  802. {
  803. struct ebpf_target *root = ptr;
  804. ebpf_create_charts_on_apps(NETDATA_SHMGET_CHART,
  805. "Calls to syscall <code>shmget(2)</code>.",
  806. EBPF_COMMON_DIMENSION_CALL,
  807. NETDATA_APPS_IPC_SHM_GROUP,
  808. NETDATA_EBPF_CHART_TYPE_STACKED,
  809. 20191,
  810. ebpf_algorithms[NETDATA_EBPF_INCREMENTAL_IDX],
  811. root, em->update_every, NETDATA_EBPF_MODULE_NAME_SHM);
  812. ebpf_create_charts_on_apps(NETDATA_SHMAT_CHART,
  813. "Calls to syscall <code>shmat(2)</code>.",
  814. EBPF_COMMON_DIMENSION_CALL,
  815. NETDATA_APPS_IPC_SHM_GROUP,
  816. NETDATA_EBPF_CHART_TYPE_STACKED,
  817. 20192,
  818. ebpf_algorithms[NETDATA_EBPF_INCREMENTAL_IDX],
  819. root, em->update_every, NETDATA_EBPF_MODULE_NAME_SHM);
  820. ebpf_create_charts_on_apps(NETDATA_SHMDT_CHART,
  821. "Calls to syscall <code>shmdt(2)</code>.",
  822. EBPF_COMMON_DIMENSION_CALL,
  823. NETDATA_APPS_IPC_SHM_GROUP,
  824. NETDATA_EBPF_CHART_TYPE_STACKED,
  825. 20193,
  826. ebpf_algorithms[NETDATA_EBPF_INCREMENTAL_IDX],
  827. root, em->update_every, NETDATA_EBPF_MODULE_NAME_SHM);
  828. ebpf_create_charts_on_apps(NETDATA_SHMCTL_CHART,
  829. "Calls to syscall <code>shmctl(2)</code>.",
  830. EBPF_COMMON_DIMENSION_CALL,
  831. NETDATA_APPS_IPC_SHM_GROUP,
  832. NETDATA_EBPF_CHART_TYPE_STACKED,
  833. 20194,
  834. ebpf_algorithms[NETDATA_EBPF_INCREMENTAL_IDX],
  835. root, em->update_every, NETDATA_EBPF_MODULE_NAME_SHM);
  836. em->apps_charts |= NETDATA_EBPF_APPS_FLAG_CHART_CREATED;
  837. }
  838. /**
  839. * Allocate vectors used with this thread.
  840. *
  841. * We are not testing the return, because callocz does this and shutdown the software
  842. * case it was not possible to allocate.
  843. *
  844. * @param apps is apps enabled?
  845. */
  846. static void ebpf_shm_allocate_global_vectors(int apps)
  847. {
  848. if (apps) {
  849. ebpf_shm_aral_init();
  850. shm_pid = callocz((size_t)pid_max, sizeof(netdata_publish_shm_t *));
  851. shm_vector = callocz((size_t)ebpf_nprocs, sizeof(netdata_publish_shm_t));
  852. }
  853. shm_values = callocz((size_t)ebpf_nprocs, sizeof(netdata_idx_t));
  854. memset(shm_hash_values, 0, sizeof(shm_hash_values));
  855. }
  856. /*****************************************************************
  857. * MAIN THREAD
  858. *****************************************************************/
  859. /**
  860. * Create global charts
  861. *
  862. * Call ebpf_create_chart to create the charts for the collector.
  863. *
  864. * @param update_every value to overwrite the update frequency set by the server.
  865. */
  866. static void ebpf_create_shm_charts(int update_every)
  867. {
  868. ebpf_create_chart(
  869. NETDATA_EBPF_SYSTEM_GROUP,
  870. NETDATA_SHM_GLOBAL_CHART,
  871. "Calls to shared memory system calls",
  872. EBPF_COMMON_DIMENSION_CALL,
  873. NETDATA_SYSTEM_IPC_SHM_SUBMENU,
  874. NULL,
  875. NETDATA_EBPF_CHART_TYPE_LINE,
  876. NETDATA_CHART_PRIO_SYSTEM_IPC_SHARED_MEM_CALLS,
  877. ebpf_create_global_dimension,
  878. shm_publish_aggregated,
  879. NETDATA_SHM_END,
  880. update_every, NETDATA_EBPF_MODULE_NAME_SHM
  881. );
  882. fflush(stdout);
  883. }
  884. /*
  885. * Load BPF
  886. *
  887. * Load BPF files.
  888. *
  889. * @param em the structure with configuration
  890. */
  891. static int ebpf_shm_load_bpf(ebpf_module_t *em)
  892. {
  893. #ifdef LIBBPF_MAJOR_VERSION
  894. ebpf_define_map_type(em->maps, em->maps_per_core, running_on_kernel);
  895. #endif
  896. int ret = 0;
  897. ebpf_adjust_apps_cgroup(em, em->targets[NETDATA_KEY_SHMGET_CALL].mode);
  898. if (em->load & EBPF_LOAD_LEGACY) {
  899. em->probe_links = ebpf_load_program(ebpf_plugin_dir, em, running_on_kernel, isrh, &em->objects);
  900. if (!em->probe_links) {
  901. ret = -1;
  902. }
  903. }
  904. #ifdef LIBBPF_MAJOR_VERSION
  905. else {
  906. shm_bpf_obj = shm_bpf__open();
  907. if (!shm_bpf_obj)
  908. ret = -1;
  909. else
  910. ret = ebpf_shm_load_and_attach(shm_bpf_obj, em);
  911. }
  912. #endif
  913. if (ret)
  914. error("%s %s", EBPF_DEFAULT_ERROR_MSG, em->thread_name);
  915. return ret;
  916. }
  917. /**
  918. * Shared memory thread.
  919. *
  920. * @param ptr a pointer to `struct ebpf_module`
  921. * @return It always return NULL
  922. */
  923. void *ebpf_shm_thread(void *ptr)
  924. {
  925. netdata_thread_cleanup_push(ebpf_shm_exit, ptr);
  926. ebpf_module_t *em = (ebpf_module_t *)ptr;
  927. em->maps = shm_maps;
  928. ebpf_update_pid_table(&shm_maps[NETDATA_PID_SHM_TABLE], em);
  929. #ifdef LIBBPF_MAJOR_VERSION
  930. ebpf_adjust_thread_load(em, default_btf);
  931. #endif
  932. if (ebpf_shm_load_bpf(em)) {
  933. goto endshm;
  934. }
  935. ebpf_shm_allocate_global_vectors(em->apps_charts);
  936. int algorithms[NETDATA_SHM_END] = {
  937. NETDATA_EBPF_INCREMENTAL_IDX,
  938. NETDATA_EBPF_INCREMENTAL_IDX,
  939. NETDATA_EBPF_INCREMENTAL_IDX,
  940. NETDATA_EBPF_INCREMENTAL_IDX
  941. };
  942. ebpf_global_labels(
  943. shm_aggregated_data,
  944. shm_publish_aggregated,
  945. shm_dimension_name,
  946. shm_dimension_name,
  947. algorithms,
  948. NETDATA_SHM_END
  949. );
  950. pthread_mutex_lock(&lock);
  951. ebpf_create_shm_charts(em->update_every);
  952. ebpf_update_stats(&plugin_statistics, em);
  953. ebpf_update_kernel_memory_with_vector(&plugin_statistics, em->maps);
  954. #ifdef NETDATA_DEV_MODE
  955. if (ebpf_aral_shm_pid)
  956. ebpf_statistic_create_aral_chart(NETDATA_EBPF_SHM_ARAL_NAME, em);
  957. #endif
  958. pthread_mutex_unlock(&lock);
  959. shm_collector(em);
  960. endshm:
  961. ebpf_update_disabled_plugin_stats(em);
  962. netdata_thread_cleanup_pop(1);
  963. return NULL;
  964. }