ebpf_dcstat.c 49 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375
  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. netdata_dcstat_pid_t *dcstat_vector = NULL;
  8. static netdata_idx_t dcstat_hash_values[NETDATA_DCSTAT_IDX_END];
  9. static netdata_idx_t *dcstat_values = NULL;
  10. struct config dcstat_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. ebpf_local_maps_t dcstat_maps[] = {{.name = "dcstat_global", .internal_input = NETDATA_DIRECTORY_CACHE_END,
  16. .user_input = 0, .type = NETDATA_EBPF_MAP_STATIC,
  17. .map_fd = ND_EBPF_MAP_FD_NOT_INITIALIZED,
  18. #ifdef LIBBPF_MAJOR_VERSION
  19. .map_type = BPF_MAP_TYPE_PERCPU_ARRAY
  20. #endif
  21. },
  22. {.name = "dcstat_pid", .internal_input = ND_EBPF_DEFAULT_PID_SIZE,
  23. .user_input = 0,
  24. .type = NETDATA_EBPF_MAP_RESIZABLE | NETDATA_EBPF_MAP_PID,
  25. .map_fd = ND_EBPF_MAP_FD_NOT_INITIALIZED,
  26. #ifdef LIBBPF_MAJOR_VERSION
  27. .map_type = BPF_MAP_TYPE_PERCPU_HASH
  28. #endif
  29. },
  30. {.name = "dcstat_ctrl", .internal_input = NETDATA_CONTROLLER_END,
  31. .user_input = 0,
  32. .type = NETDATA_EBPF_MAP_CONTROLLER,
  33. .map_fd = ND_EBPF_MAP_FD_NOT_INITIALIZED,
  34. #ifdef LIBBPF_MAJOR_VERSION
  35. .map_type = BPF_MAP_TYPE_PERCPU_ARRAY
  36. #endif
  37. },
  38. {.name = NULL, .internal_input = 0, .user_input = 0,
  39. .type = NETDATA_EBPF_MAP_CONTROLLER,
  40. .map_fd = ND_EBPF_MAP_FD_NOT_INITIALIZED,
  41. #ifdef LIBBPF_MAJOR_VERSION
  42. .map_type = BPF_MAP_TYPE_PERCPU_ARRAY
  43. #endif
  44. }};
  45. static ebpf_specify_name_t dc_optional_name[] = { {.program_name = "netdata_lookup_fast",
  46. .function_to_attach = "lookup_fast",
  47. .optional = NULL,
  48. .retprobe = CONFIG_BOOLEAN_NO},
  49. {.program_name = NULL}};
  50. netdata_ebpf_targets_t dc_targets[] = { {.name = "lookup_fast", .mode = EBPF_LOAD_TRAMPOLINE},
  51. {.name = "d_lookup", .mode = EBPF_LOAD_TRAMPOLINE},
  52. {.name = NULL, .mode = EBPF_LOAD_TRAMPOLINE}};
  53. #ifdef NETDATA_DEV_MODE
  54. int dcstat_disable_priority;
  55. #endif
  56. #ifdef LIBBPF_MAJOR_VERSION
  57. /**
  58. * Disable probe
  59. *
  60. * Disable all probes to use exclusively another method.
  61. *
  62. * @param obj is the main structure for bpf objects
  63. */
  64. static inline void ebpf_dc_disable_probes(struct dc_bpf *obj)
  65. {
  66. bpf_program__set_autoload(obj->progs.netdata_lookup_fast_kprobe, false);
  67. bpf_program__set_autoload(obj->progs.netdata_d_lookup_kretprobe, false);
  68. bpf_program__set_autoload(obj->progs.netdata_dcstat_release_task_kprobe, false);
  69. }
  70. /*
  71. * Disable trampoline
  72. *
  73. * Disable all trampoline to use exclusively another method.
  74. *
  75. * @param obj is the main structure for bpf objects.
  76. */
  77. static inline void ebpf_dc_disable_trampoline(struct dc_bpf *obj)
  78. {
  79. bpf_program__set_autoload(obj->progs.netdata_lookup_fast_fentry, false);
  80. bpf_program__set_autoload(obj->progs.netdata_d_lookup_fexit, false);
  81. bpf_program__set_autoload(obj->progs.netdata_dcstat_release_task_fentry, false);
  82. }
  83. /**
  84. * Set trampoline target
  85. *
  86. * Set the targets we will monitor.
  87. *
  88. * @param obj is the main structure for bpf objects.
  89. */
  90. static void ebpf_dc_set_trampoline_target(struct dc_bpf *obj)
  91. {
  92. bpf_program__set_attach_target(obj->progs.netdata_lookup_fast_fentry, 0,
  93. dc_targets[NETDATA_DC_TARGET_LOOKUP_FAST].name);
  94. bpf_program__set_attach_target(obj->progs.netdata_d_lookup_fexit, 0,
  95. dc_targets[NETDATA_DC_TARGET_D_LOOKUP].name);
  96. bpf_program__set_attach_target(obj->progs.netdata_dcstat_release_task_fentry, 0,
  97. EBPF_COMMON_FNCT_CLEAN_UP);
  98. }
  99. /**
  100. * Mount Attach Probe
  101. *
  102. * Attach probes to target
  103. *
  104. * @param obj is the main structure for bpf objects.
  105. *
  106. * @return It returns 0 on success and -1 otherwise.
  107. */
  108. static int ebpf_dc_attach_probes(struct dc_bpf *obj)
  109. {
  110. obj->links.netdata_d_lookup_kretprobe = bpf_program__attach_kprobe(obj->progs.netdata_d_lookup_kretprobe,
  111. true,
  112. dc_targets[NETDATA_DC_TARGET_D_LOOKUP].name);
  113. int ret = libbpf_get_error(obj->links.netdata_d_lookup_kretprobe);
  114. if (ret)
  115. return -1;
  116. char *lookup_name = (dc_optional_name[NETDATA_DC_TARGET_LOOKUP_FAST].optional) ?
  117. dc_optional_name[NETDATA_DC_TARGET_LOOKUP_FAST].optional :
  118. dc_targets[NETDATA_DC_TARGET_LOOKUP_FAST].name ;
  119. obj->links.netdata_lookup_fast_kprobe = bpf_program__attach_kprobe(obj->progs.netdata_lookup_fast_kprobe,
  120. false,
  121. lookup_name);
  122. ret = libbpf_get_error(obj->links.netdata_lookup_fast_kprobe);
  123. if (ret)
  124. return -1;
  125. obj->links.netdata_dcstat_release_task_kprobe = bpf_program__attach_kprobe(obj->progs.netdata_dcstat_release_task_kprobe,
  126. false,
  127. EBPF_COMMON_FNCT_CLEAN_UP);
  128. ret = libbpf_get_error(obj->links.netdata_dcstat_release_task_kprobe);
  129. if (ret)
  130. return -1;
  131. return 0;
  132. }
  133. /**
  134. * Adjust Map Size
  135. *
  136. * Resize maps according input from users.
  137. *
  138. * @param obj is the main structure for bpf objects.
  139. * @param em structure with configuration
  140. */
  141. static void ebpf_dc_adjust_map(struct dc_bpf *obj, ebpf_module_t *em)
  142. {
  143. ebpf_update_map_size(obj->maps.dcstat_pid, &dcstat_maps[NETDATA_DCSTAT_PID_STATS],
  144. em, bpf_map__name(obj->maps.dcstat_pid));
  145. ebpf_update_map_type(obj->maps.dcstat_global, &dcstat_maps[NETDATA_DCSTAT_GLOBAL_STATS]);
  146. ebpf_update_map_type(obj->maps.dcstat_pid, &dcstat_maps[NETDATA_DCSTAT_PID_STATS]);
  147. ebpf_update_map_type(obj->maps.dcstat_ctrl, &dcstat_maps[NETDATA_DCSTAT_CTRL]);
  148. }
  149. /**
  150. * Set hash tables
  151. *
  152. * Set the values for maps according the value given by kernel.
  153. *
  154. * @param obj is the main structure for bpf objects.
  155. */
  156. static void ebpf_dc_set_hash_tables(struct dc_bpf *obj)
  157. {
  158. dcstat_maps[NETDATA_DCSTAT_GLOBAL_STATS].map_fd = bpf_map__fd(obj->maps.dcstat_global);
  159. dcstat_maps[NETDATA_DCSTAT_PID_STATS].map_fd = bpf_map__fd(obj->maps.dcstat_pid);
  160. dcstat_maps[NETDATA_DCSTAT_CTRL].map_fd = bpf_map__fd(obj->maps.dcstat_ctrl);
  161. }
  162. /**
  163. * Update Load
  164. *
  165. * For directory cache, some distributions change the function name, and we do not have condition to use
  166. * TRAMPOLINE like other functions.
  167. *
  168. * @param em structure with configuration
  169. *
  170. * @return When then symbols were not modified, it returns TRAMPOLINE, else it returns RETPROBE.
  171. */
  172. netdata_ebpf_program_loaded_t ebpf_dc_update_load(ebpf_module_t *em)
  173. {
  174. if (!strcmp(dc_optional_name[NETDATA_DC_TARGET_LOOKUP_FAST].optional,
  175. dc_optional_name[NETDATA_DC_TARGET_LOOKUP_FAST].function_to_attach))
  176. return EBPF_LOAD_TRAMPOLINE;
  177. if (em->targets[NETDATA_DC_TARGET_LOOKUP_FAST].mode != EBPF_LOAD_RETPROBE)
  178. netdata_log_info("When your kernel was compiled the symbol %s was modified, instead to use `trampoline`, the plugin will use `probes`.",
  179. dc_optional_name[NETDATA_DC_TARGET_LOOKUP_FAST].function_to_attach);
  180. return EBPF_LOAD_RETPROBE;
  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_dc_disable_release_task(struct dc_bpf *obj)
  190. {
  191. bpf_program__set_autoload(obj->progs.netdata_dcstat_release_task_kprobe, false);
  192. bpf_program__set_autoload(obj->progs.netdata_dcstat_release_task_fentry, false);
  193. }
  194. /**
  195. * Load and attach
  196. *
  197. * Load and attach the eBPF code in kernel.
  198. *
  199. * @param obj is the main structure for bpf objects.
  200. * @param em structure with configuration
  201. *
  202. * @return it returns 0 on success and -1 otherwise
  203. */
  204. static inline int ebpf_dc_load_and_attach(struct dc_bpf *obj, ebpf_module_t *em)
  205. {
  206. netdata_ebpf_program_loaded_t test = ebpf_dc_update_load(em);
  207. if (test == EBPF_LOAD_TRAMPOLINE) {
  208. ebpf_dc_disable_probes(obj);
  209. ebpf_dc_set_trampoline_target(obj);
  210. } else {
  211. ebpf_dc_disable_trampoline(obj);
  212. }
  213. ebpf_dc_adjust_map(obj, em);
  214. if (!em->apps_charts && !em->cgroup_charts)
  215. ebpf_dc_disable_release_task(obj);
  216. int ret = dc_bpf__load(obj);
  217. if (ret) {
  218. return ret;
  219. }
  220. ret = (test == EBPF_LOAD_TRAMPOLINE) ? dc_bpf__attach(obj) : ebpf_dc_attach_probes(obj);
  221. if (!ret) {
  222. ebpf_dc_set_hash_tables(obj);
  223. ebpf_update_controller(dcstat_maps[NETDATA_DCSTAT_CTRL].map_fd, em);
  224. }
  225. return ret;
  226. }
  227. #endif
  228. /*****************************************************************
  229. *
  230. * COMMON FUNCTIONS
  231. *
  232. *****************************************************************/
  233. /**
  234. * Update publish
  235. *
  236. * Update publish values before to write dimension.
  237. *
  238. * @param out structure that will receive data.
  239. * @param cache_access number of access to directory cache.
  240. * @param not_found number of files not found on the file system
  241. */
  242. void dcstat_update_publish(netdata_publish_dcstat_t *out, uint64_t cache_access, uint64_t not_found)
  243. {
  244. NETDATA_DOUBLE successful_access = (NETDATA_DOUBLE) (((long long)cache_access) - ((long long)not_found));
  245. NETDATA_DOUBLE ratio = (cache_access) ? successful_access/(NETDATA_DOUBLE)cache_access : 0;
  246. out->ratio = (long long )(ratio*100);
  247. }
  248. /*****************************************************************
  249. *
  250. * FUNCTIONS TO CLOSE THE THREAD
  251. *
  252. *****************************************************************/
  253. static void ebpf_obsolete_specific_dc_charts(char *type, int update_every);
  254. /**
  255. * Obsolete services
  256. *
  257. * Obsolete all service charts created
  258. *
  259. * @param em a pointer to `struct ebpf_module`
  260. */
  261. static void ebpf_obsolete_dc_services(ebpf_module_t *em)
  262. {
  263. ebpf_write_chart_obsolete(NETDATA_SERVICE_FAMILY,
  264. NETDATA_DC_HIT_CHART,
  265. "Percentage of files inside directory cache",
  266. EBPF_COMMON_DIMENSION_PERCENTAGE,
  267. NETDATA_DIRECTORY_CACHE_SUBMENU,
  268. NETDATA_EBPF_CHART_TYPE_LINE,
  269. NETDATA_SYSTEMD_DC_HIT_RATIO_CONTEXT,
  270. 21200,
  271. em->update_every);
  272. ebpf_write_chart_obsolete(NETDATA_SERVICE_FAMILY,
  273. NETDATA_DC_REFERENCE_CHART,
  274. "Count file access",
  275. EBPF_COMMON_DIMENSION_FILES,
  276. NETDATA_DIRECTORY_CACHE_SUBMENU,
  277. NETDATA_EBPF_CHART_TYPE_LINE,
  278. NETDATA_SYSTEMD_DC_REFERENCE_CONTEXT,
  279. 21201,
  280. em->update_every);
  281. ebpf_write_chart_obsolete(NETDATA_SERVICE_FAMILY,
  282. NETDATA_DC_REQUEST_NOT_CACHE_CHART,
  283. "Files not present inside directory cache",
  284. EBPF_COMMON_DIMENSION_FILES,
  285. NETDATA_DIRECTORY_CACHE_SUBMENU,
  286. NETDATA_EBPF_CHART_TYPE_LINE,
  287. NETDATA_SYSTEMD_DC_NOT_CACHE_CONTEXT,
  288. 21202,
  289. em->update_every);
  290. ebpf_write_chart_obsolete(NETDATA_SERVICE_FAMILY,
  291. NETDATA_DC_REQUEST_NOT_FOUND_CHART,
  292. "Files not found",
  293. EBPF_COMMON_DIMENSION_FILES,
  294. NETDATA_DIRECTORY_CACHE_SUBMENU,
  295. NETDATA_EBPF_CHART_TYPE_LINE,
  296. NETDATA_SYSTEMD_DC_NOT_FOUND_CONTEXT,
  297. 21202,
  298. em->update_every);
  299. }
  300. /**
  301. * Obsolete cgroup chart
  302. *
  303. * Send obsolete for all charts created before to close.
  304. *
  305. * @param em a pointer to `struct ebpf_module`
  306. */
  307. static inline void ebpf_obsolete_dc_cgroup_charts(ebpf_module_t *em) {
  308. pthread_mutex_lock(&mutex_cgroup_shm);
  309. ebpf_obsolete_dc_services(em);
  310. ebpf_cgroup_target_t *ect;
  311. for (ect = ebpf_cgroup_pids; ect ; ect = ect->next) {
  312. if (ect->systemd)
  313. continue;
  314. ebpf_obsolete_specific_dc_charts(ect->name, em->update_every);
  315. }
  316. pthread_mutex_unlock(&mutex_cgroup_shm);
  317. }
  318. /**
  319. * Obsolette apps charts
  320. *
  321. * Obsolete apps charts.
  322. *
  323. * @param em a pointer to the structure with the default values.
  324. */
  325. void ebpf_obsolete_dc_apps_charts(struct ebpf_module *em)
  326. {
  327. ebpf_write_chart_obsolete(NETDATA_APPS_FAMILY,
  328. NETDATA_DC_HIT_CHART,
  329. "Percentage of files inside directory cache",
  330. EBPF_COMMON_DIMENSION_PERCENTAGE,
  331. NETDATA_DIRECTORY_CACHE_SUBMENU,
  332. NETDATA_EBPF_CHART_TYPE_LINE,
  333. NULL,
  334. 20100,
  335. em->update_every);
  336. ebpf_write_chart_obsolete(NETDATA_APPS_FAMILY,
  337. NETDATA_DC_REFERENCE_CHART,
  338. "Count file access",
  339. EBPF_COMMON_DIMENSION_FILES,
  340. NETDATA_DIRECTORY_CACHE_SUBMENU,
  341. NETDATA_EBPF_CHART_TYPE_STACKED,
  342. NULL,
  343. 20101,
  344. em->update_every);
  345. ebpf_write_chart_obsolete(NETDATA_APPS_FAMILY,
  346. NETDATA_DC_REQUEST_NOT_CACHE_CHART,
  347. "Files not present inside directory cache",
  348. EBPF_COMMON_DIMENSION_FILES,
  349. NETDATA_DIRECTORY_CACHE_SUBMENU,
  350. NETDATA_EBPF_CHART_TYPE_STACKED,
  351. NULL,
  352. 20102,
  353. em->update_every);
  354. ebpf_write_chart_obsolete(NETDATA_APPS_FAMILY,
  355. NETDATA_DC_REQUEST_NOT_FOUND_CHART,
  356. "Files not found",
  357. EBPF_COMMON_DIMENSION_FILES,
  358. NETDATA_DIRECTORY_CACHE_SUBMENU,
  359. NETDATA_EBPF_CHART_TYPE_STACKED,
  360. NULL,
  361. 20103,
  362. em->update_every);
  363. }
  364. /**
  365. * Obsolete global
  366. *
  367. * Obsolete global charts created by thread.
  368. *
  369. * @param em a pointer to `struct ebpf_module`
  370. */
  371. static void ebpf_obsolete_dc_global(ebpf_module_t *em)
  372. {
  373. ebpf_write_chart_obsolete(NETDATA_FILESYSTEM_FAMILY,
  374. NETDATA_DC_HIT_CHART,
  375. "Percentage of files inside directory cache",
  376. EBPF_COMMON_DIMENSION_PERCENTAGE,
  377. NETDATA_DIRECTORY_CACHE_SUBMENU,
  378. NETDATA_EBPF_CHART_TYPE_LINE,
  379. NULL,
  380. 21200,
  381. em->update_every);
  382. ebpf_write_chart_obsolete(NETDATA_FILESYSTEM_FAMILY,
  383. NETDATA_DC_REFERENCE_CHART,
  384. "Variables used to calculate hit ratio.",
  385. EBPF_COMMON_DIMENSION_FILES,
  386. NETDATA_DIRECTORY_CACHE_SUBMENU,
  387. NETDATA_EBPF_CHART_TYPE_LINE,
  388. NULL,
  389. 21201,
  390. em->update_every);
  391. }
  392. /**
  393. * DCstat exit
  394. *
  395. * Cancel child and exit.
  396. *
  397. * @param ptr thread data.
  398. */
  399. static void ebpf_dcstat_exit(void *ptr)
  400. {
  401. ebpf_module_t *em = (ebpf_module_t *)ptr;
  402. if (em->enabled == NETDATA_THREAD_EBPF_FUNCTION_RUNNING) {
  403. pthread_mutex_lock(&lock);
  404. if (em->cgroup_charts) {
  405. ebpf_obsolete_dc_cgroup_charts(em);
  406. fflush(stdout);
  407. }
  408. if (em->apps_charts & NETDATA_EBPF_APPS_FLAG_CHART_CREATED) {
  409. ebpf_obsolete_dc_apps_charts(em);
  410. }
  411. ebpf_obsolete_dc_global(em);
  412. #ifdef NETDATA_DEV_MODE
  413. if (ebpf_aral_dcstat_pid)
  414. ebpf_statistic_obsolete_aral_chart(em, dcstat_disable_priority);
  415. #endif
  416. fflush(stdout);
  417. pthread_mutex_unlock(&lock);
  418. }
  419. ebpf_update_kernel_memory_with_vector(&plugin_statistics, em->maps, EBPF_ACTION_STAT_REMOVE);
  420. #ifdef LIBBPF_MAJOR_VERSION
  421. if (dc_bpf_obj) {
  422. dc_bpf__destroy(dc_bpf_obj);
  423. dc_bpf_obj = NULL;
  424. }
  425. #endif
  426. if (em->objects){
  427. ebpf_unload_legacy_code(em->objects, em->probe_links);
  428. em->objects = NULL;
  429. em->probe_links = NULL;
  430. }
  431. pthread_mutex_lock(&ebpf_exit_cleanup);
  432. em->enabled = NETDATA_THREAD_EBPF_STOPPED;
  433. ebpf_update_stats(&plugin_statistics, em);
  434. pthread_mutex_unlock(&ebpf_exit_cleanup);
  435. }
  436. /*****************************************************************
  437. *
  438. * APPS
  439. *
  440. *****************************************************************/
  441. /**
  442. * Create apps charts
  443. *
  444. * Call ebpf_create_chart to create the charts on apps submenu.
  445. *
  446. * @param em a pointer to the structure with the default values.
  447. */
  448. void ebpf_dcstat_create_apps_charts(struct ebpf_module *em, void *ptr)
  449. {
  450. struct ebpf_target *root = ptr;
  451. ebpf_create_charts_on_apps(NETDATA_DC_HIT_CHART,
  452. "Percentage of files inside directory cache",
  453. EBPF_COMMON_DIMENSION_PERCENTAGE,
  454. NETDATA_DIRECTORY_CACHE_SUBMENU,
  455. NETDATA_EBPF_CHART_TYPE_LINE,
  456. 20100,
  457. ebpf_algorithms[NETDATA_EBPF_ABSOLUTE_IDX],
  458. root, em->update_every, NETDATA_EBPF_MODULE_NAME_DCSTAT);
  459. ebpf_create_charts_on_apps(NETDATA_DC_REFERENCE_CHART,
  460. "Count file access",
  461. EBPF_COMMON_DIMENSION_FILES,
  462. NETDATA_DIRECTORY_CACHE_SUBMENU,
  463. NETDATA_EBPF_CHART_TYPE_STACKED,
  464. 20101,
  465. ebpf_algorithms[NETDATA_EBPF_ABSOLUTE_IDX],
  466. root, em->update_every, NETDATA_EBPF_MODULE_NAME_DCSTAT);
  467. ebpf_create_charts_on_apps(NETDATA_DC_REQUEST_NOT_CACHE_CHART,
  468. "Files not present inside directory cache",
  469. EBPF_COMMON_DIMENSION_FILES,
  470. NETDATA_DIRECTORY_CACHE_SUBMENU,
  471. NETDATA_EBPF_CHART_TYPE_STACKED,
  472. 20102,
  473. ebpf_algorithms[NETDATA_EBPF_ABSOLUTE_IDX],
  474. root, em->update_every, NETDATA_EBPF_MODULE_NAME_DCSTAT);
  475. ebpf_create_charts_on_apps(NETDATA_DC_REQUEST_NOT_FOUND_CHART,
  476. "Files not found",
  477. EBPF_COMMON_DIMENSION_FILES,
  478. NETDATA_DIRECTORY_CACHE_SUBMENU,
  479. NETDATA_EBPF_CHART_TYPE_STACKED,
  480. 20103,
  481. ebpf_algorithms[NETDATA_EBPF_ABSOLUTE_IDX],
  482. root, em->update_every, NETDATA_EBPF_MODULE_NAME_DCSTAT);
  483. em->apps_charts |= NETDATA_EBPF_APPS_FLAG_CHART_CREATED;
  484. }
  485. /*****************************************************************
  486. *
  487. * MAIN LOOP
  488. *
  489. *****************************************************************/
  490. /**
  491. * Apps Accumulator
  492. *
  493. * Sum all values read from kernel and store in the first address.
  494. *
  495. * @param out the vector with read values.
  496. * @param maps_per_core do I need to read all cores?
  497. */
  498. static void dcstat_apps_accumulator(netdata_dcstat_pid_t *out, int maps_per_core)
  499. {
  500. int i, end = (maps_per_core) ? ebpf_nprocs : 1;
  501. netdata_dcstat_pid_t *total = &out[0];
  502. for (i = 1; i < end; i++) {
  503. netdata_dcstat_pid_t *w = &out[i];
  504. total->cache_access += w->cache_access;
  505. total->file_system += w->file_system;
  506. total->not_found += w->not_found;
  507. }
  508. }
  509. /**
  510. * Save PID values
  511. *
  512. * Save the current values inside the structure
  513. *
  514. * @param out vector used to plot charts
  515. * @param publish vector with values read from hash tables.
  516. */
  517. static inline void dcstat_save_pid_values(netdata_publish_dcstat_t *out, netdata_dcstat_pid_t *publish)
  518. {
  519. memcpy(&out->curr, &publish[0], sizeof(netdata_dcstat_pid_t));
  520. }
  521. /**
  522. * Fill PID
  523. *
  524. * Fill PID structures
  525. *
  526. * @param current_pid pid that we are collecting data
  527. * @param out values read from hash tables;
  528. */
  529. static void dcstat_fill_pid(uint32_t current_pid, netdata_dcstat_pid_t *publish)
  530. {
  531. netdata_publish_dcstat_t *curr = dcstat_pid[current_pid];
  532. if (!curr) {
  533. curr = ebpf_publish_dcstat_get();
  534. dcstat_pid[current_pid] = curr;
  535. }
  536. dcstat_save_pid_values(curr, publish);
  537. }
  538. /**
  539. * Read Directory Cache APPS table
  540. *
  541. * Read the apps table and store data inside the structure.
  542. *
  543. * @param maps_per_core do I need to read all cores?
  544. */
  545. static void read_dc_apps_table(int maps_per_core)
  546. {
  547. netdata_dcstat_pid_t *cv = dcstat_vector;
  548. uint32_t key;
  549. struct ebpf_pid_stat *pids = ebpf_root_of_pids;
  550. int fd = dcstat_maps[NETDATA_DCSTAT_PID_STATS].map_fd;
  551. size_t length = sizeof(netdata_dcstat_pid_t);
  552. if (maps_per_core)
  553. length *= ebpf_nprocs;
  554. while (pids) {
  555. key = pids->pid;
  556. if (bpf_map_lookup_elem(fd, &key, cv)) {
  557. pids = pids->next;
  558. continue;
  559. }
  560. dcstat_apps_accumulator(cv, maps_per_core);
  561. dcstat_fill_pid(key, cv);
  562. // We are cleaning to avoid passing data read from one process to other.
  563. memset(cv, 0, length);
  564. pids = pids->next;
  565. }
  566. }
  567. /**
  568. * Update cgroup
  569. *
  570. * Update cgroup data based in collected PID.
  571. *
  572. * @param maps_per_core do I need to read all cores?
  573. */
  574. static void ebpf_update_dc_cgroup(int maps_per_core)
  575. {
  576. netdata_dcstat_pid_t *cv = dcstat_vector;
  577. int fd = dcstat_maps[NETDATA_DCSTAT_PID_STATS].map_fd;
  578. size_t length = sizeof(netdata_dcstat_pid_t)*ebpf_nprocs;
  579. ebpf_cgroup_target_t *ect;
  580. pthread_mutex_lock(&mutex_cgroup_shm);
  581. for (ect = ebpf_cgroup_pids; ect; ect = ect->next) {
  582. struct pid_on_target2 *pids;
  583. for (pids = ect->pids; pids; pids = pids->next) {
  584. int pid = pids->pid;
  585. netdata_dcstat_pid_t *out = &pids->dc;
  586. if (likely(dcstat_pid) && dcstat_pid[pid]) {
  587. netdata_publish_dcstat_t *in = dcstat_pid[pid];
  588. memcpy(out, &in->curr, sizeof(netdata_dcstat_pid_t));
  589. } else {
  590. memset(cv, 0, length);
  591. if (bpf_map_lookup_elem(fd, &pid, cv)) {
  592. continue;
  593. }
  594. dcstat_apps_accumulator(cv, maps_per_core);
  595. memcpy(out, cv, sizeof(netdata_dcstat_pid_t));
  596. }
  597. }
  598. }
  599. pthread_mutex_unlock(&mutex_cgroup_shm);
  600. }
  601. /**
  602. * Read global table
  603. *
  604. * Read the table with number of calls for all functions
  605. *
  606. * @param maps_per_core do I need to read all cores?
  607. */
  608. static void ebpf_dc_read_global_table(int maps_per_core)
  609. {
  610. uint32_t idx;
  611. netdata_idx_t *val = dcstat_hash_values;
  612. netdata_idx_t *stored = dcstat_values;
  613. int fd = dcstat_maps[NETDATA_DCSTAT_GLOBAL_STATS].map_fd;
  614. for (idx = NETDATA_KEY_DC_REFERENCE; idx < NETDATA_DIRECTORY_CACHE_END; idx++) {
  615. if (!bpf_map_lookup_elem(fd, &idx, stored)) {
  616. int i;
  617. int end = (maps_per_core) ? ebpf_nprocs: 1;
  618. netdata_idx_t total = 0;
  619. for (i = 0; i < end; i++)
  620. total += stored[i];
  621. val[idx] = total;
  622. }
  623. }
  624. }
  625. /**
  626. * Cachestat sum PIDs
  627. *
  628. * Sum values for all PIDs associated to a group
  629. *
  630. * @param publish output structure.
  631. * @param root structure with listed IPs
  632. */
  633. void ebpf_dcstat_sum_pids(netdata_publish_dcstat_t *publish, struct ebpf_pid_on_target *root)
  634. {
  635. memset(&publish->curr, 0, sizeof(netdata_dcstat_pid_t));
  636. netdata_dcstat_pid_t *dst = &publish->curr;
  637. while (root) {
  638. int32_t pid = root->pid;
  639. netdata_publish_dcstat_t *w = dcstat_pid[pid];
  640. if (w) {
  641. netdata_dcstat_pid_t *src = &w->curr;
  642. dst->cache_access += src->cache_access;
  643. dst->file_system += src->file_system;
  644. dst->not_found += src->not_found;
  645. }
  646. root = root->next;
  647. }
  648. }
  649. /**
  650. * Send data to Netdata calling auxiliary functions.
  651. *
  652. * @param root the target list.
  653. */
  654. void ebpf_dcache_send_apps_data(struct ebpf_target *root)
  655. {
  656. struct ebpf_target *w;
  657. collected_number value;
  658. write_begin_chart(NETDATA_APPS_FAMILY, NETDATA_DC_HIT_CHART);
  659. for (w = root; w; w = w->next) {
  660. if (unlikely(w->exposed && w->processes)) {
  661. ebpf_dcstat_sum_pids(&w->dcstat, w->root_pid);
  662. uint64_t cache = w->dcstat.curr.cache_access;
  663. uint64_t not_found = w->dcstat.curr.not_found;
  664. dcstat_update_publish(&w->dcstat, cache, not_found);
  665. value = (collected_number) w->dcstat.ratio;
  666. write_chart_dimension(w->name, value);
  667. }
  668. }
  669. write_end_chart();
  670. write_begin_chart(NETDATA_APPS_FAMILY, NETDATA_DC_REFERENCE_CHART);
  671. for (w = root; w; w = w->next) {
  672. if (unlikely(w->exposed && w->processes)) {
  673. if (w->dcstat.curr.cache_access < w->dcstat.prev.cache_access) {
  674. w->dcstat.prev.cache_access = 0;
  675. }
  676. w->dcstat.cache_access = (long long)w->dcstat.curr.cache_access - (long long)w->dcstat.prev.cache_access;
  677. value = (collected_number) w->dcstat.cache_access;
  678. write_chart_dimension(w->name, value);
  679. w->dcstat.prev.cache_access = w->dcstat.curr.cache_access;
  680. }
  681. }
  682. write_end_chart();
  683. write_begin_chart(NETDATA_APPS_FAMILY, NETDATA_DC_REQUEST_NOT_CACHE_CHART);
  684. for (w = root; w; w = w->next) {
  685. if (unlikely(w->exposed && w->processes)) {
  686. if (w->dcstat.curr.file_system < w->dcstat.prev.file_system) {
  687. w->dcstat.prev.file_system = 0;
  688. }
  689. value = (collected_number) (!w->dcstat.cache_access) ? 0 :
  690. (long long )w->dcstat.curr.file_system - (long long)w->dcstat.prev.file_system;
  691. write_chart_dimension(w->name, value);
  692. w->dcstat.prev.file_system = w->dcstat.curr.file_system;
  693. }
  694. }
  695. write_end_chart();
  696. write_begin_chart(NETDATA_APPS_FAMILY, NETDATA_DC_REQUEST_NOT_FOUND_CHART);
  697. for (w = root; w; w = w->next) {
  698. if (unlikely(w->exposed && w->processes)) {
  699. if (w->dcstat.curr.not_found < w->dcstat.prev.not_found) {
  700. w->dcstat.prev.not_found = 0;
  701. }
  702. value = (collected_number) (!w->dcstat.cache_access) ? 0 :
  703. (long long)w->dcstat.curr.not_found - (long long)w->dcstat.prev.not_found;
  704. write_chart_dimension(w->name, value);
  705. w->dcstat.prev.not_found = w->dcstat.curr.not_found;
  706. }
  707. }
  708. write_end_chart();
  709. }
  710. /**
  711. * Send global
  712. *
  713. * Send global charts to Netdata
  714. */
  715. static void dcstat_send_global(netdata_publish_dcstat_t *publish)
  716. {
  717. dcstat_update_publish(publish, dcstat_hash_values[NETDATA_KEY_DC_REFERENCE],
  718. dcstat_hash_values[NETDATA_KEY_DC_MISS]);
  719. netdata_publish_syscall_t *ptr = dcstat_counter_publish_aggregated;
  720. netdata_idx_t value = dcstat_hash_values[NETDATA_KEY_DC_REFERENCE];
  721. if (value != ptr[NETDATA_DCSTAT_IDX_REFERENCE].pcall) {
  722. ptr[NETDATA_DCSTAT_IDX_REFERENCE].ncall = value - ptr[NETDATA_DCSTAT_IDX_REFERENCE].pcall;
  723. ptr[NETDATA_DCSTAT_IDX_REFERENCE].pcall = value;
  724. value = dcstat_hash_values[NETDATA_KEY_DC_SLOW];
  725. ptr[NETDATA_DCSTAT_IDX_SLOW].ncall = value - ptr[NETDATA_DCSTAT_IDX_SLOW].pcall;
  726. ptr[NETDATA_DCSTAT_IDX_SLOW].pcall = value;
  727. value = dcstat_hash_values[NETDATA_KEY_DC_MISS];
  728. ptr[NETDATA_DCSTAT_IDX_MISS].ncall = value - ptr[NETDATA_DCSTAT_IDX_MISS].pcall;
  729. ptr[NETDATA_DCSTAT_IDX_MISS].pcall = value;
  730. } else {
  731. ptr[NETDATA_DCSTAT_IDX_REFERENCE].ncall = 0;
  732. ptr[NETDATA_DCSTAT_IDX_SLOW].ncall = 0;
  733. ptr[NETDATA_DCSTAT_IDX_MISS].ncall = 0;
  734. }
  735. ebpf_one_dimension_write_charts(NETDATA_FILESYSTEM_FAMILY, NETDATA_DC_HIT_CHART,
  736. ptr[NETDATA_DCSTAT_IDX_RATIO].dimension, publish->ratio);
  737. write_count_chart(
  738. NETDATA_DC_REFERENCE_CHART, NETDATA_FILESYSTEM_FAMILY,
  739. &dcstat_counter_publish_aggregated[NETDATA_DCSTAT_IDX_REFERENCE], 3);
  740. }
  741. /**
  742. * Create specific directory cache charts
  743. *
  744. * Create charts for cgroup/application.
  745. *
  746. * @param type the chart type.
  747. * @param update_every value to overwrite the update frequency set by the server.
  748. */
  749. static void ebpf_create_specific_dc_charts(char *type, int update_every)
  750. {
  751. ebpf_create_chart(type, NETDATA_DC_HIT_CHART, "Percentage of files inside directory cache",
  752. EBPF_COMMON_DIMENSION_PERCENTAGE, NETDATA_DIRECTORY_CACHE_SUBMENU,
  753. NETDATA_CGROUP_DC_HIT_RATIO_CONTEXT, NETDATA_EBPF_CHART_TYPE_LINE,
  754. NETDATA_CHART_PRIO_CGROUPS_CONTAINERS + 5700,
  755. ebpf_create_global_dimension,
  756. dcstat_counter_publish_aggregated, 1, update_every, NETDATA_EBPF_MODULE_NAME_DCSTAT);
  757. ebpf_create_chart(type, NETDATA_DC_REFERENCE_CHART, "Count file access",
  758. EBPF_COMMON_DIMENSION_FILES, NETDATA_DIRECTORY_CACHE_SUBMENU,
  759. NETDATA_CGROUP_DC_REFERENCE_CONTEXT, NETDATA_EBPF_CHART_TYPE_LINE,
  760. NETDATA_CHART_PRIO_CGROUPS_CONTAINERS + 5701,
  761. ebpf_create_global_dimension,
  762. &dcstat_counter_publish_aggregated[NETDATA_DCSTAT_IDX_REFERENCE], 1,
  763. update_every, NETDATA_EBPF_MODULE_NAME_DCSTAT);
  764. ebpf_create_chart(type, NETDATA_DC_REQUEST_NOT_CACHE_CHART,
  765. "Files not present inside directory cache",
  766. EBPF_COMMON_DIMENSION_FILES, NETDATA_DIRECTORY_CACHE_SUBMENU,
  767. NETDATA_CGROUP_DC_NOT_CACHE_CONTEXT, NETDATA_EBPF_CHART_TYPE_LINE,
  768. NETDATA_CHART_PRIO_CGROUPS_CONTAINERS + 5702,
  769. ebpf_create_global_dimension,
  770. &dcstat_counter_publish_aggregated[NETDATA_DCSTAT_IDX_SLOW], 1,
  771. update_every, NETDATA_EBPF_MODULE_NAME_DCSTAT);
  772. ebpf_create_chart(type, NETDATA_DC_REQUEST_NOT_FOUND_CHART,
  773. "Files not found",
  774. EBPF_COMMON_DIMENSION_FILES, NETDATA_DIRECTORY_CACHE_SUBMENU,
  775. NETDATA_CGROUP_DC_NOT_FOUND_CONTEXT, NETDATA_EBPF_CHART_TYPE_LINE,
  776. NETDATA_CHART_PRIO_CGROUPS_CONTAINERS + 5703,
  777. ebpf_create_global_dimension,
  778. &dcstat_counter_publish_aggregated[NETDATA_DCSTAT_IDX_MISS], 1,
  779. update_every, NETDATA_EBPF_MODULE_NAME_DCSTAT);
  780. }
  781. /**
  782. * Obsolete specific directory cache charts
  783. *
  784. * Obsolete charts for cgroup/application.
  785. *
  786. * @param type the chart type.
  787. * @param update_every value to overwrite the update frequency set by the server.
  788. */
  789. static void ebpf_obsolete_specific_dc_charts(char *type, int update_every)
  790. {
  791. ebpf_write_chart_obsolete(type, NETDATA_DC_HIT_CHART,
  792. "Percentage of files inside directory cache",
  793. EBPF_COMMON_DIMENSION_PERCENTAGE, NETDATA_DIRECTORY_CACHE_SUBMENU,
  794. NETDATA_EBPF_CHART_TYPE_LINE, NETDATA_CGROUP_DC_HIT_RATIO_CONTEXT,
  795. NETDATA_CHART_PRIO_CGROUPS_CONTAINERS + 5700, update_every);
  796. ebpf_write_chart_obsolete(type, NETDATA_DC_REFERENCE_CHART,
  797. "Count file access",
  798. EBPF_COMMON_DIMENSION_FILES, NETDATA_DIRECTORY_CACHE_SUBMENU,
  799. NETDATA_EBPF_CHART_TYPE_LINE, NETDATA_CGROUP_DC_REFERENCE_CONTEXT,
  800. NETDATA_CHART_PRIO_CGROUPS_CONTAINERS + 5701, update_every);
  801. ebpf_write_chart_obsolete(type, NETDATA_DC_REQUEST_NOT_CACHE_CHART,
  802. "Files not present inside directory cache",
  803. EBPF_COMMON_DIMENSION_FILES, NETDATA_DIRECTORY_CACHE_SUBMENU,
  804. NETDATA_EBPF_CHART_TYPE_LINE, NETDATA_CGROUP_DC_NOT_CACHE_CONTEXT,
  805. NETDATA_CHART_PRIO_CGROUPS_CONTAINERS + 5702, update_every);
  806. ebpf_write_chart_obsolete(type, NETDATA_DC_REQUEST_NOT_FOUND_CHART,
  807. "Files not found",
  808. EBPF_COMMON_DIMENSION_FILES, NETDATA_DIRECTORY_CACHE_SUBMENU,
  809. NETDATA_EBPF_CHART_TYPE_LINE, NETDATA_CGROUP_DC_NOT_FOUND_CONTEXT,
  810. NETDATA_CHART_PRIO_CGROUPS_CONTAINERS + 5703, update_every);
  811. }
  812. /**
  813. * Cachestat sum PIDs
  814. *
  815. * Sum values for all PIDs associated to a group
  816. *
  817. * @param publish output structure.
  818. * @param root structure with listed IPs
  819. */
  820. void ebpf_dc_sum_cgroup_pids(netdata_publish_dcstat_t *publish, struct pid_on_target2 *root)
  821. {
  822. memset(&publish->curr, 0, sizeof(netdata_dcstat_pid_t));
  823. netdata_dcstat_pid_t *dst = &publish->curr;
  824. while (root) {
  825. netdata_dcstat_pid_t *src = &root->dc;
  826. dst->cache_access += src->cache_access;
  827. dst->file_system += src->file_system;
  828. dst->not_found += src->not_found;
  829. root = root->next;
  830. }
  831. }
  832. /**
  833. * Calc chart values
  834. *
  835. * Do necessary math to plot charts.
  836. */
  837. void ebpf_dc_calc_chart_values()
  838. {
  839. ebpf_cgroup_target_t *ect;
  840. for (ect = ebpf_cgroup_pids; ect ; ect = ect->next) {
  841. ebpf_dc_sum_cgroup_pids(&ect->publish_dc, ect->pids);
  842. uint64_t cache = ect->publish_dc.curr.cache_access;
  843. uint64_t not_found = ect->publish_dc.curr.not_found;
  844. dcstat_update_publish(&ect->publish_dc, cache, not_found);
  845. ect->publish_dc.cache_access = (long long)ect->publish_dc.curr.cache_access -
  846. (long long)ect->publish_dc.prev.cache_access;
  847. ect->publish_dc.prev.cache_access = ect->publish_dc.curr.cache_access;
  848. if (ect->publish_dc.curr.not_found < ect->publish_dc.prev.not_found) {
  849. ect->publish_dc.prev.not_found = 0;
  850. }
  851. }
  852. }
  853. /**
  854. * Create Systemd directory cache Charts
  855. *
  856. * Create charts when systemd is enabled
  857. *
  858. * @param update_every value to overwrite the update frequency set by the server.
  859. **/
  860. static void ebpf_create_systemd_dc_charts(int update_every)
  861. {
  862. ebpf_create_charts_on_systemd(NETDATA_DC_HIT_CHART,
  863. "Percentage of files inside directory cache",
  864. EBPF_COMMON_DIMENSION_PERCENTAGE,
  865. NETDATA_DIRECTORY_CACHE_SUBMENU,
  866. NETDATA_EBPF_CHART_TYPE_LINE,
  867. 21200,
  868. ebpf_algorithms[NETDATA_EBPF_ABSOLUTE_IDX],
  869. NETDATA_SYSTEMD_DC_HIT_RATIO_CONTEXT, NETDATA_EBPF_MODULE_NAME_DCSTAT,
  870. update_every);
  871. ebpf_create_charts_on_systemd(NETDATA_DC_REFERENCE_CHART,
  872. "Count file access",
  873. EBPF_COMMON_DIMENSION_FILES,
  874. NETDATA_DIRECTORY_CACHE_SUBMENU,
  875. NETDATA_EBPF_CHART_TYPE_LINE,
  876. 21201,
  877. ebpf_algorithms[NETDATA_EBPF_ABSOLUTE_IDX],
  878. NETDATA_SYSTEMD_DC_REFERENCE_CONTEXT, NETDATA_EBPF_MODULE_NAME_DCSTAT,
  879. update_every);
  880. ebpf_create_charts_on_systemd(NETDATA_DC_REQUEST_NOT_CACHE_CHART,
  881. "Files not present inside directory cache",
  882. EBPF_COMMON_DIMENSION_FILES,
  883. NETDATA_DIRECTORY_CACHE_SUBMENU,
  884. NETDATA_EBPF_CHART_TYPE_LINE,
  885. 21202,
  886. ebpf_algorithms[NETDATA_EBPF_ABSOLUTE_IDX],
  887. NETDATA_SYSTEMD_DC_NOT_CACHE_CONTEXT, NETDATA_EBPF_MODULE_NAME_DCSTAT,
  888. update_every);
  889. ebpf_create_charts_on_systemd(NETDATA_DC_REQUEST_NOT_FOUND_CHART,
  890. "Files not found",
  891. EBPF_COMMON_DIMENSION_FILES,
  892. NETDATA_DIRECTORY_CACHE_SUBMENU,
  893. NETDATA_EBPF_CHART_TYPE_LINE,
  894. 21202,
  895. ebpf_algorithms[NETDATA_EBPF_ABSOLUTE_IDX],
  896. NETDATA_SYSTEMD_DC_NOT_FOUND_CONTEXT, NETDATA_EBPF_MODULE_NAME_DCSTAT,
  897. update_every);
  898. }
  899. /**
  900. * Send Directory Cache charts
  901. *
  902. * Send collected data to Netdata.
  903. */
  904. static void ebpf_send_systemd_dc_charts()
  905. {
  906. collected_number value;
  907. ebpf_cgroup_target_t *ect;
  908. write_begin_chart(NETDATA_SERVICE_FAMILY, NETDATA_DC_HIT_CHART);
  909. for (ect = ebpf_cgroup_pids; ect ; ect = ect->next) {
  910. if (unlikely(ect->systemd) && unlikely(ect->updated)) {
  911. write_chart_dimension(ect->name, (long long) ect->publish_dc.ratio);
  912. }
  913. }
  914. write_end_chart();
  915. write_begin_chart(NETDATA_SERVICE_FAMILY, NETDATA_DC_REFERENCE_CHART);
  916. for (ect = ebpf_cgroup_pids; ect ; ect = ect->next) {
  917. if (unlikely(ect->systemd) && unlikely(ect->updated)) {
  918. write_chart_dimension(ect->name, (long long) ect->publish_dc.cache_access);
  919. }
  920. }
  921. write_end_chart();
  922. write_begin_chart(NETDATA_SERVICE_FAMILY, NETDATA_DC_REQUEST_NOT_CACHE_CHART);
  923. for (ect = ebpf_cgroup_pids; ect ; ect = ect->next) {
  924. if (unlikely(ect->systemd) && unlikely(ect->updated)) {
  925. value = (collected_number) (!ect->publish_dc.cache_access) ? 0 :
  926. (long long )ect->publish_dc.curr.file_system - (long long)ect->publish_dc.prev.file_system;
  927. ect->publish_dc.prev.file_system = ect->publish_dc.curr.file_system;
  928. write_chart_dimension(ect->name, (long long) value);
  929. }
  930. }
  931. write_end_chart();
  932. write_begin_chart(NETDATA_SERVICE_FAMILY, NETDATA_DC_REQUEST_NOT_FOUND_CHART);
  933. for (ect = ebpf_cgroup_pids; ect ; ect = ect->next) {
  934. if (unlikely(ect->systemd) && unlikely(ect->updated)) {
  935. value = (collected_number) (!ect->publish_dc.cache_access) ? 0 :
  936. (long long)ect->publish_dc.curr.not_found - (long long)ect->publish_dc.prev.not_found;
  937. ect->publish_dc.prev.not_found = ect->publish_dc.curr.not_found;
  938. write_chart_dimension(ect->name, (long long) value);
  939. }
  940. }
  941. write_end_chart();
  942. }
  943. /**
  944. * Send Directory Cache charts
  945. *
  946. * Send collected data to Netdata.
  947. *
  948. */
  949. static void ebpf_send_specific_dc_data(char *type, netdata_publish_dcstat_t *pdc)
  950. {
  951. collected_number value;
  952. write_begin_chart(type, NETDATA_DC_HIT_CHART);
  953. write_chart_dimension(dcstat_counter_publish_aggregated[NETDATA_DCSTAT_IDX_RATIO].name,
  954. (long long) pdc->ratio);
  955. write_end_chart();
  956. write_begin_chart(type, NETDATA_DC_REFERENCE_CHART);
  957. write_chart_dimension(dcstat_counter_publish_aggregated[NETDATA_DCSTAT_IDX_REFERENCE].name,
  958. (long long) pdc->cache_access);
  959. write_end_chart();
  960. value = (collected_number) (!pdc->cache_access) ? 0 :
  961. (long long )pdc->curr.file_system - (long long)pdc->prev.file_system;
  962. pdc->prev.file_system = pdc->curr.file_system;
  963. write_begin_chart(type, NETDATA_DC_REQUEST_NOT_CACHE_CHART);
  964. write_chart_dimension(dcstat_counter_publish_aggregated[NETDATA_DCSTAT_IDX_SLOW].name, (long long) value);
  965. write_end_chart();
  966. value = (collected_number) (!pdc->cache_access) ? 0 :
  967. (long long)pdc->curr.not_found - (long long)pdc->prev.not_found;
  968. pdc->prev.not_found = pdc->curr.not_found;
  969. write_begin_chart(type, NETDATA_DC_REQUEST_NOT_FOUND_CHART);
  970. write_chart_dimension(dcstat_counter_publish_aggregated[NETDATA_DCSTAT_IDX_MISS].name, (long long) value);
  971. write_end_chart();
  972. }
  973. /**
  974. * Send data to Netdata calling auxiliary functions.
  975. *
  976. * @param update_every value to overwrite the update frequency set by the server.
  977. */
  978. void ebpf_dc_send_cgroup_data(int update_every)
  979. {
  980. if (!ebpf_cgroup_pids)
  981. return;
  982. pthread_mutex_lock(&mutex_cgroup_shm);
  983. ebpf_cgroup_target_t *ect;
  984. ebpf_dc_calc_chart_values();
  985. int has_systemd = shm_ebpf_cgroup.header->systemd_enabled;
  986. if (has_systemd) {
  987. if (send_cgroup_chart) {
  988. ebpf_create_systemd_dc_charts(update_every);
  989. }
  990. ebpf_send_systemd_dc_charts();
  991. }
  992. for (ect = ebpf_cgroup_pids; ect ; ect = ect->next) {
  993. if (ect->systemd)
  994. continue;
  995. if (!(ect->flags & NETDATA_EBPF_CGROUP_HAS_DC_CHART) && ect->updated) {
  996. ebpf_create_specific_dc_charts(ect->name, update_every);
  997. ect->flags |= NETDATA_EBPF_CGROUP_HAS_DC_CHART;
  998. }
  999. if (ect->flags & NETDATA_EBPF_CGROUP_HAS_DC_CHART) {
  1000. if (ect->updated) {
  1001. ebpf_send_specific_dc_data(ect->name, &ect->publish_dc);
  1002. } else {
  1003. ebpf_obsolete_specific_dc_charts(ect->name, update_every);
  1004. ect->flags &= ~NETDATA_EBPF_CGROUP_HAS_DC_CHART;
  1005. }
  1006. }
  1007. }
  1008. pthread_mutex_unlock(&mutex_cgroup_shm);
  1009. }
  1010. /**
  1011. * Main loop for this collector.
  1012. */
  1013. static void dcstat_collector(ebpf_module_t *em)
  1014. {
  1015. netdata_publish_dcstat_t publish;
  1016. memset(&publish, 0, sizeof(publish));
  1017. int cgroups = em->cgroup_charts;
  1018. int update_every = em->update_every;
  1019. heartbeat_t hb;
  1020. heartbeat_init(&hb);
  1021. int counter = update_every - 1;
  1022. int maps_per_core = em->maps_per_core;
  1023. uint32_t running_time = 0;
  1024. uint32_t lifetime = em->lifetime;
  1025. while (!ebpf_exit_plugin && running_time < lifetime) {
  1026. (void)heartbeat_next(&hb, USEC_PER_SEC);
  1027. if (ebpf_exit_plugin || ++counter != update_every)
  1028. continue;
  1029. counter = 0;
  1030. netdata_apps_integration_flags_t apps = em->apps_charts;
  1031. ebpf_dc_read_global_table(maps_per_core);
  1032. pthread_mutex_lock(&collect_data_mutex);
  1033. if (apps)
  1034. read_dc_apps_table(maps_per_core);
  1035. if (cgroups)
  1036. ebpf_update_dc_cgroup(maps_per_core);
  1037. pthread_mutex_lock(&lock);
  1038. dcstat_send_global(&publish);
  1039. if (apps & NETDATA_EBPF_APPS_FLAG_CHART_CREATED)
  1040. ebpf_dcache_send_apps_data(apps_groups_root_target);
  1041. #ifdef NETDATA_DEV_MODE
  1042. if (ebpf_aral_dcstat_pid)
  1043. ebpf_send_data_aral_chart(ebpf_aral_dcstat_pid, em);
  1044. #endif
  1045. if (cgroups)
  1046. ebpf_dc_send_cgroup_data(update_every);
  1047. pthread_mutex_unlock(&lock);
  1048. pthread_mutex_unlock(&collect_data_mutex);
  1049. pthread_mutex_lock(&ebpf_exit_cleanup);
  1050. if (running_time && !em->running_time)
  1051. running_time = update_every;
  1052. else
  1053. running_time += update_every;
  1054. em->running_time = running_time;
  1055. pthread_mutex_unlock(&ebpf_exit_cleanup);
  1056. }
  1057. }
  1058. /*****************************************************************
  1059. *
  1060. * INITIALIZE THREAD
  1061. *
  1062. *****************************************************************/
  1063. /**
  1064. * Create filesystem charts
  1065. *
  1066. * Call ebpf_create_chart to create the charts for the collector.
  1067. *
  1068. * @param update_every value to overwrite the update frequency set by the server.
  1069. */
  1070. static void ebpf_create_dc_global_charts(int update_every)
  1071. {
  1072. ebpf_create_chart(NETDATA_FILESYSTEM_FAMILY, NETDATA_DC_HIT_CHART,
  1073. "Percentage of files inside directory cache",
  1074. EBPF_COMMON_DIMENSION_PERCENTAGE, NETDATA_DIRECTORY_CACHE_SUBMENU,
  1075. NULL,
  1076. NETDATA_EBPF_CHART_TYPE_LINE,
  1077. 21200,
  1078. ebpf_create_global_dimension,
  1079. dcstat_counter_publish_aggregated, 1, update_every, NETDATA_EBPF_MODULE_NAME_DCSTAT);
  1080. ebpf_create_chart(NETDATA_FILESYSTEM_FAMILY, NETDATA_DC_REFERENCE_CHART,
  1081. "Variables used to calculate hit ratio.",
  1082. EBPF_COMMON_DIMENSION_FILES, NETDATA_DIRECTORY_CACHE_SUBMENU,
  1083. NULL,
  1084. NETDATA_EBPF_CHART_TYPE_LINE,
  1085. 21201,
  1086. ebpf_create_global_dimension,
  1087. &dcstat_counter_publish_aggregated[NETDATA_DCSTAT_IDX_REFERENCE], 3,
  1088. update_every, NETDATA_EBPF_MODULE_NAME_DCSTAT);
  1089. fflush(stdout);
  1090. }
  1091. /**
  1092. * Allocate vectors used with this thread.
  1093. *
  1094. * We are not testing the return, because callocz does this and shutdown the software
  1095. * case it was not possible to allocate.
  1096. *
  1097. * @param apps is apps enabled?
  1098. */
  1099. static void ebpf_dcstat_allocate_global_vectors(int apps)
  1100. {
  1101. if (apps) {
  1102. ebpf_dcstat_aral_init();
  1103. dcstat_pid = callocz((size_t)pid_max, sizeof(netdata_publish_dcstat_t *));
  1104. dcstat_vector = callocz((size_t)ebpf_nprocs, sizeof(netdata_dcstat_pid_t));
  1105. }
  1106. dcstat_values = callocz((size_t)ebpf_nprocs, sizeof(netdata_idx_t));
  1107. memset(dcstat_counter_aggregated_data, 0, NETDATA_DCSTAT_IDX_END * sizeof(netdata_syscall_stat_t));
  1108. memset(dcstat_counter_publish_aggregated, 0, NETDATA_DCSTAT_IDX_END * sizeof(netdata_publish_syscall_t));
  1109. }
  1110. /*****************************************************************
  1111. *
  1112. * MAIN THREAD
  1113. *
  1114. *****************************************************************/
  1115. /*
  1116. * Load BPF
  1117. *
  1118. * Load BPF files.
  1119. *
  1120. * @param em the structure with configuration
  1121. */
  1122. static int ebpf_dcstat_load_bpf(ebpf_module_t *em)
  1123. {
  1124. #ifdef LIBBPF_MAJOR_VERSION
  1125. ebpf_define_map_type(dcstat_maps, em->maps_per_core, running_on_kernel);
  1126. #endif
  1127. int ret = 0;
  1128. ebpf_adjust_apps_cgroup(em, em->targets[NETDATA_DC_TARGET_LOOKUP_FAST].mode);
  1129. if (em->load & EBPF_LOAD_LEGACY) {
  1130. em->probe_links = ebpf_load_program(ebpf_plugin_dir, em, running_on_kernel, isrh, &em->objects);
  1131. if (!em->probe_links) {
  1132. ret = -1;
  1133. }
  1134. }
  1135. #ifdef LIBBPF_MAJOR_VERSION
  1136. else {
  1137. dc_bpf_obj = dc_bpf__open();
  1138. if (!dc_bpf_obj)
  1139. ret = -1;
  1140. else
  1141. ret = ebpf_dc_load_and_attach(dc_bpf_obj, em);
  1142. }
  1143. #endif
  1144. if (ret)
  1145. netdata_log_error("%s %s", EBPF_DEFAULT_ERROR_MSG, em->thread_name);
  1146. return ret;
  1147. }
  1148. /**
  1149. * Directory Cache thread
  1150. *
  1151. * Thread used to make dcstat thread
  1152. *
  1153. * @param ptr a pointer to `struct ebpf_module`
  1154. *
  1155. * @return It always returns NULL
  1156. */
  1157. void *ebpf_dcstat_thread(void *ptr)
  1158. {
  1159. netdata_thread_cleanup_push(ebpf_dcstat_exit, ptr);
  1160. ebpf_module_t *em = (ebpf_module_t *)ptr;
  1161. em->maps = dcstat_maps;
  1162. ebpf_update_pid_table(&dcstat_maps[NETDATA_DCSTAT_PID_STATS], em);
  1163. ebpf_update_names(dc_optional_name, em);
  1164. #ifdef LIBBPF_MAJOR_VERSION
  1165. ebpf_adjust_thread_load(em, default_btf);
  1166. #endif
  1167. if (ebpf_dcstat_load_bpf(em)) {
  1168. goto enddcstat;
  1169. }
  1170. ebpf_dcstat_allocate_global_vectors(em->apps_charts);
  1171. int algorithms[NETDATA_DCSTAT_IDX_END] = {
  1172. NETDATA_EBPF_ABSOLUTE_IDX, NETDATA_EBPF_ABSOLUTE_IDX, NETDATA_EBPF_ABSOLUTE_IDX,
  1173. NETDATA_EBPF_ABSOLUTE_IDX
  1174. };
  1175. ebpf_global_labels(dcstat_counter_aggregated_data, dcstat_counter_publish_aggregated,
  1176. dcstat_counter_dimension_name, dcstat_counter_dimension_name,
  1177. algorithms, NETDATA_DCSTAT_IDX_END);
  1178. pthread_mutex_lock(&lock);
  1179. ebpf_create_dc_global_charts(em->update_every);
  1180. ebpf_update_stats(&plugin_statistics, em);
  1181. ebpf_update_kernel_memory_with_vector(&plugin_statistics, em->maps, EBPF_ACTION_STAT_ADD);
  1182. #ifdef NETDATA_DEV_MODE
  1183. if (ebpf_aral_dcstat_pid)
  1184. dcstat_disable_priority = ebpf_statistic_create_aral_chart(NETDATA_EBPF_DCSTAT_ARAL_NAME, em);
  1185. #endif
  1186. pthread_mutex_unlock(&lock);
  1187. dcstat_collector(em);
  1188. enddcstat:
  1189. ebpf_update_disabled_plugin_stats(em);
  1190. netdata_thread_cleanup_pop(1);
  1191. return NULL;
  1192. }