ebpf_cachestat.c 61 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591
  1. // SPDX-License-Identifier: GPL-3.0-or-later
  2. #include "ebpf.h"
  3. #include "ebpf_cachestat.h"
  4. static char *cachestat_counter_dimension_name[NETDATA_CACHESTAT_END] = { "ratio", "dirty", "hit",
  5. "miss" };
  6. static netdata_syscall_stat_t cachestat_counter_aggregated_data[NETDATA_CACHESTAT_END];
  7. static netdata_publish_syscall_t cachestat_counter_publish_aggregated[NETDATA_CACHESTAT_END];
  8. netdata_cachestat_pid_t *cachestat_vector = NULL;
  9. static netdata_idx_t cachestat_hash_values[NETDATA_CACHESTAT_END];
  10. static netdata_idx_t *cachestat_values = NULL;
  11. ebpf_local_maps_t cachestat_maps[] = {{.name = "cstat_global", .internal_input = NETDATA_CACHESTAT_END,
  12. .user_input = 0, .type = NETDATA_EBPF_MAP_STATIC,
  13. .map_fd = ND_EBPF_MAP_FD_NOT_INITIALIZED,
  14. #ifdef LIBBPF_MAJOR_VERSION
  15. .map_type = BPF_MAP_TYPE_PERCPU_ARRAY
  16. #endif
  17. },
  18. {.name = "cstat_pid", .internal_input = ND_EBPF_DEFAULT_PID_SIZE,
  19. .user_input = 0,
  20. .type = NETDATA_EBPF_MAP_RESIZABLE | NETDATA_EBPF_MAP_PID,
  21. .map_fd = ND_EBPF_MAP_FD_NOT_INITIALIZED,
  22. #ifdef LIBBPF_MAJOR_VERSION
  23. .map_type = BPF_MAP_TYPE_PERCPU_HASH
  24. #endif
  25. },
  26. {.name = "cstat_ctrl", .internal_input = NETDATA_CONTROLLER_END,
  27. .user_input = 0,
  28. .type = NETDATA_EBPF_MAP_CONTROLLER,
  29. .map_fd = ND_EBPF_MAP_FD_NOT_INITIALIZED,
  30. #ifdef LIBBPF_MAJOR_VERSION
  31. .map_type = BPF_MAP_TYPE_PERCPU_ARRAY
  32. #endif
  33. },
  34. {.name = NULL, .internal_input = 0, .user_input = 0,
  35. .type = NETDATA_EBPF_MAP_CONTROLLER,
  36. .map_fd = ND_EBPF_MAP_FD_NOT_INITIALIZED,
  37. #ifdef LIBBPF_MAJOR_VERSION
  38. #endif
  39. }};
  40. struct config cachestat_config = { .first_section = NULL,
  41. .last_section = NULL,
  42. .mutex = NETDATA_MUTEX_INITIALIZER,
  43. .index = { .avl_tree = { .root = NULL, .compar = appconfig_section_compare },
  44. .rwlock = AVL_LOCK_INITIALIZER } };
  45. netdata_ebpf_targets_t cachestat_targets[] = { {.name = "add_to_page_cache_lru", .mode = EBPF_LOAD_TRAMPOLINE},
  46. {.name = "mark_page_accessed", .mode = EBPF_LOAD_TRAMPOLINE},
  47. {.name = NULL, .mode = EBPF_LOAD_TRAMPOLINE},
  48. {.name = "mark_buffer_dirty", .mode = EBPF_LOAD_TRAMPOLINE},
  49. {.name = NULL, .mode = EBPF_LOAD_TRAMPOLINE}};
  50. static char *account_page[NETDATA_CACHESTAT_ACCOUNT_DIRTY_END] ={ "account_page_dirtied",
  51. "__set_page_dirty", "__folio_mark_dirty" };
  52. #ifdef NETDATA_DEV_MODE
  53. int cachestat_disable_priority;
  54. #endif
  55. #ifdef LIBBPF_MAJOR_VERSION
  56. /**
  57. * Disable probe
  58. *
  59. * Disable all probes to use exclusively another method.
  60. *
  61. * @param obj is the main structure for bpf objects
  62. */
  63. static void ebpf_cachestat_disable_probe(struct cachestat_bpf *obj)
  64. {
  65. bpf_program__set_autoload(obj->progs.netdata_add_to_page_cache_lru_kprobe, false);
  66. bpf_program__set_autoload(obj->progs.netdata_mark_page_accessed_kprobe, false);
  67. bpf_program__set_autoload(obj->progs.netdata_folio_mark_dirty_kprobe, false);
  68. bpf_program__set_autoload(obj->progs.netdata_set_page_dirty_kprobe, false);
  69. bpf_program__set_autoload(obj->progs.netdata_account_page_dirtied_kprobe, false);
  70. bpf_program__set_autoload(obj->progs.netdata_mark_buffer_dirty_kprobe, false);
  71. bpf_program__set_autoload(obj->progs.netdata_release_task_kprobe, false);
  72. }
  73. /*
  74. * Disable specific probe
  75. *
  76. * Disable probes according the kernel version
  77. *
  78. * @param obj is the main structure for bpf objects
  79. */
  80. static void ebpf_cachestat_disable_specific_probe(struct cachestat_bpf *obj)
  81. {
  82. if (!strcmp(cachestat_targets[NETDATA_KEY_CALLS_ACCOUNT_PAGE_DIRTIED].name,
  83. account_page[NETDATA_CACHESTAT_FOLIO_DIRTY])) {
  84. bpf_program__set_autoload(obj->progs.netdata_account_page_dirtied_kprobe, false);
  85. bpf_program__set_autoload(obj->progs.netdata_set_page_dirty_kprobe, false);
  86. } else if (!strcmp(cachestat_targets[NETDATA_KEY_CALLS_ACCOUNT_PAGE_DIRTIED].name,
  87. account_page[NETDATA_CACHESTAT_SET_PAGE_DIRTY])) {
  88. bpf_program__set_autoload(obj->progs.netdata_folio_mark_dirty_kprobe, false);
  89. bpf_program__set_autoload(obj->progs.netdata_account_page_dirtied_kprobe, false);
  90. } else {
  91. bpf_program__set_autoload(obj->progs.netdata_folio_mark_dirty_kprobe, false);
  92. bpf_program__set_autoload(obj->progs.netdata_set_page_dirty_kprobe, false);
  93. }
  94. }
  95. /*
  96. * Disable trampoline
  97. *
  98. * Disable all trampoline to use exclusively another method.
  99. *
  100. * @param obj is the main structure for bpf objects.
  101. */
  102. static void ebpf_cachestat_disable_trampoline(struct cachestat_bpf *obj)
  103. {
  104. bpf_program__set_autoload(obj->progs.netdata_add_to_page_cache_lru_fentry, false);
  105. bpf_program__set_autoload(obj->progs.netdata_mark_page_accessed_fentry, false);
  106. bpf_program__set_autoload(obj->progs.netdata_folio_mark_dirty_fentry, false);
  107. bpf_program__set_autoload(obj->progs.netdata_set_page_dirty_fentry, false);
  108. bpf_program__set_autoload(obj->progs.netdata_account_page_dirtied_fentry, false);
  109. bpf_program__set_autoload(obj->progs.netdata_mark_buffer_dirty_fentry, false);
  110. bpf_program__set_autoload(obj->progs.netdata_release_task_fentry, false);
  111. }
  112. /*
  113. * Disable specific trampoline
  114. *
  115. * Disable trampoline according to kernel version.
  116. *
  117. * @param obj is the main structure for bpf objects.
  118. */
  119. static void ebpf_cachestat_disable_specific_trampoline(struct cachestat_bpf *obj)
  120. {
  121. if (!strcmp(cachestat_targets[NETDATA_KEY_CALLS_ACCOUNT_PAGE_DIRTIED].name,
  122. account_page[NETDATA_CACHESTAT_FOLIO_DIRTY])) {
  123. bpf_program__set_autoload(obj->progs.netdata_account_page_dirtied_fentry, false);
  124. bpf_program__set_autoload(obj->progs.netdata_set_page_dirty_fentry, false);
  125. } else if (!strcmp(cachestat_targets[NETDATA_KEY_CALLS_ACCOUNT_PAGE_DIRTIED].name,
  126. account_page[NETDATA_CACHESTAT_SET_PAGE_DIRTY])) {
  127. bpf_program__set_autoload(obj->progs.netdata_folio_mark_dirty_fentry, false);
  128. bpf_program__set_autoload(obj->progs.netdata_account_page_dirtied_fentry, false);
  129. } else {
  130. bpf_program__set_autoload(obj->progs.netdata_folio_mark_dirty_fentry, false);
  131. bpf_program__set_autoload(obj->progs.netdata_set_page_dirty_fentry, false);
  132. }
  133. }
  134. /**
  135. * Set trampoline target
  136. *
  137. * Set the targets we will monitor.
  138. *
  139. * @param obj is the main structure for bpf objects.
  140. */
  141. static inline void netdata_set_trampoline_target(struct cachestat_bpf *obj)
  142. {
  143. bpf_program__set_attach_target(obj->progs.netdata_add_to_page_cache_lru_fentry, 0,
  144. cachestat_targets[NETDATA_KEY_CALLS_ADD_TO_PAGE_CACHE_LRU].name);
  145. bpf_program__set_attach_target(obj->progs.netdata_mark_page_accessed_fentry, 0,
  146. cachestat_targets[NETDATA_KEY_CALLS_MARK_PAGE_ACCESSED].name);
  147. if (!strcmp(cachestat_targets[NETDATA_KEY_CALLS_ACCOUNT_PAGE_DIRTIED].name,
  148. account_page[NETDATA_CACHESTAT_FOLIO_DIRTY])) {
  149. bpf_program__set_attach_target(obj->progs.netdata_folio_mark_dirty_fentry, 0,
  150. cachestat_targets[NETDATA_KEY_CALLS_ACCOUNT_PAGE_DIRTIED].name);
  151. } else if (!strcmp(cachestat_targets[NETDATA_KEY_CALLS_ACCOUNT_PAGE_DIRTIED].name,
  152. account_page[NETDATA_CACHESTAT_SET_PAGE_DIRTY])) {
  153. bpf_program__set_attach_target(obj->progs.netdata_set_page_dirty_fentry, 0,
  154. cachestat_targets[NETDATA_KEY_CALLS_ACCOUNT_PAGE_DIRTIED].name);
  155. } else {
  156. bpf_program__set_attach_target(obj->progs.netdata_account_page_dirtied_fentry, 0,
  157. cachestat_targets[NETDATA_KEY_CALLS_ACCOUNT_PAGE_DIRTIED].name);
  158. }
  159. bpf_program__set_attach_target(obj->progs.netdata_mark_buffer_dirty_fentry, 0,
  160. cachestat_targets[NETDATA_KEY_CALLS_MARK_BUFFER_DIRTY].name);
  161. bpf_program__set_attach_target(obj->progs.netdata_release_task_fentry, 0,
  162. EBPF_COMMON_FNCT_CLEAN_UP);
  163. }
  164. /**
  165. * Mount Attach Probe
  166. *
  167. * Attach probes to target
  168. *
  169. * @param obj is the main structure for bpf objects.
  170. *
  171. * @return It returns 0 on success and -1 otherwise.
  172. */
  173. static int ebpf_cachestat_attach_probe(struct cachestat_bpf *obj)
  174. {
  175. obj->links.netdata_add_to_page_cache_lru_kprobe = bpf_program__attach_kprobe(obj->progs.netdata_add_to_page_cache_lru_kprobe,
  176. false,
  177. cachestat_targets[NETDATA_KEY_CALLS_ADD_TO_PAGE_CACHE_LRU].name);
  178. int ret = libbpf_get_error(obj->links.netdata_add_to_page_cache_lru_kprobe);
  179. if (ret)
  180. return -1;
  181. obj->links.netdata_mark_page_accessed_kprobe = bpf_program__attach_kprobe(obj->progs.netdata_mark_page_accessed_kprobe,
  182. false,
  183. cachestat_targets[NETDATA_KEY_CALLS_MARK_PAGE_ACCESSED].name);
  184. ret = libbpf_get_error(obj->links.netdata_mark_page_accessed_kprobe);
  185. if (ret)
  186. return -1;
  187. if (!strcmp(cachestat_targets[NETDATA_KEY_CALLS_ACCOUNT_PAGE_DIRTIED].name,
  188. account_page[NETDATA_CACHESTAT_FOLIO_DIRTY])) {
  189. obj->links.netdata_folio_mark_dirty_kprobe = bpf_program__attach_kprobe(obj->progs.netdata_folio_mark_dirty_kprobe,
  190. false,
  191. cachestat_targets[NETDATA_KEY_CALLS_ACCOUNT_PAGE_DIRTIED].name);
  192. ret = libbpf_get_error(obj->links.netdata_folio_mark_dirty_kprobe);
  193. } else if (!strcmp(cachestat_targets[NETDATA_KEY_CALLS_ACCOUNT_PAGE_DIRTIED].name,
  194. account_page[NETDATA_CACHESTAT_SET_PAGE_DIRTY])) {
  195. obj->links.netdata_set_page_dirty_kprobe = bpf_program__attach_kprobe(obj->progs.netdata_set_page_dirty_kprobe,
  196. false,
  197. cachestat_targets[NETDATA_KEY_CALLS_ACCOUNT_PAGE_DIRTIED].name);
  198. ret = libbpf_get_error(obj->links.netdata_set_page_dirty_kprobe);
  199. } else {
  200. obj->links.netdata_account_page_dirtied_kprobe = bpf_program__attach_kprobe(obj->progs.netdata_account_page_dirtied_kprobe,
  201. false,
  202. cachestat_targets[NETDATA_KEY_CALLS_ACCOUNT_PAGE_DIRTIED].name);
  203. ret = libbpf_get_error(obj->links.netdata_account_page_dirtied_kprobe);
  204. }
  205. if (ret)
  206. return -1;
  207. obj->links.netdata_mark_buffer_dirty_kprobe = bpf_program__attach_kprobe(obj->progs.netdata_mark_buffer_dirty_kprobe,
  208. false,
  209. cachestat_targets[NETDATA_KEY_CALLS_MARK_BUFFER_DIRTY].name);
  210. ret = libbpf_get_error(obj->links.netdata_mark_buffer_dirty_kprobe);
  211. if (ret)
  212. return -1;
  213. obj->links.netdata_release_task_kprobe = bpf_program__attach_kprobe(obj->progs.netdata_release_task_kprobe,
  214. false,
  215. EBPF_COMMON_FNCT_CLEAN_UP);
  216. ret = libbpf_get_error(obj->links.netdata_release_task_kprobe);
  217. if (ret)
  218. return -1;
  219. return 0;
  220. }
  221. /**
  222. * Adjust Map Size
  223. *
  224. * Resize maps according input from users.
  225. *
  226. * @param obj is the main structure for bpf objects.
  227. * @param em structure with configuration
  228. */
  229. static void ebpf_cachestat_adjust_map(struct cachestat_bpf *obj, ebpf_module_t *em)
  230. {
  231. ebpf_update_map_size(obj->maps.cstat_pid, &cachestat_maps[NETDATA_CACHESTAT_PID_STATS],
  232. em, bpf_map__name(obj->maps.cstat_pid));
  233. ebpf_update_map_type(obj->maps.cstat_global, &cachestat_maps[NETDATA_CACHESTAT_GLOBAL_STATS]);
  234. ebpf_update_map_type(obj->maps.cstat_pid, &cachestat_maps[NETDATA_CACHESTAT_PID_STATS]);
  235. ebpf_update_map_type(obj->maps.cstat_ctrl, &cachestat_maps[NETDATA_CACHESTAT_CTRL]);
  236. }
  237. /**
  238. * Set hash tables
  239. *
  240. * Set the values for maps according the value given by kernel.
  241. *
  242. * @param obj is the main structure for bpf objects.
  243. */
  244. static void ebpf_cachestat_set_hash_tables(struct cachestat_bpf *obj)
  245. {
  246. cachestat_maps[NETDATA_CACHESTAT_GLOBAL_STATS].map_fd = bpf_map__fd(obj->maps.cstat_global);
  247. cachestat_maps[NETDATA_CACHESTAT_PID_STATS].map_fd = bpf_map__fd(obj->maps.cstat_pid);
  248. cachestat_maps[NETDATA_CACHESTAT_CTRL].map_fd = bpf_map__fd(obj->maps.cstat_ctrl);
  249. }
  250. /**
  251. * Disable Release Task
  252. *
  253. * Disable release task when apps is not enabled.
  254. *
  255. * @param obj is the main structure for bpf objects.
  256. */
  257. static void ebpf_cachestat_disable_release_task(struct cachestat_bpf *obj)
  258. {
  259. bpf_program__set_autoload(obj->progs.netdata_release_task_kprobe, false);
  260. bpf_program__set_autoload(obj->progs.netdata_release_task_fentry, false);
  261. }
  262. /**
  263. * Load and attach
  264. *
  265. * Load and attach the eBPF code in kernel.
  266. *
  267. * @param obj is the main structure for bpf objects.
  268. * @param em structure with configuration
  269. *
  270. * @return it returns 0 on success and -1 otherwise
  271. */
  272. static inline int ebpf_cachestat_load_and_attach(struct cachestat_bpf *obj, ebpf_module_t *em)
  273. {
  274. netdata_ebpf_targets_t *mt = em->targets;
  275. netdata_ebpf_program_loaded_t test = mt[NETDATA_KEY_CALLS_ADD_TO_PAGE_CACHE_LRU].mode;
  276. if (test == EBPF_LOAD_TRAMPOLINE) {
  277. ebpf_cachestat_disable_probe(obj);
  278. ebpf_cachestat_disable_specific_trampoline(obj);
  279. netdata_set_trampoline_target(obj);
  280. } else {
  281. ebpf_cachestat_disable_trampoline(obj);
  282. ebpf_cachestat_disable_specific_probe(obj);
  283. }
  284. ebpf_cachestat_adjust_map(obj, em);
  285. if (!em->apps_charts && !em->cgroup_charts)
  286. ebpf_cachestat_disable_release_task(obj);
  287. int ret = cachestat_bpf__load(obj);
  288. if (ret) {
  289. return ret;
  290. }
  291. ret = (test == EBPF_LOAD_TRAMPOLINE) ? cachestat_bpf__attach(obj) : ebpf_cachestat_attach_probe(obj);
  292. if (!ret) {
  293. ebpf_cachestat_set_hash_tables(obj);
  294. ebpf_update_controller(cachestat_maps[NETDATA_CACHESTAT_CTRL].map_fd, em);
  295. }
  296. return ret;
  297. }
  298. #endif
  299. /*****************************************************************
  300. *
  301. * FUNCTIONS TO CLOSE THE THREAD
  302. *
  303. *****************************************************************/
  304. static void ebpf_obsolete_specific_cachestat_charts(char *type, int update_every);
  305. /**
  306. * Obsolete services
  307. *
  308. * Obsolete all service charts created
  309. *
  310. * @param em a pointer to `struct ebpf_module`
  311. */
  312. static void ebpf_obsolete_services(ebpf_module_t *em)
  313. {
  314. ebpf_write_chart_obsolete(NETDATA_SERVICE_FAMILY,
  315. NETDATA_CACHESTAT_HIT_RATIO_CHART,
  316. "",
  317. "Hit ratio",
  318. EBPF_COMMON_DIMENSION_PERCENTAGE,
  319. NETDATA_CACHESTAT_SUBMENU,
  320. NETDATA_EBPF_CHART_TYPE_LINE,
  321. NETDATA_SYSTEMD_CACHESTAT_HIT_RATIO_CONTEXT,
  322. 21100,
  323. em->update_every);
  324. ebpf_write_chart_obsolete(NETDATA_SERVICE_FAMILY,
  325. NETDATA_CACHESTAT_DIRTY_CHART,
  326. "",
  327. "Number of dirty pages",
  328. EBPF_CACHESTAT_DIMENSION_PAGE,
  329. NETDATA_CACHESTAT_SUBMENU,
  330. NETDATA_EBPF_CHART_TYPE_LINE,
  331. NETDATA_SYSTEMD_CACHESTAT_MODIFIED_CACHE_CONTEXT,
  332. 21101,
  333. em->update_every);
  334. ebpf_write_chart_obsolete(NETDATA_SERVICE_FAMILY,
  335. NETDATA_CACHESTAT_HIT_CHART,
  336. "",
  337. "Number of accessed files",
  338. EBPF_CACHESTAT_DIMENSION_HITS,
  339. NETDATA_CACHESTAT_SUBMENU,
  340. NETDATA_EBPF_CHART_TYPE_LINE,
  341. NETDATA_SYSTEMD_CACHESTAT_HIT_FILE_CONTEXT,
  342. 21102,
  343. em->update_every);
  344. ebpf_write_chart_obsolete(NETDATA_SERVICE_FAMILY,
  345. NETDATA_CACHESTAT_MISSES_CHART,
  346. "",
  347. "Files out of page cache",
  348. EBPF_CACHESTAT_DIMENSION_MISSES,
  349. NETDATA_CACHESTAT_SUBMENU,
  350. NETDATA_EBPF_CHART_TYPE_LINE,
  351. NETDATA_SYSTEMD_CACHESTAT_MISS_FILES_CONTEXT,
  352. 21103,
  353. em->update_every);
  354. }
  355. /**
  356. * Obsolete cgroup chart
  357. *
  358. * Send obsolete for all charts created before to close.
  359. *
  360. * @param em a pointer to `struct ebpf_module`
  361. */
  362. static inline void ebpf_obsolete_cachestat_cgroup_charts(ebpf_module_t *em) {
  363. pthread_mutex_lock(&mutex_cgroup_shm);
  364. ebpf_obsolete_services(em);
  365. ebpf_cgroup_target_t *ect;
  366. for (ect = ebpf_cgroup_pids; ect ; ect = ect->next) {
  367. if (ect->systemd)
  368. continue;
  369. ebpf_obsolete_specific_cachestat_charts(ect->name, em->update_every);
  370. }
  371. pthread_mutex_unlock(&mutex_cgroup_shm);
  372. }
  373. /**
  374. * Obsolete global
  375. *
  376. * Obsolete global charts created by thread.
  377. *
  378. * @param em a pointer to `struct ebpf_module`
  379. */
  380. static void ebpf_obsolete_cachestat_global(ebpf_module_t *em)
  381. {
  382. ebpf_write_chart_obsolete(NETDATA_EBPF_MEMORY_GROUP,
  383. NETDATA_CACHESTAT_HIT_RATIO_CHART,
  384. "",
  385. "Hit ratio",
  386. EBPF_COMMON_DIMENSION_PERCENTAGE,
  387. NETDATA_CACHESTAT_SUBMENU,
  388. NETDATA_EBPF_CHART_TYPE_LINE,
  389. NULL,
  390. 21100,
  391. em->update_every);
  392. ebpf_write_chart_obsolete(NETDATA_EBPF_MEMORY_GROUP,
  393. NETDATA_CACHESTAT_DIRTY_CHART,
  394. "",
  395. "Number of dirty pages",
  396. EBPF_CACHESTAT_DIMENSION_PAGE,
  397. NETDATA_CACHESTAT_SUBMENU,
  398. NETDATA_EBPF_CHART_TYPE_LINE,
  399. NULL,
  400. 21101,
  401. em->update_every);
  402. ebpf_write_chart_obsolete(NETDATA_EBPF_MEMORY_GROUP,
  403. NETDATA_CACHESTAT_HIT_CHART,
  404. "",
  405. "Number of accessed files",
  406. EBPF_CACHESTAT_DIMENSION_HITS,
  407. NETDATA_CACHESTAT_SUBMENU,
  408. NETDATA_EBPF_CHART_TYPE_LINE,
  409. NULL,
  410. 21102,
  411. em->update_every);
  412. ebpf_write_chart_obsolete(NETDATA_EBPF_MEMORY_GROUP,
  413. NETDATA_CACHESTAT_MISSES_CHART,
  414. "",
  415. "Files out of page cache",
  416. EBPF_CACHESTAT_DIMENSION_MISSES,
  417. NETDATA_CACHESTAT_SUBMENU,
  418. NETDATA_EBPF_CHART_TYPE_LINE,
  419. NULL,
  420. 21103,
  421. em->update_every);
  422. }
  423. /**
  424. * Obsolette apps charts
  425. *
  426. * Obsolete apps charts.
  427. *
  428. * @param em a pointer to the structure with the default values.
  429. */
  430. void ebpf_obsolete_cachestat_apps_charts(struct ebpf_module *em)
  431. {
  432. struct ebpf_target *w;
  433. int update_every = em->update_every;
  434. for (w = apps_groups_root_target; w; w = w->next) {
  435. if (unlikely(!(w->charts_created & (1<<EBPF_MODULE_CACHESTAT_IDX))))
  436. continue;
  437. ebpf_write_chart_obsolete(NETDATA_APP_FAMILY,
  438. w->clean_name,
  439. "_ebpf_cachestat_hit_ratio",
  440. "Hit ratio",
  441. EBPF_COMMON_DIMENSION_PERCENTAGE,
  442. NETDATA_CACHESTAT_SUBMENU,
  443. NETDATA_EBPF_CHART_TYPE_LINE,
  444. "app.ebpf_cachestat_hit_ratio",
  445. 20260,
  446. update_every);
  447. ebpf_write_chart_obsolete(NETDATA_APP_FAMILY,
  448. w->clean_name,
  449. "_ebpf_cachestat_dirty_pages",
  450. "Number of dirty pages",
  451. EBPF_CACHESTAT_DIMENSION_PAGE,
  452. NETDATA_CACHESTAT_SUBMENU,
  453. NETDATA_EBPF_CHART_TYPE_STACKED,
  454. "app.ebpf_cachestat_dirty_pages",
  455. 20261,
  456. update_every);
  457. ebpf_write_chart_obsolete(NETDATA_APP_FAMILY,
  458. w->clean_name,
  459. "_ebpf_cachestat_access",
  460. "Number of accessed files",
  461. EBPF_CACHESTAT_DIMENSION_HITS,
  462. NETDATA_CACHESTAT_SUBMENU,
  463. NETDATA_EBPF_CHART_TYPE_STACKED,
  464. "app.ebpf_cachestat_access",
  465. 20262,
  466. update_every);
  467. ebpf_write_chart_obsolete(NETDATA_APP_FAMILY,
  468. w->clean_name,
  469. "_ebpf_cachestat_misses",
  470. "Files out of page cache",
  471. EBPF_CACHESTAT_DIMENSION_MISSES,
  472. NETDATA_CACHESTAT_SUBMENU,
  473. NETDATA_EBPF_CHART_TYPE_STACKED,
  474. "app.ebpf_cachestat_misses",
  475. 20263,
  476. update_every);
  477. w->charts_created &= ~(1<<EBPF_MODULE_CACHESTAT_IDX);
  478. }
  479. }
  480. /**
  481. * Cachestat exit.
  482. *
  483. * Cancel child and exit.
  484. *
  485. * @param ptr thread data.
  486. */
  487. static void ebpf_cachestat_exit(void *ptr)
  488. {
  489. ebpf_module_t *em = (ebpf_module_t *)ptr;
  490. if (em->enabled == NETDATA_THREAD_EBPF_FUNCTION_RUNNING) {
  491. pthread_mutex_lock(&lock);
  492. if (em->cgroup_charts) {
  493. ebpf_obsolete_cachestat_cgroup_charts(em);
  494. fflush(stdout);
  495. }
  496. if (em->apps_charts & NETDATA_EBPF_APPS_FLAG_CHART_CREATED) {
  497. ebpf_obsolete_cachestat_apps_charts(em);
  498. }
  499. ebpf_obsolete_cachestat_global(em);
  500. #ifdef NETDATA_DEV_MODE
  501. if (ebpf_aral_cachestat_pid)
  502. ebpf_statistic_obsolete_aral_chart(em, cachestat_disable_priority);
  503. #endif
  504. fflush(stdout);
  505. pthread_mutex_unlock(&lock);
  506. }
  507. ebpf_update_kernel_memory_with_vector(&plugin_statistics, em->maps, EBPF_ACTION_STAT_REMOVE);
  508. #ifdef LIBBPF_MAJOR_VERSION
  509. if (cachestat_bpf_obj) {
  510. cachestat_bpf__destroy(cachestat_bpf_obj);
  511. cachestat_bpf_obj = NULL;
  512. }
  513. #endif
  514. if (em->objects) {
  515. ebpf_unload_legacy_code(em->objects, em->probe_links);
  516. em->objects = NULL;
  517. em->probe_links = NULL;
  518. }
  519. pthread_mutex_lock(&ebpf_exit_cleanup);
  520. em->enabled = NETDATA_THREAD_EBPF_STOPPED;
  521. ebpf_update_stats(&plugin_statistics, em);
  522. pthread_mutex_unlock(&ebpf_exit_cleanup);
  523. }
  524. /*****************************************************************
  525. *
  526. * COMMON FUNCTIONS
  527. *
  528. *****************************************************************/
  529. /**
  530. * Update publish
  531. *
  532. * Update publish values before to write dimension.
  533. *
  534. * @param out structure that will receive data.
  535. * @param mpa calls for mark_page_accessed during the last second.
  536. * @param mbd calls for mark_buffer_dirty during the last second.
  537. * @param apcl calls for add_to_page_cache_lru during the last second.
  538. * @param apd calls for account_page_dirtied during the last second.
  539. */
  540. void cachestat_update_publish(netdata_publish_cachestat_t *out, uint64_t mpa, uint64_t mbd,
  541. uint64_t apcl, uint64_t apd)
  542. {
  543. // Adapted algorithm from https://github.com/iovisor/bcc/blob/master/tools/cachestat.py#L126-L138
  544. NETDATA_DOUBLE total = (NETDATA_DOUBLE) (((long long)mpa) - ((long long)mbd));
  545. if (total < 0)
  546. total = 0;
  547. NETDATA_DOUBLE misses = (NETDATA_DOUBLE) ( ((long long) apcl) - ((long long) apd) );
  548. if (misses < 0)
  549. misses = 0;
  550. // If hits are < 0, then its possible misses are overestimate due to possibly page cache read ahead adding
  551. // more pages than needed. In this case just assume misses as total and reset hits.
  552. NETDATA_DOUBLE hits = total - misses;
  553. if (hits < 0 ) {
  554. misses = total;
  555. hits = 0;
  556. }
  557. NETDATA_DOUBLE ratio = (total > 0) ? hits/total : 1;
  558. out->ratio = (long long )(ratio*100);
  559. out->hit = (long long)hits;
  560. out->miss = (long long)misses;
  561. }
  562. /**
  563. * Save previous values
  564. *
  565. * Save values used this time.
  566. *
  567. * @param publish
  568. */
  569. static void save_previous_values(netdata_publish_cachestat_t *publish) {
  570. publish->prev.mark_page_accessed = cachestat_hash_values[NETDATA_KEY_CALLS_MARK_PAGE_ACCESSED];
  571. publish->prev.account_page_dirtied = cachestat_hash_values[NETDATA_KEY_CALLS_ACCOUNT_PAGE_DIRTIED];
  572. publish->prev.add_to_page_cache_lru = cachestat_hash_values[NETDATA_KEY_CALLS_ADD_TO_PAGE_CACHE_LRU];
  573. publish->prev.mark_buffer_dirty = cachestat_hash_values[NETDATA_KEY_CALLS_MARK_BUFFER_DIRTY];
  574. }
  575. /**
  576. * Calculate statistics
  577. *
  578. * @param publish the structure where we will store the data.
  579. */
  580. static void calculate_stats(netdata_publish_cachestat_t *publish) {
  581. if (!publish->prev.mark_page_accessed) {
  582. save_previous_values(publish);
  583. return;
  584. }
  585. uint64_t mpa = cachestat_hash_values[NETDATA_KEY_CALLS_MARK_PAGE_ACCESSED] - publish->prev.mark_page_accessed;
  586. uint64_t mbd = cachestat_hash_values[NETDATA_KEY_CALLS_MARK_BUFFER_DIRTY] - publish->prev.mark_buffer_dirty;
  587. uint64_t apcl = cachestat_hash_values[NETDATA_KEY_CALLS_ADD_TO_PAGE_CACHE_LRU] - publish->prev.add_to_page_cache_lru;
  588. uint64_t apd = cachestat_hash_values[NETDATA_KEY_CALLS_ACCOUNT_PAGE_DIRTIED] - publish->prev.account_page_dirtied;
  589. save_previous_values(publish);
  590. // We are changing the original algorithm to have a smooth ratio.
  591. cachestat_update_publish(publish, mpa, mbd, apcl, apd);
  592. }
  593. /*****************************************************************
  594. *
  595. * APPS
  596. *
  597. *****************************************************************/
  598. /**
  599. * Apps Accumulator
  600. *
  601. * Sum all values read from kernel and store in the first address.
  602. *
  603. * @param out the vector with read values.
  604. * @param maps_per_core do I need to read all cores?
  605. */
  606. static void cachestat_apps_accumulator(netdata_cachestat_pid_t *out, int maps_per_core)
  607. {
  608. int i, end = (maps_per_core) ? ebpf_nprocs : 1;
  609. netdata_cachestat_pid_t *total = &out[0];
  610. for (i = 1; i < end; i++) {
  611. netdata_cachestat_pid_t *w = &out[i];
  612. total->account_page_dirtied += w->account_page_dirtied;
  613. total->add_to_page_cache_lru += w->add_to_page_cache_lru;
  614. total->mark_buffer_dirty += w->mark_buffer_dirty;
  615. total->mark_page_accessed += w->mark_page_accessed;
  616. }
  617. }
  618. /**
  619. * Save Pid values
  620. *
  621. * Save the current values inside the structure
  622. *
  623. * @param out vector used to plot charts
  624. * @param publish vector with values read from hash tables.
  625. */
  626. static inline void cachestat_save_pid_values(netdata_publish_cachestat_t *out, netdata_cachestat_pid_t *publish)
  627. {
  628. if (!out->current.mark_page_accessed) {
  629. memcpy(&out->current, &publish[0], sizeof(netdata_cachestat_pid_t));
  630. return;
  631. }
  632. memcpy(&out->prev, &out->current, sizeof(netdata_cachestat_pid_t));
  633. memcpy(&out->current, &publish[0], sizeof(netdata_cachestat_pid_t));
  634. }
  635. /**
  636. * Fill PID
  637. *
  638. * Fill PID structures
  639. *
  640. * @param current_pid pid that we are collecting data
  641. * @param out values read from hash tables;
  642. */
  643. static void cachestat_fill_pid(uint32_t current_pid, netdata_cachestat_pid_t *publish)
  644. {
  645. netdata_publish_cachestat_t *curr = cachestat_pid[current_pid];
  646. if (!curr) {
  647. curr = ebpf_publish_cachestat_get();
  648. cachestat_pid[current_pid] = curr;
  649. cachestat_save_pid_values(curr, publish);
  650. return;
  651. }
  652. cachestat_save_pid_values(curr, publish);
  653. }
  654. /**
  655. * Read APPS table
  656. *
  657. * Read the apps table and store data inside the structure.
  658. *
  659. * @param maps_per_core do I need to read all cores?
  660. */
  661. static void ebpf_read_cachestat_apps_table(int maps_per_core)
  662. {
  663. netdata_cachestat_pid_t *cv = cachestat_vector;
  664. uint32_t key;
  665. struct ebpf_pid_stat *pids = ebpf_root_of_pids;
  666. int fd = cachestat_maps[NETDATA_CACHESTAT_PID_STATS].map_fd;
  667. size_t length = sizeof(netdata_cachestat_pid_t);
  668. if (maps_per_core)
  669. length *= ebpf_nprocs;
  670. while (pids) {
  671. key = pids->pid;
  672. if (bpf_map_lookup_elem(fd, &key, cv)) {
  673. pids = pids->next;
  674. continue;
  675. }
  676. cachestat_apps_accumulator(cv, maps_per_core);
  677. cachestat_fill_pid(key, cv);
  678. // We are cleaning to avoid passing data read from one process to other.
  679. memset(cv, 0, length);
  680. pids = pids->next;
  681. }
  682. }
  683. /**
  684. * Update cgroup
  685. *
  686. * Update cgroup data based in
  687. *
  688. * @param maps_per_core do I need to read all cores?
  689. */
  690. static void ebpf_update_cachestat_cgroup(int maps_per_core)
  691. {
  692. netdata_cachestat_pid_t *cv = cachestat_vector;
  693. int fd = cachestat_maps[NETDATA_CACHESTAT_PID_STATS].map_fd;
  694. size_t length = sizeof(netdata_cachestat_pid_t);
  695. if (maps_per_core)
  696. length *= ebpf_nprocs;
  697. ebpf_cgroup_target_t *ect;
  698. pthread_mutex_lock(&mutex_cgroup_shm);
  699. for (ect = ebpf_cgroup_pids; ect; ect = ect->next) {
  700. struct pid_on_target2 *pids;
  701. for (pids = ect->pids; pids; pids = pids->next) {
  702. int pid = pids->pid;
  703. netdata_cachestat_pid_t *out = &pids->cachestat;
  704. if (likely(cachestat_pid) && cachestat_pid[pid]) {
  705. netdata_publish_cachestat_t *in = cachestat_pid[pid];
  706. memcpy(out, &in->current, sizeof(netdata_cachestat_pid_t));
  707. } else {
  708. memset(cv, 0, length);
  709. if (bpf_map_lookup_elem(fd, &pid, cv)) {
  710. continue;
  711. }
  712. cachestat_apps_accumulator(cv, maps_per_core);
  713. memcpy(out, cv, sizeof(netdata_cachestat_pid_t));
  714. }
  715. }
  716. }
  717. pthread_mutex_unlock(&mutex_cgroup_shm);
  718. }
  719. /**
  720. * Create apps charts
  721. *
  722. * Call ebpf_create_chart to create the charts on apps submenu.
  723. *
  724. * @param em a pointer to the structure with the default values.
  725. */
  726. void ebpf_cachestat_create_apps_charts(struct ebpf_module *em, void *ptr)
  727. {
  728. struct ebpf_target *root = ptr;
  729. struct ebpf_target *w;
  730. int update_every = em->update_every;
  731. for (w = root; w; w = w->next) {
  732. if (unlikely(!w->exposed))
  733. continue;
  734. ebpf_write_chart_cmd(NETDATA_APP_FAMILY,
  735. w->clean_name,
  736. "_ebpf_cachestat_hit_ratio",
  737. "Hit ratio",
  738. EBPF_COMMON_DIMENSION_PERCENTAGE,
  739. NETDATA_CACHESTAT_SUBMENU,
  740. NETDATA_EBPF_CHART_TYPE_LINE,
  741. "app.ebpf_cachestat_hit_ratio",
  742. 20260,
  743. update_every,
  744. NETDATA_EBPF_MODULE_NAME_CACHESTAT);
  745. ebpf_create_chart_labels("app_group", w->name, 0);
  746. ebpf_commit_label();
  747. fprintf(stdout, "DIMENSION ratio '' %s 1 1\n", ebpf_algorithms[NETDATA_EBPF_ABSOLUTE_IDX]);
  748. ebpf_write_chart_cmd(NETDATA_APP_FAMILY,
  749. w->clean_name,
  750. "_ebpf_cachestat_dirty_pages",
  751. "Number of dirty pages",
  752. EBPF_CACHESTAT_DIMENSION_PAGE,
  753. NETDATA_CACHESTAT_SUBMENU,
  754. NETDATA_EBPF_CHART_TYPE_LINE,
  755. "app.ebpf_cachestat_dirty_pages",
  756. 20261,
  757. update_every,
  758. NETDATA_EBPF_MODULE_NAME_CACHESTAT);
  759. ebpf_create_chart_labels("app_group", w->name, 0);
  760. ebpf_commit_label();
  761. fprintf(stdout, "DIMENSION pages '' %s 1 1\n", ebpf_algorithms[NETDATA_EBPF_INCREMENTAL_IDX]);
  762. ebpf_write_chart_cmd(NETDATA_APP_FAMILY,
  763. w->clean_name,
  764. "_ebpf_cachestat_access",
  765. "Number of accessed files",
  766. EBPF_CACHESTAT_DIMENSION_HITS,
  767. NETDATA_CACHESTAT_SUBMENU,
  768. NETDATA_EBPF_CHART_TYPE_STACKED,
  769. "app.ebpf_cachestat_access",
  770. 20262,
  771. update_every,
  772. NETDATA_EBPF_MODULE_NAME_CACHESTAT);
  773. ebpf_create_chart_labels("app_group", w->name, 0);
  774. ebpf_commit_label();
  775. fprintf(stdout, "DIMENSION hits '' %s 1 1\n", ebpf_algorithms[NETDATA_EBPF_ABSOLUTE_IDX]);
  776. ebpf_write_chart_cmd(NETDATA_APP_FAMILY,
  777. w->clean_name,
  778. "_ebpf_cachestat_misses",
  779. "Files out of page cache",
  780. EBPF_CACHESTAT_DIMENSION_MISSES,
  781. NETDATA_CACHESTAT_SUBMENU,
  782. NETDATA_EBPF_CHART_TYPE_STACKED,
  783. "app.ebpf_cachestat_misses",
  784. 20263,
  785. update_every,
  786. NETDATA_EBPF_MODULE_NAME_CACHESTAT);
  787. ebpf_create_chart_labels("app_group", w->name, 0);
  788. ebpf_commit_label();
  789. fprintf(stdout, "DIMENSION misses '' %s 1 1\n", ebpf_algorithms[NETDATA_EBPF_ABSOLUTE_IDX]);
  790. w->charts_created |= 1<<EBPF_MODULE_CACHESTAT_IDX;
  791. }
  792. em->apps_charts |= NETDATA_EBPF_APPS_FLAG_CHART_CREATED;
  793. }
  794. /*****************************************************************
  795. *
  796. * MAIN LOOP
  797. *
  798. *****************************************************************/
  799. /**
  800. * Read global counter
  801. *
  802. * Read the table with number of calls for all functions
  803. *
  804. * @param stats vector used to read data from control table.
  805. * @param maps_per_core do I need to read all cores?
  806. */
  807. static void ebpf_cachestat_read_global_tables(netdata_idx_t *stats, int maps_per_core)
  808. {
  809. ebpf_read_global_table_stats(cachestat_hash_values,
  810. cachestat_values,
  811. cachestat_maps[NETDATA_CACHESTAT_GLOBAL_STATS].map_fd,
  812. maps_per_core,
  813. NETDATA_KEY_CALLS_ADD_TO_PAGE_CACHE_LRU,
  814. NETDATA_CACHESTAT_END);
  815. ebpf_read_global_table_stats(stats,
  816. cachestat_values,
  817. cachestat_maps[NETDATA_CACHESTAT_CTRL].map_fd,
  818. maps_per_core,
  819. NETDATA_CONTROLLER_PID_TABLE_ADD,
  820. NETDATA_CONTROLLER_END);
  821. }
  822. /**
  823. * Send global
  824. *
  825. * Send global charts to Netdata
  826. */
  827. static void cachestat_send_global(netdata_publish_cachestat_t *publish)
  828. {
  829. calculate_stats(publish);
  830. netdata_publish_syscall_t *ptr = cachestat_counter_publish_aggregated;
  831. ebpf_one_dimension_write_charts(
  832. NETDATA_EBPF_MEMORY_GROUP, NETDATA_CACHESTAT_HIT_RATIO_CHART, ptr[NETDATA_CACHESTAT_IDX_RATIO].dimension,
  833. publish->ratio);
  834. ebpf_one_dimension_write_charts(
  835. NETDATA_EBPF_MEMORY_GROUP, NETDATA_CACHESTAT_DIRTY_CHART, ptr[NETDATA_CACHESTAT_IDX_DIRTY].dimension,
  836. cachestat_hash_values[NETDATA_KEY_CALLS_MARK_BUFFER_DIRTY]);
  837. ebpf_one_dimension_write_charts(
  838. NETDATA_EBPF_MEMORY_GROUP, NETDATA_CACHESTAT_HIT_CHART, ptr[NETDATA_CACHESTAT_IDX_HIT].dimension, publish->hit);
  839. ebpf_one_dimension_write_charts(
  840. NETDATA_EBPF_MEMORY_GROUP, NETDATA_CACHESTAT_MISSES_CHART, ptr[NETDATA_CACHESTAT_IDX_MISS].dimension,
  841. publish->miss);
  842. }
  843. /**
  844. * Cachestat sum PIDs
  845. *
  846. * Sum values for all PIDs associated to a group
  847. *
  848. * @param publish output structure.
  849. * @param root structure with listed IPs
  850. */
  851. void ebpf_cachestat_sum_pids(netdata_publish_cachestat_t *publish, struct ebpf_pid_on_target *root)
  852. {
  853. memcpy(&publish->prev, &publish->current,sizeof(publish->current));
  854. memset(&publish->current, 0, sizeof(publish->current));
  855. netdata_cachestat_pid_t *dst = &publish->current;
  856. while (root) {
  857. int32_t pid = root->pid;
  858. netdata_publish_cachestat_t *w = cachestat_pid[pid];
  859. if (w) {
  860. netdata_cachestat_pid_t *src = &w->current;
  861. dst->account_page_dirtied += src->account_page_dirtied;
  862. dst->add_to_page_cache_lru += src->add_to_page_cache_lru;
  863. dst->mark_buffer_dirty += src->mark_buffer_dirty;
  864. dst->mark_page_accessed += src->mark_page_accessed;
  865. }
  866. root = root->next;
  867. }
  868. }
  869. /**
  870. * Send data to Netdata calling auxiliary functions.
  871. *
  872. * @param root the target list.
  873. */
  874. void ebpf_cache_send_apps_data(struct ebpf_target *root)
  875. {
  876. struct ebpf_target *w;
  877. collected_number value;
  878. for (w = root; w; w = w->next) {
  879. if (unlikely(!(w->charts_created & (1<<EBPF_MODULE_CACHESTAT_IDX))))
  880. continue;
  881. ebpf_cachestat_sum_pids(&w->cachestat, w->root_pid);
  882. netdata_cachestat_pid_t *current = &w->cachestat.current;
  883. netdata_cachestat_pid_t *prev = &w->cachestat.prev;
  884. uint64_t mpa = current->mark_page_accessed - prev->mark_page_accessed;
  885. uint64_t mbd = current->mark_buffer_dirty - prev->mark_buffer_dirty;
  886. w->cachestat.dirty = mbd;
  887. uint64_t apcl = current->add_to_page_cache_lru - prev->add_to_page_cache_lru;
  888. uint64_t apd = current->account_page_dirtied - prev->account_page_dirtied;
  889. cachestat_update_publish(&w->cachestat, mpa, mbd, apcl, apd);
  890. value = (collected_number) w->cachestat.ratio;
  891. ebpf_write_begin_chart(NETDATA_APP_FAMILY, w->clean_name, "_ebpf_cachestat_hit_ratio");
  892. write_chart_dimension("ratio", value);
  893. ebpf_write_end_chart();
  894. value = (collected_number) w->cachestat.dirty;
  895. ebpf_write_begin_chart(NETDATA_APP_FAMILY, w->clean_name, "_ebpf_cachestat_dirty_pages");
  896. write_chart_dimension("pages", value);
  897. ebpf_write_end_chart();
  898. value = (collected_number) w->cachestat.hit;
  899. ebpf_write_begin_chart(NETDATA_APP_FAMILY, w->clean_name, "_ebpf_cachestat_access");
  900. write_chart_dimension("hits", value);
  901. ebpf_write_end_chart();
  902. value = (collected_number) w->cachestat.miss;
  903. ebpf_write_begin_chart(NETDATA_APP_FAMILY, w->clean_name, "_ebpf_cachestat_misses");
  904. write_chart_dimension("misses", value);
  905. ebpf_write_end_chart();
  906. }
  907. }
  908. /**
  909. * Cachestat sum PIDs
  910. *
  911. * Sum values for all PIDs associated to a group
  912. *
  913. * @param publish output structure.
  914. * @param root structure with listed IPs
  915. */
  916. void ebpf_cachestat_sum_cgroup_pids(netdata_publish_cachestat_t *publish, struct pid_on_target2 *root)
  917. {
  918. memcpy(&publish->prev, &publish->current,sizeof(publish->current));
  919. memset(&publish->current, 0, sizeof(publish->current));
  920. netdata_cachestat_pid_t *dst = &publish->current;
  921. while (root) {
  922. netdata_cachestat_pid_t *src = &root->cachestat;
  923. dst->account_page_dirtied += src->account_page_dirtied;
  924. dst->add_to_page_cache_lru += src->add_to_page_cache_lru;
  925. dst->mark_buffer_dirty += src->mark_buffer_dirty;
  926. dst->mark_page_accessed += src->mark_page_accessed;
  927. root = root->next;
  928. }
  929. }
  930. /**
  931. * Calc chart values
  932. *
  933. * Do necessary math to plot charts.
  934. */
  935. void ebpf_cachestat_calc_chart_values()
  936. {
  937. ebpf_cgroup_target_t *ect;
  938. for (ect = ebpf_cgroup_pids; ect ; ect = ect->next) {
  939. ebpf_cachestat_sum_cgroup_pids(&ect->publish_cachestat, ect->pids);
  940. netdata_cachestat_pid_t *current = &ect->publish_cachestat.current;
  941. netdata_cachestat_pid_t *prev = &ect->publish_cachestat.prev;
  942. uint64_t mpa = current->mark_page_accessed - prev->mark_page_accessed;
  943. uint64_t mbd = current->mark_buffer_dirty - prev->mark_buffer_dirty;
  944. ect->publish_cachestat.dirty = mbd;
  945. uint64_t apcl = current->add_to_page_cache_lru - prev->add_to_page_cache_lru;
  946. uint64_t apd = current->account_page_dirtied - prev->account_page_dirtied;
  947. cachestat_update_publish(&ect->publish_cachestat, mpa, mbd, apcl, apd);
  948. }
  949. }
  950. /**
  951. * Create Systemd cachestat Charts
  952. *
  953. * Create charts when systemd is enabled
  954. *
  955. * @param update_every value to overwrite the update frequency set by the server.
  956. **/
  957. static void ebpf_create_systemd_cachestat_charts(int update_every)
  958. {
  959. ebpf_create_charts_on_systemd(NETDATA_CACHESTAT_HIT_RATIO_CHART,
  960. "Hit ratio",
  961. EBPF_COMMON_DIMENSION_PERCENTAGE, NETDATA_CACHESTAT_SUBMENU,
  962. NETDATA_EBPF_CHART_TYPE_LINE, 21100,
  963. ebpf_algorithms[NETDATA_EBPF_ABSOLUTE_IDX],
  964. NETDATA_SYSTEMD_CACHESTAT_HIT_RATIO_CONTEXT, NETDATA_EBPF_MODULE_NAME_CACHESTAT,
  965. update_every);
  966. ebpf_create_charts_on_systemd(NETDATA_CACHESTAT_DIRTY_CHART,
  967. "Number of dirty pages",
  968. EBPF_CACHESTAT_DIMENSION_PAGE, NETDATA_CACHESTAT_SUBMENU,
  969. NETDATA_EBPF_CHART_TYPE_LINE, 21101,
  970. ebpf_algorithms[NETDATA_EBPF_ABSOLUTE_IDX],
  971. NETDATA_SYSTEMD_CACHESTAT_MODIFIED_CACHE_CONTEXT, NETDATA_EBPF_MODULE_NAME_CACHESTAT,
  972. update_every);
  973. ebpf_create_charts_on_systemd(NETDATA_CACHESTAT_HIT_CHART, "Number of accessed files",
  974. EBPF_CACHESTAT_DIMENSION_HITS, NETDATA_CACHESTAT_SUBMENU,
  975. NETDATA_EBPF_CHART_TYPE_LINE, 21102,
  976. ebpf_algorithms[NETDATA_EBPF_ABSOLUTE_IDX],
  977. NETDATA_SYSTEMD_CACHESTAT_HIT_FILE_CONTEXT, NETDATA_EBPF_MODULE_NAME_CACHESTAT,
  978. update_every);
  979. ebpf_create_charts_on_systemd(NETDATA_CACHESTAT_MISSES_CHART, "Files out of page cache",
  980. EBPF_CACHESTAT_DIMENSION_MISSES, NETDATA_CACHESTAT_SUBMENU,
  981. NETDATA_EBPF_CHART_TYPE_LINE, 21103,
  982. ebpf_algorithms[NETDATA_EBPF_ABSOLUTE_IDX],
  983. NETDATA_SYSTEMD_CACHESTAT_MISS_FILES_CONTEXT, NETDATA_EBPF_MODULE_NAME_CACHESTAT,
  984. update_every);
  985. }
  986. /**
  987. * Send Cache Stat charts
  988. *
  989. * Send collected data to Netdata.
  990. */
  991. static void ebpf_send_systemd_cachestat_charts()
  992. {
  993. ebpf_cgroup_target_t *ect;
  994. ebpf_write_begin_chart(NETDATA_SERVICE_FAMILY, NETDATA_CACHESTAT_HIT_RATIO_CHART, "");
  995. for (ect = ebpf_cgroup_pids; ect; ect = ect->next) {
  996. if (unlikely(ect->systemd) && unlikely(ect->updated)) {
  997. write_chart_dimension(ect->name, (long long)ect->publish_cachestat.ratio);
  998. }
  999. }
  1000. ebpf_write_end_chart();
  1001. ebpf_write_begin_chart(NETDATA_SERVICE_FAMILY, NETDATA_CACHESTAT_DIRTY_CHART, "");
  1002. for (ect = ebpf_cgroup_pids; ect; ect = ect->next) {
  1003. if (unlikely(ect->systemd) && unlikely(ect->updated)) {
  1004. write_chart_dimension(ect->name, (long long)ect->publish_cachestat.dirty);
  1005. }
  1006. }
  1007. ebpf_write_end_chart();
  1008. ebpf_write_begin_chart(NETDATA_SERVICE_FAMILY, NETDATA_CACHESTAT_HIT_CHART, "");
  1009. for (ect = ebpf_cgroup_pids; ect; ect = ect->next) {
  1010. if (unlikely(ect->systemd) && unlikely(ect->updated)) {
  1011. write_chart_dimension(ect->name, (long long)ect->publish_cachestat.hit);
  1012. }
  1013. }
  1014. ebpf_write_end_chart();
  1015. ebpf_write_begin_chart(NETDATA_SERVICE_FAMILY, NETDATA_CACHESTAT_MISSES_CHART, "");
  1016. for (ect = ebpf_cgroup_pids; ect; ect = ect->next) {
  1017. if (unlikely(ect->systemd) && unlikely(ect->updated)) {
  1018. write_chart_dimension(ect->name, (long long)ect->publish_cachestat.miss);
  1019. }
  1020. }
  1021. ebpf_write_end_chart();
  1022. }
  1023. /**
  1024. * Send Directory Cache charts
  1025. *
  1026. * Send collected data to Netdata.
  1027. */
  1028. static void ebpf_send_specific_cachestat_data(char *type, netdata_publish_cachestat_t *npc)
  1029. {
  1030. ebpf_write_begin_chart(type, NETDATA_CACHESTAT_HIT_RATIO_CHART, "");
  1031. write_chart_dimension(cachestat_counter_publish_aggregated[NETDATA_CACHESTAT_IDX_RATIO].name, (long long)npc->ratio);
  1032. ebpf_write_end_chart();
  1033. ebpf_write_begin_chart(type, NETDATA_CACHESTAT_DIRTY_CHART, "");
  1034. write_chart_dimension(cachestat_counter_publish_aggregated[NETDATA_CACHESTAT_IDX_DIRTY].name, (long long)npc->dirty);
  1035. ebpf_write_end_chart();
  1036. ebpf_write_begin_chart(type, NETDATA_CACHESTAT_HIT_CHART, "");
  1037. write_chart_dimension(cachestat_counter_publish_aggregated[NETDATA_CACHESTAT_IDX_HIT].name, (long long)npc->hit);
  1038. ebpf_write_end_chart();
  1039. ebpf_write_begin_chart(type, NETDATA_CACHESTAT_MISSES_CHART, "");
  1040. write_chart_dimension(cachestat_counter_publish_aggregated[NETDATA_CACHESTAT_IDX_MISS].name, (long long)npc->miss);
  1041. ebpf_write_end_chart();
  1042. }
  1043. /**
  1044. * Create specific cache Stat charts
  1045. *
  1046. * Create charts for cgroup/application.
  1047. *
  1048. * @param type the chart type.
  1049. * @param update_every value to overwrite the update frequency set by the server.
  1050. */
  1051. static void ebpf_create_specific_cachestat_charts(char *type, int update_every)
  1052. {
  1053. ebpf_create_chart(type, NETDATA_CACHESTAT_HIT_RATIO_CHART,
  1054. "Hit ratio",
  1055. EBPF_COMMON_DIMENSION_PERCENTAGE, NETDATA_CACHESTAT_CGROUP_SUBMENU,
  1056. NETDATA_CGROUP_CACHESTAT_HIT_RATIO_CONTEXT,
  1057. NETDATA_EBPF_CHART_TYPE_LINE, NETDATA_CHART_PRIO_CGROUPS_CONTAINERS + 5200,
  1058. ebpf_create_global_dimension,
  1059. cachestat_counter_publish_aggregated, 1, update_every, NETDATA_EBPF_MODULE_NAME_CACHESTAT);
  1060. ebpf_create_chart(type, NETDATA_CACHESTAT_DIRTY_CHART,
  1061. "Number of dirty pages",
  1062. EBPF_CACHESTAT_DIMENSION_PAGE, NETDATA_CACHESTAT_CGROUP_SUBMENU,
  1063. NETDATA_CGROUP_CACHESTAT_MODIFIED_CACHE_CONTEXT,
  1064. NETDATA_EBPF_CHART_TYPE_LINE, NETDATA_CHART_PRIO_CGROUPS_CONTAINERS + 5201,
  1065. ebpf_create_global_dimension,
  1066. &cachestat_counter_publish_aggregated[NETDATA_CACHESTAT_IDX_DIRTY], 1,
  1067. update_every, NETDATA_EBPF_MODULE_NAME_CACHESTAT);
  1068. ebpf_create_chart(type, NETDATA_CACHESTAT_HIT_CHART,
  1069. "Number of accessed files",
  1070. EBPF_CACHESTAT_DIMENSION_HITS, NETDATA_CACHESTAT_CGROUP_SUBMENU,
  1071. NETDATA_CGROUP_CACHESTAT_HIT_FILES_CONTEXT,
  1072. NETDATA_EBPF_CHART_TYPE_LINE, NETDATA_CHART_PRIO_CGROUPS_CONTAINERS + 5202,
  1073. ebpf_create_global_dimension,
  1074. &cachestat_counter_publish_aggregated[NETDATA_CACHESTAT_IDX_HIT], 1,
  1075. update_every, NETDATA_EBPF_MODULE_NAME_CACHESTAT);
  1076. ebpf_create_chart(type, NETDATA_CACHESTAT_MISSES_CHART,
  1077. "Files out of page cache",
  1078. EBPF_CACHESTAT_DIMENSION_MISSES, NETDATA_CACHESTAT_CGROUP_SUBMENU,
  1079. NETDATA_CGROUP_CACHESTAT_MISS_FILES_CONTEXT,
  1080. NETDATA_EBPF_CHART_TYPE_LINE, NETDATA_CHART_PRIO_CGROUPS_CONTAINERS + 5203,
  1081. ebpf_create_global_dimension,
  1082. &cachestat_counter_publish_aggregated[NETDATA_CACHESTAT_IDX_MISS], 1,
  1083. update_every, NETDATA_EBPF_MODULE_NAME_CACHESTAT);
  1084. }
  1085. /**
  1086. * Obsolete specific cache stat charts
  1087. *
  1088. * Obsolete charts for cgroup/application.
  1089. *
  1090. * @param type the chart type.
  1091. * @param update_every value to overwrite the update frequency set by the server.
  1092. */
  1093. static void ebpf_obsolete_specific_cachestat_charts(char *type, int update_every)
  1094. {
  1095. ebpf_write_chart_obsolete(type, NETDATA_CACHESTAT_HIT_RATIO_CHART,
  1096. "",
  1097. "Hit ratio",
  1098. EBPF_COMMON_DIMENSION_PERCENTAGE, NETDATA_CACHESTAT_SUBMENU,
  1099. NETDATA_EBPF_CHART_TYPE_LINE, NETDATA_CGROUP_CACHESTAT_HIT_RATIO_CONTEXT,
  1100. NETDATA_CHART_PRIO_CGROUPS_CONTAINERS + 5200, update_every);
  1101. ebpf_write_chart_obsolete(type, NETDATA_CACHESTAT_DIRTY_CHART,
  1102. "",
  1103. "Number of dirty pages",
  1104. EBPF_CACHESTAT_DIMENSION_PAGE, NETDATA_CACHESTAT_SUBMENU,
  1105. NETDATA_EBPF_CHART_TYPE_LINE, NETDATA_CGROUP_CACHESTAT_MODIFIED_CACHE_CONTEXT,
  1106. NETDATA_CHART_PRIO_CGROUPS_CONTAINERS + 5201, update_every);
  1107. ebpf_write_chart_obsolete(type, NETDATA_CACHESTAT_HIT_CHART,
  1108. "",
  1109. "Number of accessed files",
  1110. EBPF_CACHESTAT_DIMENSION_HITS, NETDATA_CACHESTAT_SUBMENU,
  1111. NETDATA_EBPF_CHART_TYPE_LINE, NETDATA_CGROUP_CACHESTAT_HIT_FILES_CONTEXT,
  1112. NETDATA_CHART_PRIO_CGROUPS_CONTAINERS + 5202, update_every);
  1113. ebpf_write_chart_obsolete(type, NETDATA_CACHESTAT_MISSES_CHART,
  1114. "",
  1115. "Files out of page cache",
  1116. EBPF_CACHESTAT_DIMENSION_MISSES, NETDATA_CACHESTAT_SUBMENU,
  1117. NETDATA_EBPF_CHART_TYPE_LINE, NETDATA_CGROUP_CACHESTAT_MISS_FILES_CONTEXT,
  1118. NETDATA_CHART_PRIO_CGROUPS_CONTAINERS + 5203, update_every);
  1119. }
  1120. /**
  1121. * Send data to Netdata calling auxiliary functions.
  1122. *
  1123. * @param update_every value to overwrite the update frequency set by the server.
  1124. */
  1125. void ebpf_cachestat_send_cgroup_data(int update_every)
  1126. {
  1127. if (!ebpf_cgroup_pids)
  1128. return;
  1129. pthread_mutex_lock(&mutex_cgroup_shm);
  1130. ebpf_cgroup_target_t *ect;
  1131. ebpf_cachestat_calc_chart_values();
  1132. int has_systemd = shm_ebpf_cgroup.header->systemd_enabled;
  1133. if (has_systemd) {
  1134. if (send_cgroup_chart) {
  1135. ebpf_create_systemd_cachestat_charts(update_every);
  1136. }
  1137. ebpf_send_systemd_cachestat_charts();
  1138. }
  1139. for (ect = ebpf_cgroup_pids; ect ; ect = ect->next) {
  1140. if (ect->systemd)
  1141. continue;
  1142. if (!(ect->flags & NETDATA_EBPF_CGROUP_HAS_CACHESTAT_CHART) && ect->updated) {
  1143. ebpf_create_specific_cachestat_charts(ect->name, update_every);
  1144. ect->flags |= NETDATA_EBPF_CGROUP_HAS_CACHESTAT_CHART;
  1145. }
  1146. if (ect->flags & NETDATA_EBPF_CGROUP_HAS_CACHESTAT_CHART) {
  1147. if (ect->updated) {
  1148. ebpf_send_specific_cachestat_data(ect->name, &ect->publish_cachestat);
  1149. } else {
  1150. ebpf_obsolete_specific_cachestat_charts(ect->name, update_every);
  1151. ect->flags &= ~NETDATA_EBPF_CGROUP_HAS_CACHESTAT_CHART;
  1152. }
  1153. }
  1154. }
  1155. pthread_mutex_unlock(&mutex_cgroup_shm);
  1156. }
  1157. /**
  1158. * Main loop for this collector.
  1159. */
  1160. static void cachestat_collector(ebpf_module_t *em)
  1161. {
  1162. netdata_publish_cachestat_t publish;
  1163. memset(&publish, 0, sizeof(publish));
  1164. int cgroups = em->cgroup_charts;
  1165. int update_every = em->update_every;
  1166. int maps_per_core = em->maps_per_core;
  1167. heartbeat_t hb;
  1168. heartbeat_init(&hb);
  1169. int counter = update_every - 1;
  1170. //This will be cancelled by its parent
  1171. uint32_t running_time = 0;
  1172. uint32_t lifetime = em->lifetime;
  1173. netdata_idx_t *stats = em->hash_table_stats;
  1174. memset(stats, 0, sizeof(em->hash_table_stats));
  1175. while (!ebpf_plugin_exit && running_time < lifetime) {
  1176. (void)heartbeat_next(&hb, USEC_PER_SEC);
  1177. if (ebpf_plugin_exit || ++counter != update_every)
  1178. continue;
  1179. counter = 0;
  1180. netdata_apps_integration_flags_t apps = em->apps_charts;
  1181. ebpf_cachestat_read_global_tables(stats, maps_per_core);
  1182. pthread_mutex_lock(&collect_data_mutex);
  1183. if (apps)
  1184. ebpf_read_cachestat_apps_table(maps_per_core);
  1185. if (cgroups)
  1186. ebpf_update_cachestat_cgroup(maps_per_core);
  1187. pthread_mutex_lock(&lock);
  1188. cachestat_send_global(&publish);
  1189. if (apps & NETDATA_EBPF_APPS_FLAG_CHART_CREATED)
  1190. ebpf_cache_send_apps_data(apps_groups_root_target);
  1191. #ifdef NETDATA_DEV_MODE
  1192. if (ebpf_aral_cachestat_pid)
  1193. ebpf_send_data_aral_chart(ebpf_aral_cachestat_pid, em);
  1194. #endif
  1195. if (cgroups)
  1196. ebpf_cachestat_send_cgroup_data(update_every);
  1197. pthread_mutex_unlock(&lock);
  1198. pthread_mutex_unlock(&collect_data_mutex);
  1199. pthread_mutex_lock(&ebpf_exit_cleanup);
  1200. if (running_time && !em->running_time)
  1201. running_time = update_every;
  1202. else
  1203. running_time += update_every;
  1204. em->running_time = running_time;
  1205. pthread_mutex_unlock(&ebpf_exit_cleanup);
  1206. }
  1207. }
  1208. /*****************************************************************
  1209. *
  1210. * INITIALIZE THREAD
  1211. *
  1212. *****************************************************************/
  1213. /**
  1214. * Create global charts
  1215. *
  1216. * Call ebpf_create_chart to create the charts for the collector.
  1217. *
  1218. * @param em a pointer to `struct ebpf_module`
  1219. */
  1220. static void ebpf_create_memory_charts(ebpf_module_t *em)
  1221. {
  1222. ebpf_create_chart(NETDATA_EBPF_MEMORY_GROUP, NETDATA_CACHESTAT_HIT_RATIO_CHART,
  1223. "Hit ratio",
  1224. EBPF_COMMON_DIMENSION_PERCENTAGE, NETDATA_CACHESTAT_SUBMENU,
  1225. NULL,
  1226. NETDATA_EBPF_CHART_TYPE_LINE,
  1227. 21100,
  1228. ebpf_create_global_dimension,
  1229. cachestat_counter_publish_aggregated, 1, em->update_every, NETDATA_EBPF_MODULE_NAME_CACHESTAT);
  1230. ebpf_create_chart(NETDATA_EBPF_MEMORY_GROUP, NETDATA_CACHESTAT_DIRTY_CHART,
  1231. "Number of dirty pages",
  1232. EBPF_CACHESTAT_DIMENSION_PAGE, NETDATA_CACHESTAT_SUBMENU,
  1233. NULL,
  1234. NETDATA_EBPF_CHART_TYPE_LINE,
  1235. 21101,
  1236. ebpf_create_global_dimension,
  1237. &cachestat_counter_publish_aggregated[NETDATA_CACHESTAT_IDX_DIRTY], 1,
  1238. em->update_every, NETDATA_EBPF_MODULE_NAME_CACHESTAT);
  1239. ebpf_create_chart(NETDATA_EBPF_MEMORY_GROUP, NETDATA_CACHESTAT_HIT_CHART,
  1240. "Number of accessed files",
  1241. EBPF_CACHESTAT_DIMENSION_HITS, NETDATA_CACHESTAT_SUBMENU,
  1242. NULL,
  1243. NETDATA_EBPF_CHART_TYPE_LINE,
  1244. 21102,
  1245. ebpf_create_global_dimension,
  1246. &cachestat_counter_publish_aggregated[NETDATA_CACHESTAT_IDX_HIT], 1,
  1247. em->update_every, NETDATA_EBPF_MODULE_NAME_CACHESTAT);
  1248. ebpf_create_chart(NETDATA_EBPF_MEMORY_GROUP, NETDATA_CACHESTAT_MISSES_CHART,
  1249. "Files out of page cache",
  1250. EBPF_CACHESTAT_DIMENSION_MISSES, NETDATA_CACHESTAT_SUBMENU,
  1251. NULL,
  1252. NETDATA_EBPF_CHART_TYPE_LINE,
  1253. 21103,
  1254. ebpf_create_global_dimension,
  1255. &cachestat_counter_publish_aggregated[NETDATA_CACHESTAT_IDX_MISS], 1,
  1256. em->update_every, NETDATA_EBPF_MODULE_NAME_CACHESTAT);
  1257. fflush(stdout);
  1258. }
  1259. /**
  1260. * Allocate vectors used with this thread.
  1261. *
  1262. * We are not testing the return, because callocz does this and shutdown the software
  1263. * case it was not possible to allocate.
  1264. *
  1265. * @param apps is apps enabled?
  1266. */
  1267. static void ebpf_cachestat_allocate_global_vectors(int apps)
  1268. {
  1269. if (apps) {
  1270. cachestat_pid = callocz((size_t)pid_max, sizeof(netdata_publish_cachestat_t *));
  1271. ebpf_cachestat_aral_init();
  1272. cachestat_vector = callocz((size_t)ebpf_nprocs, sizeof(netdata_cachestat_pid_t));
  1273. }
  1274. cachestat_values = callocz((size_t)ebpf_nprocs, sizeof(netdata_idx_t));
  1275. memset(cachestat_hash_values, 0, NETDATA_CACHESTAT_END * sizeof(netdata_idx_t));
  1276. memset(cachestat_counter_aggregated_data, 0, NETDATA_CACHESTAT_END * sizeof(netdata_syscall_stat_t));
  1277. memset(cachestat_counter_publish_aggregated, 0, NETDATA_CACHESTAT_END * sizeof(netdata_publish_syscall_t));
  1278. }
  1279. /*****************************************************************
  1280. *
  1281. * MAIN THREAD
  1282. *
  1283. *****************************************************************/
  1284. /**
  1285. * Update Internal value
  1286. *
  1287. * Update values used during runtime.
  1288. *
  1289. * @return It returns 0 when one of the functions is present and -1 otherwise.
  1290. */
  1291. static int ebpf_cachestat_set_internal_value()
  1292. {
  1293. ebpf_addresses_t address = {.function = NULL, .hash = 0, .addr = 0};
  1294. int i;
  1295. for (i = 0; i < NETDATA_CACHESTAT_ACCOUNT_DIRTY_END ; i++) {
  1296. address.function = account_page[i];
  1297. ebpf_load_addresses(&address, -1);
  1298. if (address.addr)
  1299. break;
  1300. }
  1301. if (!address.addr) {
  1302. netdata_log_error("%s cachestat.", NETDATA_EBPF_DEFAULT_FNT_NOT_FOUND);
  1303. return -1;
  1304. }
  1305. cachestat_targets[NETDATA_KEY_CALLS_ACCOUNT_PAGE_DIRTIED].name = address.function;
  1306. return 0;
  1307. }
  1308. /*
  1309. * Load BPF
  1310. *
  1311. * Load BPF files.
  1312. *
  1313. * @param em the structure with configuration
  1314. */
  1315. static int ebpf_cachestat_load_bpf(ebpf_module_t *em)
  1316. {
  1317. #ifdef LIBBPF_MAJOR_VERSION
  1318. ebpf_define_map_type(cachestat_maps, em->maps_per_core, running_on_kernel);
  1319. #endif
  1320. int ret = 0;
  1321. ebpf_adjust_apps_cgroup(em, em->targets[NETDATA_KEY_CALLS_ADD_TO_PAGE_CACHE_LRU].mode);
  1322. if (em->load & EBPF_LOAD_LEGACY) {
  1323. em->probe_links = ebpf_load_program(ebpf_plugin_dir, em, running_on_kernel, isrh, &em->objects);
  1324. if (!em->probe_links) {
  1325. ret = -1;
  1326. }
  1327. }
  1328. #ifdef LIBBPF_MAJOR_VERSION
  1329. else {
  1330. cachestat_bpf_obj = cachestat_bpf__open();
  1331. if (!cachestat_bpf_obj)
  1332. ret = -1;
  1333. else
  1334. ret = ebpf_cachestat_load_and_attach(cachestat_bpf_obj, em);
  1335. }
  1336. #endif
  1337. if (ret)
  1338. netdata_log_error("%s %s", EBPF_DEFAULT_ERROR_MSG, em->info.thread_name);
  1339. return ret;
  1340. }
  1341. /**
  1342. * Cachestat thread
  1343. *
  1344. * Thread used to make cachestat thread
  1345. *
  1346. * @param ptr a pointer to `struct ebpf_module`
  1347. *
  1348. * @return It always return NULL
  1349. */
  1350. void *ebpf_cachestat_thread(void *ptr)
  1351. {
  1352. netdata_thread_cleanup_push(ebpf_cachestat_exit, ptr);
  1353. ebpf_module_t *em = (ebpf_module_t *)ptr;
  1354. em->maps = cachestat_maps;
  1355. ebpf_update_pid_table(&cachestat_maps[NETDATA_CACHESTAT_PID_STATS], em);
  1356. if (ebpf_cachestat_set_internal_value()) {
  1357. goto endcachestat;
  1358. }
  1359. #ifdef LIBBPF_MAJOR_VERSION
  1360. ebpf_adjust_thread_load(em, default_btf);
  1361. #endif
  1362. if (ebpf_cachestat_load_bpf(em)) {
  1363. goto endcachestat;
  1364. }
  1365. ebpf_cachestat_allocate_global_vectors(em->apps_charts);
  1366. int algorithms[NETDATA_CACHESTAT_END] = {
  1367. NETDATA_EBPF_ABSOLUTE_IDX, NETDATA_EBPF_INCREMENTAL_IDX, NETDATA_EBPF_ABSOLUTE_IDX, NETDATA_EBPF_ABSOLUTE_IDX
  1368. };
  1369. ebpf_global_labels(cachestat_counter_aggregated_data, cachestat_counter_publish_aggregated,
  1370. cachestat_counter_dimension_name, cachestat_counter_dimension_name,
  1371. algorithms, NETDATA_CACHESTAT_END);
  1372. pthread_mutex_lock(&lock);
  1373. ebpf_update_stats(&plugin_statistics, em);
  1374. ebpf_update_kernel_memory_with_vector(&plugin_statistics, em->maps, EBPF_ACTION_STAT_ADD);
  1375. ebpf_create_memory_charts(em);
  1376. #ifdef NETDATA_DEV_MODE
  1377. if (ebpf_aral_cachestat_pid)
  1378. cachestat_disable_priority = ebpf_statistic_create_aral_chart(NETDATA_EBPF_CACHESTAT_ARAL_NAME, em);
  1379. #endif
  1380. pthread_mutex_unlock(&lock);
  1381. cachestat_collector(em);
  1382. endcachestat:
  1383. ebpf_update_disabled_plugin_stats(em);
  1384. netdata_thread_cleanup_pop(1);
  1385. return NULL;
  1386. }