ebpf_cachestat.c 60 KB

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