ebpf_dcstat.c 41 KB

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