ebpf_dcstat.c 43 KB

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