ebpf_dcstat.c 35 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996
  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 struct bpf_link **probe_links = NULL;
  10. static struct bpf_object *objects = NULL;
  11. static netdata_idx_t dcstat_hash_values[NETDATA_DCSTAT_IDX_END];
  12. static netdata_idx_t *dcstat_values = NULL;
  13. static int read_thread_closed = 1;
  14. struct config dcstat_config = { .first_section = NULL,
  15. .last_section = NULL,
  16. .mutex = NETDATA_MUTEX_INITIALIZER,
  17. .index = { .avl_tree = { .root = NULL, .compar = appconfig_section_compare },
  18. .rwlock = AVL_LOCK_INITIALIZER } };
  19. struct netdata_static_thread dcstat_threads = {"DCSTAT KERNEL",
  20. NULL, NULL, 1, NULL,
  21. NULL, NULL};
  22. static ebpf_local_maps_t dcstat_maps[] = {{.name = "dcstat_global", .internal_input = NETDATA_DIRECTORY_CACHE_END,
  23. .user_input = 0, .type = NETDATA_EBPF_MAP_STATIC,
  24. .map_fd = ND_EBPF_MAP_FD_NOT_INITIALIZED},
  25. {.name = "dcstat_pid", .internal_input = ND_EBPF_DEFAULT_PID_SIZE,
  26. .user_input = 0,
  27. .type = NETDATA_EBPF_MAP_RESIZABLE | NETDATA_EBPF_MAP_PID,
  28. .map_fd = ND_EBPF_MAP_FD_NOT_INITIALIZED},
  29. {.name = "dcstat_ctrl", .internal_input = NETDATA_CONTROLLER_END,
  30. .user_input = 0,
  31. .type = NETDATA_EBPF_MAP_CONTROLLER,
  32. .map_fd = ND_EBPF_MAP_FD_NOT_INITIALIZED},
  33. {.name = NULL, .internal_input = 0, .user_input = 0,
  34. .type = NETDATA_EBPF_MAP_CONTROLLER,
  35. .map_fd = ND_EBPF_MAP_FD_NOT_INITIALIZED}};
  36. static ebpf_specify_name_t dc_optional_name[] = { {.program_name = "netdata_lookup_fast",
  37. .function_to_attach = "lookup_fast",
  38. .optional = NULL,
  39. .retprobe = CONFIG_BOOLEAN_NO},
  40. {.program_name = NULL}};
  41. /*****************************************************************
  42. *
  43. * COMMON FUNCTIONS
  44. *
  45. *****************************************************************/
  46. /**
  47. * Update publish
  48. *
  49. * Update publish values before to write dimension.
  50. *
  51. * @param out structure that will receive data.
  52. * @param cache_access number of access to directory cache.
  53. * @param not_found number of files not found on the file system
  54. */
  55. void dcstat_update_publish(netdata_publish_dcstat_t *out, uint64_t cache_access, uint64_t not_found)
  56. {
  57. calculated_number successful_access = (calculated_number) (((long long)cache_access) - ((long long)not_found));
  58. calculated_number ratio = (cache_access) ? successful_access/(calculated_number)cache_access : 0;
  59. out->ratio = (long long )(ratio*100);
  60. }
  61. /*****************************************************************
  62. *
  63. * FUNCTIONS TO CLOSE THE THREAD
  64. *
  65. *****************************************************************/
  66. /**
  67. * Clean PID structures
  68. *
  69. * Clean the allocated structures.
  70. */
  71. void clean_dcstat_pid_structures() {
  72. struct pid_stat *pids = root_of_pids;
  73. while (pids) {
  74. freez(dcstat_pid[pids->pid]);
  75. pids = pids->next;
  76. }
  77. }
  78. /**
  79. * Clean names
  80. *
  81. * Clean the optional names allocated during startup.
  82. */
  83. void ebpf_dcstat_clean_names()
  84. {
  85. size_t i = 0;
  86. while (dc_optional_name[i].program_name) {
  87. freez(dc_optional_name[i].optional);
  88. i++;
  89. }
  90. }
  91. /**
  92. * Clean up the main thread.
  93. *
  94. * @param ptr thread data.
  95. */
  96. static void ebpf_dcstat_cleanup(void *ptr)
  97. {
  98. ebpf_module_t *em = (ebpf_module_t *)ptr;
  99. if (!em->enabled)
  100. return;
  101. heartbeat_t hb;
  102. heartbeat_init(&hb);
  103. uint32_t tick = 2 * USEC_PER_MS;
  104. while (!read_thread_closed) {
  105. usec_t dt = heartbeat_next(&hb, tick);
  106. UNUSED(dt);
  107. }
  108. freez(dcstat_vector);
  109. freez(dcstat_values);
  110. ebpf_cleanup_publish_syscall(dcstat_counter_publish_aggregated);
  111. ebpf_dcstat_clean_names();
  112. if (probe_links) {
  113. struct bpf_program *prog;
  114. size_t i = 0 ;
  115. bpf_object__for_each_program(prog, objects) {
  116. bpf_link__destroy(probe_links[i]);
  117. i++;
  118. }
  119. bpf_object__close(objects);
  120. }
  121. }
  122. /*****************************************************************
  123. *
  124. * APPS
  125. *
  126. *****************************************************************/
  127. /**
  128. * Create apps charts
  129. *
  130. * Call ebpf_create_chart to create the charts on apps submenu.
  131. *
  132. * @param em a pointer to the structure with the default values.
  133. */
  134. void ebpf_dcstat_create_apps_charts(struct ebpf_module *em, void *ptr)
  135. {
  136. struct target *root = ptr;
  137. ebpf_create_charts_on_apps(NETDATA_DC_HIT_CHART,
  138. "Percentage of files inside directory cache",
  139. EBPF_COMMON_DIMENSION_PERCENTAGE,
  140. NETDATA_DIRECTORY_CACHE_SUBMENU,
  141. NETDATA_EBPF_CHART_TYPE_LINE,
  142. 20100,
  143. ebpf_algorithms[NETDATA_EBPF_ABSOLUTE_IDX],
  144. root, em->update_every, NETDATA_EBPF_MODULE_NAME_DCSTAT);
  145. ebpf_create_charts_on_apps(NETDATA_DC_REFERENCE_CHART,
  146. "Count file access",
  147. EBPF_COMMON_DIMENSION_FILES,
  148. NETDATA_DIRECTORY_CACHE_SUBMENU,
  149. NETDATA_EBPF_CHART_TYPE_STACKED,
  150. 20101,
  151. ebpf_algorithms[NETDATA_EBPF_ABSOLUTE_IDX],
  152. root, em->update_every, NETDATA_EBPF_MODULE_NAME_DCSTAT);
  153. ebpf_create_charts_on_apps(NETDATA_DC_REQUEST_NOT_CACHE_CHART,
  154. "Files not present inside directory cache",
  155. EBPF_COMMON_DIMENSION_FILES,
  156. NETDATA_DIRECTORY_CACHE_SUBMENU,
  157. NETDATA_EBPF_CHART_TYPE_STACKED,
  158. 20102,
  159. ebpf_algorithms[NETDATA_EBPF_ABSOLUTE_IDX],
  160. root, em->update_every, NETDATA_EBPF_MODULE_NAME_DCSTAT);
  161. ebpf_create_charts_on_apps(NETDATA_DC_REQUEST_NOT_FOUND_CHART,
  162. "Files not found",
  163. EBPF_COMMON_DIMENSION_FILES,
  164. NETDATA_DIRECTORY_CACHE_SUBMENU,
  165. NETDATA_EBPF_CHART_TYPE_STACKED,
  166. 20103,
  167. ebpf_algorithms[NETDATA_EBPF_ABSOLUTE_IDX],
  168. root, em->update_every, NETDATA_EBPF_MODULE_NAME_DCSTAT);
  169. }
  170. /*****************************************************************
  171. *
  172. * MAIN LOOP
  173. *
  174. *****************************************************************/
  175. /**
  176. * Apps Accumulator
  177. *
  178. * Sum all values read from kernel and store in the first address.
  179. *
  180. * @param out the vector with read values.
  181. */
  182. static void dcstat_apps_accumulator(netdata_dcstat_pid_t *out)
  183. {
  184. int i, end = (running_on_kernel >= NETDATA_KERNEL_V4_15) ? ebpf_nprocs : 1;
  185. netdata_dcstat_pid_t *total = &out[0];
  186. for (i = 1; i < end; i++) {
  187. netdata_dcstat_pid_t *w = &out[i];
  188. total->cache_access += w->cache_access;
  189. total->file_system += w->file_system;
  190. total->not_found += w->not_found;
  191. }
  192. }
  193. /**
  194. * Save PID values
  195. *
  196. * Save the current values inside the structure
  197. *
  198. * @param out vector used to plot charts
  199. * @param publish vector with values read from hash tables.
  200. */
  201. static inline void dcstat_save_pid_values(netdata_publish_dcstat_t *out, netdata_dcstat_pid_t *publish)
  202. {
  203. memcpy(&out->curr, &publish[0], sizeof(netdata_dcstat_pid_t));
  204. }
  205. /**
  206. * Fill PID
  207. *
  208. * Fill PID structures
  209. *
  210. * @param current_pid pid that we are collecting data
  211. * @param out values read from hash tables;
  212. */
  213. static void dcstat_fill_pid(uint32_t current_pid, netdata_dcstat_pid_t *publish)
  214. {
  215. netdata_publish_dcstat_t *curr = dcstat_pid[current_pid];
  216. if (!curr) {
  217. curr = callocz(1, sizeof(netdata_publish_dcstat_t));
  218. dcstat_pid[current_pid] = curr;
  219. }
  220. dcstat_save_pid_values(curr, publish);
  221. }
  222. /**
  223. * Read APPS table
  224. *
  225. * Read the apps table and store data inside the structure.
  226. */
  227. static void read_apps_table()
  228. {
  229. netdata_dcstat_pid_t *cv = dcstat_vector;
  230. uint32_t key;
  231. struct pid_stat *pids = root_of_pids;
  232. int fd = dcstat_maps[NETDATA_DCSTAT_PID_STATS].map_fd;
  233. size_t length = sizeof(netdata_dcstat_pid_t)*ebpf_nprocs;
  234. while (pids) {
  235. key = pids->pid;
  236. if (bpf_map_lookup_elem(fd, &key, cv)) {
  237. pids = pids->next;
  238. continue;
  239. }
  240. dcstat_apps_accumulator(cv);
  241. dcstat_fill_pid(key, cv);
  242. // We are cleaning to avoid passing data read from one process to other.
  243. memset(cv, 0, length);
  244. pids = pids->next;
  245. }
  246. }
  247. /**
  248. * Update cgroup
  249. *
  250. * Update cgroup data based in
  251. */
  252. static void ebpf_update_dc_cgroup()
  253. {
  254. netdata_dcstat_pid_t *cv = dcstat_vector;
  255. int fd = dcstat_maps[NETDATA_DCSTAT_PID_STATS].map_fd;
  256. size_t length = sizeof(netdata_dcstat_pid_t)*ebpf_nprocs;
  257. ebpf_cgroup_target_t *ect;
  258. pthread_mutex_lock(&mutex_cgroup_shm);
  259. for (ect = ebpf_cgroup_pids; ect; ect = ect->next) {
  260. struct pid_on_target2 *pids;
  261. for (pids = ect->pids; pids; pids = pids->next) {
  262. int pid = pids->pid;
  263. netdata_dcstat_pid_t *out = &pids->dc;
  264. if (likely(dcstat_pid) && dcstat_pid[pid]) {
  265. netdata_publish_dcstat_t *in = dcstat_pid[pid];
  266. memcpy(out, &in->curr, sizeof(netdata_dcstat_pid_t));
  267. } else {
  268. memset(cv, 0, length);
  269. if (bpf_map_lookup_elem(fd, &pid, cv)) {
  270. continue;
  271. }
  272. dcstat_apps_accumulator(cv);
  273. memcpy(out, cv, sizeof(netdata_dcstat_pid_t));
  274. }
  275. }
  276. }
  277. pthread_mutex_unlock(&mutex_cgroup_shm);
  278. }
  279. /**
  280. * Read global table
  281. *
  282. * Read the table with number of calls for all functions
  283. */
  284. static void read_global_table()
  285. {
  286. uint32_t idx;
  287. netdata_idx_t *val = dcstat_hash_values;
  288. netdata_idx_t *stored = dcstat_values;
  289. int fd = dcstat_maps[NETDATA_DCSTAT_GLOBAL_STATS].map_fd;
  290. for (idx = NETDATA_KEY_DC_REFERENCE; idx < NETDATA_DIRECTORY_CACHE_END; idx++) {
  291. if (!bpf_map_lookup_elem(fd, &idx, stored)) {
  292. int i;
  293. int end = ebpf_nprocs;
  294. netdata_idx_t total = 0;
  295. for (i = 0; i < end; i++)
  296. total += stored[i];
  297. val[idx] = total;
  298. }
  299. }
  300. }
  301. /**
  302. * DCstat read hash
  303. *
  304. * This is the thread callback.
  305. * This thread is necessary, because we cannot freeze the whole plugin to read the data.
  306. *
  307. * @param ptr It is a NULL value for this thread.
  308. *
  309. * @return It always returns NULL.
  310. */
  311. void *ebpf_dcstat_read_hash(void *ptr)
  312. {
  313. read_thread_closed = 0;
  314. heartbeat_t hb;
  315. heartbeat_init(&hb);
  316. ebpf_module_t *em = (ebpf_module_t *)ptr;
  317. usec_t step = NETDATA_LATENCY_DCSTAT_SLEEP_MS * em->update_every;
  318. while (!close_ebpf_plugin) {
  319. usec_t dt = heartbeat_next(&hb, step);
  320. (void)dt;
  321. read_global_table();
  322. }
  323. read_thread_closed = 1;
  324. return NULL;
  325. }
  326. /**
  327. * Cachestat sum PIDs
  328. *
  329. * Sum values for all PIDs associated to a group
  330. *
  331. * @param publish output structure.
  332. * @param root structure with listed IPs
  333. */
  334. void ebpf_dcstat_sum_pids(netdata_publish_dcstat_t *publish, struct pid_on_target *root)
  335. {
  336. memset(&publish->curr, 0, sizeof(netdata_dcstat_pid_t));
  337. netdata_dcstat_pid_t *dst = &publish->curr;
  338. while (root) {
  339. int32_t pid = root->pid;
  340. netdata_publish_dcstat_t *w = dcstat_pid[pid];
  341. if (w) {
  342. netdata_dcstat_pid_t *src = &w->curr;
  343. dst->cache_access += src->cache_access;
  344. dst->file_system += src->file_system;
  345. dst->not_found += src->not_found;
  346. }
  347. root = root->next;
  348. }
  349. }
  350. /**
  351. * Send data to Netdata calling auxiliary functions.
  352. *
  353. * @param root the target list.
  354. */
  355. void ebpf_dcache_send_apps_data(struct target *root)
  356. {
  357. struct target *w;
  358. collected_number value;
  359. write_begin_chart(NETDATA_APPS_FAMILY, NETDATA_DC_HIT_CHART);
  360. for (w = root; w; w = w->next) {
  361. if (unlikely(w->exposed && w->processes)) {
  362. ebpf_dcstat_sum_pids(&w->dcstat, w->root_pid);
  363. uint64_t cache = w->dcstat.curr.cache_access;
  364. uint64_t not_found = w->dcstat.curr.not_found;
  365. dcstat_update_publish(&w->dcstat, cache, not_found);
  366. value = (collected_number) w->dcstat.ratio;
  367. write_chart_dimension(w->name, value);
  368. }
  369. }
  370. write_end_chart();
  371. write_begin_chart(NETDATA_APPS_FAMILY, NETDATA_DC_REFERENCE_CHART);
  372. for (w = root; w; w = w->next) {
  373. if (unlikely(w->exposed && w->processes)) {
  374. if (w->dcstat.curr.cache_access < w->dcstat.prev.cache_access) {
  375. w->dcstat.prev.cache_access = 0;
  376. }
  377. w->dcstat.cache_access = (long long)w->dcstat.curr.cache_access - (long long)w->dcstat.prev.cache_access;
  378. value = (collected_number) w->dcstat.cache_access;
  379. write_chart_dimension(w->name, value);
  380. w->dcstat.prev.cache_access = w->dcstat.curr.cache_access;
  381. }
  382. }
  383. write_end_chart();
  384. write_begin_chart(NETDATA_APPS_FAMILY, NETDATA_DC_REQUEST_NOT_CACHE_CHART);
  385. for (w = root; w; w = w->next) {
  386. if (unlikely(w->exposed && w->processes)) {
  387. if (w->dcstat.curr.file_system < w->dcstat.prev.file_system) {
  388. w->dcstat.prev.file_system = 0;
  389. }
  390. value = (collected_number) (!w->dcstat.cache_access) ? 0 :
  391. (long long )w->dcstat.curr.file_system - (long long)w->dcstat.prev.file_system;
  392. write_chart_dimension(w->name, value);
  393. w->dcstat.prev.file_system = w->dcstat.curr.file_system;
  394. }
  395. }
  396. write_end_chart();
  397. write_begin_chart(NETDATA_APPS_FAMILY, NETDATA_DC_REQUEST_NOT_FOUND_CHART);
  398. for (w = root; w; w = w->next) {
  399. if (unlikely(w->exposed && w->processes)) {
  400. if (w->dcstat.curr.not_found < w->dcstat.prev.not_found) {
  401. w->dcstat.prev.not_found = 0;
  402. }
  403. value = (collected_number) (!w->dcstat.cache_access) ? 0 :
  404. (long long)w->dcstat.curr.not_found - (long long)w->dcstat.prev.not_found;
  405. write_chart_dimension(w->name, value);
  406. w->dcstat.prev.not_found = w->dcstat.curr.not_found;
  407. }
  408. }
  409. write_end_chart();
  410. }
  411. /**
  412. * Send global
  413. *
  414. * Send global charts to Netdata
  415. */
  416. static void dcstat_send_global(netdata_publish_dcstat_t *publish)
  417. {
  418. dcstat_update_publish(publish, dcstat_hash_values[NETDATA_KEY_DC_REFERENCE],
  419. dcstat_hash_values[NETDATA_KEY_DC_MISS]);
  420. netdata_publish_syscall_t *ptr = dcstat_counter_publish_aggregated;
  421. netdata_idx_t value = dcstat_hash_values[NETDATA_KEY_DC_REFERENCE];
  422. if (value != ptr[NETDATA_DCSTAT_IDX_REFERENCE].pcall) {
  423. ptr[NETDATA_DCSTAT_IDX_REFERENCE].ncall = value - ptr[NETDATA_DCSTAT_IDX_REFERENCE].pcall;
  424. ptr[NETDATA_DCSTAT_IDX_REFERENCE].pcall = value;
  425. value = dcstat_hash_values[NETDATA_KEY_DC_SLOW];
  426. ptr[NETDATA_DCSTAT_IDX_SLOW].ncall = value - ptr[NETDATA_DCSTAT_IDX_SLOW].pcall;
  427. ptr[NETDATA_DCSTAT_IDX_SLOW].pcall = value;
  428. value = dcstat_hash_values[NETDATA_KEY_DC_MISS];
  429. ptr[NETDATA_DCSTAT_IDX_MISS].ncall = value - ptr[NETDATA_DCSTAT_IDX_MISS].pcall;
  430. ptr[NETDATA_DCSTAT_IDX_MISS].pcall = value;
  431. } else {
  432. ptr[NETDATA_DCSTAT_IDX_REFERENCE].ncall = 0;
  433. ptr[NETDATA_DCSTAT_IDX_SLOW].ncall = 0;
  434. ptr[NETDATA_DCSTAT_IDX_MISS].ncall = 0;
  435. }
  436. ebpf_one_dimension_write_charts(NETDATA_FILESYSTEM_FAMILY, NETDATA_DC_HIT_CHART,
  437. ptr[NETDATA_DCSTAT_IDX_RATIO].dimension, publish->ratio);
  438. write_count_chart(
  439. NETDATA_DC_REFERENCE_CHART, NETDATA_FILESYSTEM_FAMILY,
  440. &dcstat_counter_publish_aggregated[NETDATA_DCSTAT_IDX_REFERENCE], 3);
  441. }
  442. /**
  443. * Create specific directory cache charts
  444. *
  445. * Create charts for cgroup/application.
  446. *
  447. * @param type the chart type.
  448. * @param update_every value to overwrite the update frequency set by the server.
  449. */
  450. static void ebpf_create_specific_dc_charts(char *type, int update_every)
  451. {
  452. ebpf_create_chart(type, NETDATA_DC_HIT_CHART, "Percentage of files inside directory cache",
  453. EBPF_COMMON_DIMENSION_PERCENTAGE, NETDATA_DIRECTORY_CACHE_SUBMENU,
  454. NETDATA_CGROUP_DC_HIT_RATIO_CONTEXT, NETDATA_EBPF_CHART_TYPE_LINE,
  455. NETDATA_CHART_PRIO_CGROUPS_CONTAINERS + 5700,
  456. ebpf_create_global_dimension,
  457. dcstat_counter_publish_aggregated, 1, update_every, NETDATA_EBPF_MODULE_NAME_DCSTAT);
  458. ebpf_create_chart(type, NETDATA_DC_REFERENCE_CHART, "Count file access",
  459. EBPF_COMMON_DIMENSION_FILES, NETDATA_DIRECTORY_CACHE_SUBMENU,
  460. NETDATA_CGROUP_DC_REFERENCE_CONTEXT, NETDATA_EBPF_CHART_TYPE_LINE,
  461. NETDATA_CHART_PRIO_CGROUPS_CONTAINERS + 5701,
  462. ebpf_create_global_dimension,
  463. &dcstat_counter_publish_aggregated[NETDATA_DCSTAT_IDX_REFERENCE], 1,
  464. update_every, NETDATA_EBPF_MODULE_NAME_DCSTAT);
  465. ebpf_create_chart(type, NETDATA_DC_REQUEST_NOT_CACHE_CHART,
  466. "Files not present inside directory cache",
  467. EBPF_COMMON_DIMENSION_FILES, NETDATA_DIRECTORY_CACHE_SUBMENU,
  468. NETDATA_CGROUP_DC_NOT_CACHE_CONTEXT, NETDATA_EBPF_CHART_TYPE_LINE,
  469. NETDATA_CHART_PRIO_CGROUPS_CONTAINERS + 5702,
  470. ebpf_create_global_dimension,
  471. &dcstat_counter_publish_aggregated[NETDATA_DCSTAT_IDX_SLOW], 1,
  472. update_every, NETDATA_EBPF_MODULE_NAME_DCSTAT);
  473. ebpf_create_chart(type, NETDATA_DC_REQUEST_NOT_FOUND_CHART,
  474. "Files not found",
  475. EBPF_COMMON_DIMENSION_FILES, NETDATA_DIRECTORY_CACHE_SUBMENU,
  476. NETDATA_CGROUP_DC_NOT_FOUND_CONTEXT, NETDATA_EBPF_CHART_TYPE_LINE,
  477. NETDATA_CHART_PRIO_CGROUPS_CONTAINERS + 5703,
  478. ebpf_create_global_dimension,
  479. &dcstat_counter_publish_aggregated[NETDATA_DCSTAT_IDX_MISS], 1,
  480. update_every, NETDATA_EBPF_MODULE_NAME_DCSTAT);
  481. }
  482. /**
  483. * Obsolete specific directory cache charts
  484. *
  485. * Obsolete charts for cgroup/application.
  486. *
  487. * @param type the chart type.
  488. * @param update_every value to overwrite the update frequency set by the server.
  489. */
  490. static void ebpf_obsolete_specific_dc_charts(char *type, int update_every)
  491. {
  492. ebpf_write_chart_obsolete(type, NETDATA_DC_HIT_CHART,
  493. "Percentage of files inside directory cache",
  494. EBPF_COMMON_DIMENSION_PERCENTAGE, NETDATA_DIRECTORY_CACHE_SUBMENU,
  495. NETDATA_EBPF_CHART_TYPE_LINE, NETDATA_CGROUP_DC_HIT_RATIO_CONTEXT,
  496. NETDATA_CHART_PRIO_CGROUPS_CONTAINERS + 5700, update_every);
  497. ebpf_write_chart_obsolete(type, NETDATA_DC_REFERENCE_CHART,
  498. "Count file access",
  499. EBPF_COMMON_DIMENSION_FILES, NETDATA_DIRECTORY_CACHE_SUBMENU,
  500. NETDATA_EBPF_CHART_TYPE_LINE, NETDATA_CGROUP_DC_REFERENCE_CONTEXT,
  501. NETDATA_CHART_PRIO_CGROUPS_CONTAINERS + 5701, update_every);
  502. ebpf_write_chart_obsolete(type, NETDATA_DC_REQUEST_NOT_CACHE_CHART,
  503. "Files not present inside directory cache",
  504. EBPF_COMMON_DIMENSION_FILES, NETDATA_DIRECTORY_CACHE_SUBMENU,
  505. NETDATA_EBPF_CHART_TYPE_LINE, NETDATA_CGROUP_DC_NOT_CACHE_CONTEXT,
  506. NETDATA_CHART_PRIO_CGROUPS_CONTAINERS + 5702, update_every);
  507. ebpf_write_chart_obsolete(type, NETDATA_DC_REQUEST_NOT_FOUND_CHART,
  508. "Files not found",
  509. EBPF_COMMON_DIMENSION_FILES, NETDATA_DIRECTORY_CACHE_SUBMENU,
  510. NETDATA_EBPF_CHART_TYPE_LINE, NETDATA_CGROUP_DC_NOT_FOUND_CONTEXT,
  511. NETDATA_CHART_PRIO_CGROUPS_CONTAINERS + 5703, update_every);
  512. }
  513. /**
  514. * Cachestat sum PIDs
  515. *
  516. * Sum values for all PIDs associated to a group
  517. *
  518. * @param publish output structure.
  519. * @param root structure with listed IPs
  520. */
  521. void ebpf_dc_sum_cgroup_pids(netdata_publish_dcstat_t *publish, struct pid_on_target2 *root)
  522. {
  523. memset(&publish->curr, 0, sizeof(netdata_dcstat_pid_t));
  524. netdata_dcstat_pid_t *dst = &publish->curr;
  525. while (root) {
  526. netdata_dcstat_pid_t *src = &root->dc;
  527. dst->cache_access += src->cache_access;
  528. dst->file_system += src->file_system;
  529. dst->not_found += src->not_found;
  530. root = root->next;
  531. }
  532. }
  533. /**
  534. * Calc chart values
  535. *
  536. * Do necessary math to plot charts.
  537. */
  538. void ebpf_dc_calc_chart_values()
  539. {
  540. ebpf_cgroup_target_t *ect;
  541. for (ect = ebpf_cgroup_pids; ect ; ect = ect->next) {
  542. ebpf_dc_sum_cgroup_pids(&ect->publish_dc, ect->pids);
  543. uint64_t cache = ect->publish_dc.curr.cache_access;
  544. uint64_t not_found = ect->publish_dc.curr.not_found;
  545. dcstat_update_publish(&ect->publish_dc, cache, not_found);
  546. ect->publish_dc.cache_access = (long long)ect->publish_dc.curr.cache_access -
  547. (long long)ect->publish_dc.prev.cache_access;
  548. ect->publish_dc.prev.cache_access = ect->publish_dc.curr.cache_access;
  549. if (ect->publish_dc.curr.not_found < ect->publish_dc.prev.not_found) {
  550. ect->publish_dc.prev.not_found = 0;
  551. }
  552. }
  553. }
  554. /**
  555. * Create Systemd directory cache Charts
  556. *
  557. * Create charts when systemd is enabled
  558. *
  559. * @param update_every value to overwrite the update frequency set by the server.
  560. **/
  561. static void ebpf_create_systemd_dc_charts(int update_every)
  562. {
  563. ebpf_create_charts_on_systemd(NETDATA_DC_HIT_CHART,
  564. "Percentage of files inside directory cache",
  565. EBPF_COMMON_DIMENSION_PERCENTAGE,
  566. NETDATA_DIRECTORY_CACHE_SUBMENU,
  567. NETDATA_EBPF_CHART_TYPE_LINE,
  568. 21200,
  569. ebpf_algorithms[NETDATA_EBPF_ABSOLUTE_IDX],
  570. NETDATA_SYSTEMD_DC_HIT_RATIO_CONTEXT, NETDATA_EBPF_MODULE_NAME_DCSTAT,
  571. update_every);
  572. ebpf_create_charts_on_systemd(NETDATA_DC_REFERENCE_CHART,
  573. "Count file access",
  574. EBPF_COMMON_DIMENSION_FILES,
  575. NETDATA_DIRECTORY_CACHE_SUBMENU,
  576. NETDATA_EBPF_CHART_TYPE_LINE,
  577. 21201,
  578. ebpf_algorithms[NETDATA_EBPF_ABSOLUTE_IDX],
  579. NETDATA_SYSTEMD_DC_REFERENCE_CONTEXT, NETDATA_EBPF_MODULE_NAME_DCSTAT,
  580. update_every);
  581. ebpf_create_charts_on_systemd(NETDATA_DC_REQUEST_NOT_CACHE_CHART,
  582. "Files not present inside directory cache",
  583. EBPF_COMMON_DIMENSION_FILES,
  584. NETDATA_DIRECTORY_CACHE_SUBMENU,
  585. NETDATA_EBPF_CHART_TYPE_LINE,
  586. 21202,
  587. ebpf_algorithms[NETDATA_EBPF_ABSOLUTE_IDX],
  588. NETDATA_SYSTEMD_DC_NOT_CACHE_CONTEXT, NETDATA_EBPF_MODULE_NAME_DCSTAT,
  589. update_every);
  590. ebpf_create_charts_on_systemd(NETDATA_DC_REQUEST_NOT_FOUND_CHART,
  591. "Files not found",
  592. EBPF_COMMON_DIMENSION_FILES,
  593. NETDATA_DIRECTORY_CACHE_SUBMENU,
  594. NETDATA_EBPF_CHART_TYPE_LINE,
  595. 21202,
  596. ebpf_algorithms[NETDATA_EBPF_ABSOLUTE_IDX],
  597. NETDATA_SYSTEMD_DC_NOT_FOUND_CONTEXT, NETDATA_EBPF_MODULE_NAME_DCSTAT,
  598. update_every);
  599. }
  600. /**
  601. * Send Directory Cache charts
  602. *
  603. * Send collected data to Netdata.
  604. *
  605. * @return It returns the status for chart creation, if it is necessary to remove a specific dimension, zero is returned
  606. * otherwise function returns 1 to avoid chart recreation
  607. */
  608. static int ebpf_send_systemd_dc_charts()
  609. {
  610. int ret = 1;
  611. collected_number value;
  612. ebpf_cgroup_target_t *ect;
  613. write_begin_chart(NETDATA_SERVICE_FAMILY, NETDATA_DC_HIT_CHART);
  614. for (ect = ebpf_cgroup_pids; ect ; ect = ect->next) {
  615. if (unlikely(ect->systemd) && unlikely(ect->updated)) {
  616. write_chart_dimension(ect->name, (long long) ect->publish_dc.ratio);
  617. } else
  618. ret = 0;
  619. }
  620. write_end_chart();
  621. write_begin_chart(NETDATA_SERVICE_FAMILY, NETDATA_DC_REFERENCE_CHART);
  622. for (ect = ebpf_cgroup_pids; ect ; ect = ect->next) {
  623. if (unlikely(ect->systemd) && unlikely(ect->updated)) {
  624. write_chart_dimension(ect->name, (long long) ect->publish_dc.cache_access);
  625. }
  626. }
  627. write_end_chart();
  628. write_begin_chart(NETDATA_SERVICE_FAMILY, NETDATA_DC_REQUEST_NOT_CACHE_CHART);
  629. for (ect = ebpf_cgroup_pids; ect ; ect = ect->next) {
  630. if (unlikely(ect->systemd) && unlikely(ect->updated)) {
  631. value = (collected_number) (!ect->publish_dc.cache_access) ? 0 :
  632. (long long )ect->publish_dc.curr.file_system - (long long)ect->publish_dc.prev.file_system;
  633. ect->publish_dc.prev.file_system = ect->publish_dc.curr.file_system;
  634. write_chart_dimension(ect->name, (long long) value);
  635. }
  636. }
  637. write_end_chart();
  638. write_begin_chart(NETDATA_SERVICE_FAMILY, NETDATA_DC_REQUEST_NOT_FOUND_CHART);
  639. for (ect = ebpf_cgroup_pids; ect ; ect = ect->next) {
  640. if (unlikely(ect->systemd) && unlikely(ect->updated)) {
  641. value = (collected_number) (!ect->publish_dc.cache_access) ? 0 :
  642. (long long)ect->publish_dc.curr.not_found - (long long)ect->publish_dc.prev.not_found;
  643. ect->publish_dc.prev.not_found = ect->publish_dc.curr.not_found;
  644. write_chart_dimension(ect->name, (long long) value);
  645. }
  646. }
  647. write_end_chart();
  648. return ret;
  649. }
  650. /**
  651. * Send Directory Cache charts
  652. *
  653. * Send collected data to Netdata.
  654. *
  655. */
  656. static void ebpf_send_specific_dc_data(char *type, netdata_publish_dcstat_t *pdc)
  657. {
  658. collected_number value;
  659. write_begin_chart(type, NETDATA_DC_HIT_CHART);
  660. write_chart_dimension(dcstat_counter_publish_aggregated[NETDATA_DCSTAT_IDX_RATIO].name,
  661. (long long) pdc->ratio);
  662. write_end_chart();
  663. write_begin_chart(type, NETDATA_DC_REFERENCE_CHART);
  664. write_chart_dimension(dcstat_counter_publish_aggregated[NETDATA_DCSTAT_IDX_REFERENCE].name,
  665. (long long) pdc->cache_access);
  666. write_end_chart();
  667. value = (collected_number) (!pdc->cache_access) ? 0 :
  668. (long long )pdc->curr.file_system - (long long)pdc->prev.file_system;
  669. pdc->prev.file_system = pdc->curr.file_system;
  670. write_begin_chart(type, NETDATA_DC_REQUEST_NOT_CACHE_CHART);
  671. write_chart_dimension(dcstat_counter_publish_aggregated[NETDATA_DCSTAT_IDX_SLOW].name, (long long) value);
  672. write_end_chart();
  673. value = (collected_number) (!pdc->cache_access) ? 0 :
  674. (long long)pdc->curr.not_found - (long long)pdc->prev.not_found;
  675. pdc->prev.not_found = pdc->curr.not_found;
  676. write_begin_chart(type, NETDATA_DC_REQUEST_NOT_FOUND_CHART);
  677. write_chart_dimension(dcstat_counter_publish_aggregated[NETDATA_DCSTAT_IDX_MISS].name, (long long) value);
  678. write_end_chart();
  679. }
  680. /**
  681. * Send data to Netdata calling auxiliary functions.
  682. *
  683. * @param update_every value to overwrite the update frequency set by the server.
  684. */
  685. void ebpf_dc_send_cgroup_data(int update_every)
  686. {
  687. if (!ebpf_cgroup_pids)
  688. return;
  689. pthread_mutex_lock(&mutex_cgroup_shm);
  690. ebpf_cgroup_target_t *ect;
  691. ebpf_dc_calc_chart_values();
  692. int has_systemd = shm_ebpf_cgroup.header->systemd_enabled;
  693. if (has_systemd) {
  694. static int systemd_charts = 0;
  695. if (!systemd_charts) {
  696. ebpf_create_systemd_dc_charts(update_every);
  697. systemd_charts = 1;
  698. }
  699. systemd_charts = ebpf_send_systemd_dc_charts();
  700. }
  701. for (ect = ebpf_cgroup_pids; ect ; ect = ect->next) {
  702. if (ect->systemd)
  703. continue;
  704. if (!(ect->flags & NETDATA_EBPF_CGROUP_HAS_DC_CHART) && ect->updated) {
  705. ebpf_create_specific_dc_charts(ect->name, update_every);
  706. ect->flags |= NETDATA_EBPF_CGROUP_HAS_DC_CHART;
  707. }
  708. if (ect->flags & NETDATA_EBPF_CGROUP_HAS_DC_CHART) {
  709. if (ect->updated) {
  710. ebpf_send_specific_dc_data(ect->name, &ect->publish_dc);
  711. } else {
  712. ebpf_obsolete_specific_dc_charts(ect->name, update_every);
  713. ect->flags &= ~NETDATA_EBPF_CGROUP_HAS_DC_CHART;
  714. }
  715. }
  716. }
  717. pthread_mutex_unlock(&mutex_cgroup_shm);
  718. }
  719. /**
  720. * Main loop for this collector.
  721. */
  722. static void dcstat_collector(ebpf_module_t *em)
  723. {
  724. dcstat_threads.thread = mallocz(sizeof(netdata_thread_t));
  725. dcstat_threads.start_routine = ebpf_dcstat_read_hash;
  726. netdata_thread_create(dcstat_threads.thread, dcstat_threads.name, NETDATA_THREAD_OPTION_JOINABLE,
  727. ebpf_dcstat_read_hash, em);
  728. netdata_publish_dcstat_t publish;
  729. memset(&publish, 0, sizeof(publish));
  730. int apps = em->apps_charts;
  731. int cgroups = em->cgroup_charts;
  732. int update_every = em->update_every;
  733. int counter = update_every - 1;
  734. while (!close_ebpf_plugin) {
  735. pthread_mutex_lock(&collect_data_mutex);
  736. pthread_cond_wait(&collect_data_cond_var, &collect_data_mutex);
  737. if (++counter == update_every) {
  738. counter = 0;
  739. if (apps)
  740. read_apps_table();
  741. if (cgroups)
  742. ebpf_update_dc_cgroup();
  743. pthread_mutex_lock(&lock);
  744. dcstat_send_global(&publish);
  745. if (apps)
  746. ebpf_dcache_send_apps_data(apps_groups_root_target);
  747. if (cgroups)
  748. ebpf_dc_send_cgroup_data(update_every);
  749. pthread_mutex_unlock(&lock);
  750. }
  751. pthread_mutex_unlock(&collect_data_mutex);
  752. }
  753. }
  754. /*****************************************************************
  755. *
  756. * INITIALIZE THREAD
  757. *
  758. *****************************************************************/
  759. /**
  760. * Create filesystem charts
  761. *
  762. * Call ebpf_create_chart to create the charts for the collector.
  763. *
  764. * @param update_every value to overwrite the update frequency set by the server.
  765. */
  766. static void ebpf_create_filesystem_charts(int update_every)
  767. {
  768. ebpf_create_chart(NETDATA_FILESYSTEM_FAMILY, NETDATA_DC_HIT_CHART,
  769. "Percentage of files inside directory cache",
  770. EBPF_COMMON_DIMENSION_PERCENTAGE, NETDATA_DIRECTORY_CACHE_SUBMENU,
  771. NULL,
  772. NETDATA_EBPF_CHART_TYPE_LINE,
  773. 21200,
  774. ebpf_create_global_dimension,
  775. dcstat_counter_publish_aggregated, 1, update_every, NETDATA_EBPF_MODULE_NAME_DCSTAT);
  776. ebpf_create_chart(NETDATA_FILESYSTEM_FAMILY, NETDATA_DC_REFERENCE_CHART,
  777. "Variables used to calculate hit ratio.",
  778. EBPF_COMMON_DIMENSION_FILES, NETDATA_DIRECTORY_CACHE_SUBMENU,
  779. NULL,
  780. NETDATA_EBPF_CHART_TYPE_LINE,
  781. 21201,
  782. ebpf_create_global_dimension,
  783. &dcstat_counter_publish_aggregated[NETDATA_DCSTAT_IDX_REFERENCE], 3,
  784. update_every, NETDATA_EBPF_MODULE_NAME_DCSTAT);
  785. fflush(stdout);
  786. }
  787. /**
  788. * Allocate vectors used with this thread.
  789. *
  790. * We are not testing the return, because callocz does this and shutdown the software
  791. * case it was not possible to allocate.
  792. *
  793. * @param apps is apps enabled?
  794. */
  795. static void ebpf_dcstat_allocate_global_vectors(int apps)
  796. {
  797. if (apps)
  798. dcstat_pid = callocz((size_t)pid_max, sizeof(netdata_publish_dcstat_t *));
  799. dcstat_vector = callocz((size_t)ebpf_nprocs, sizeof(netdata_dcstat_pid_t));
  800. dcstat_values = callocz((size_t)ebpf_nprocs, sizeof(netdata_idx_t));
  801. memset(dcstat_counter_aggregated_data, 0, NETDATA_DCSTAT_IDX_END * sizeof(netdata_syscall_stat_t));
  802. memset(dcstat_counter_publish_aggregated, 0, NETDATA_DCSTAT_IDX_END * sizeof(netdata_publish_syscall_t));
  803. }
  804. /*****************************************************************
  805. *
  806. * MAIN THREAD
  807. *
  808. *****************************************************************/
  809. /**
  810. * Directory Cache thread
  811. *
  812. * Thread used to make dcstat thread
  813. *
  814. * @param ptr a pointer to `struct ebpf_module`
  815. *
  816. * @return It always returns NULL
  817. */
  818. void *ebpf_dcstat_thread(void *ptr)
  819. {
  820. netdata_thread_cleanup_push(ebpf_dcstat_cleanup, ptr);
  821. ebpf_module_t *em = (ebpf_module_t *)ptr;
  822. em->maps = dcstat_maps;
  823. ebpf_update_pid_table(&dcstat_maps[NETDATA_DCSTAT_PID_STATS], em);
  824. ebpf_update_names(dc_optional_name, em);
  825. if (!em->enabled)
  826. goto enddcstat;
  827. ebpf_dcstat_allocate_global_vectors(em->apps_charts);
  828. pthread_mutex_lock(&lock);
  829. probe_links = ebpf_load_program(ebpf_plugin_dir, em, running_on_kernel, isrh, &objects);
  830. if (!probe_links) {
  831. pthread_mutex_unlock(&lock);
  832. em->enabled = CONFIG_BOOLEAN_NO;
  833. goto enddcstat;
  834. }
  835. int algorithms[NETDATA_DCSTAT_IDX_END] = {
  836. NETDATA_EBPF_ABSOLUTE_IDX, NETDATA_EBPF_ABSOLUTE_IDX, NETDATA_EBPF_ABSOLUTE_IDX,
  837. NETDATA_EBPF_ABSOLUTE_IDX
  838. };
  839. ebpf_global_labels(dcstat_counter_aggregated_data, dcstat_counter_publish_aggregated,
  840. dcstat_counter_dimension_name, dcstat_counter_dimension_name,
  841. algorithms, NETDATA_DCSTAT_IDX_END);
  842. ebpf_create_filesystem_charts(em->update_every);
  843. ebpf_update_stats(&plugin_statistics, em);
  844. pthread_mutex_unlock(&lock);
  845. dcstat_collector(em);
  846. enddcstat:
  847. if (!em->enabled)
  848. ebpf_update_disabled_plugin_stats(em);
  849. netdata_thread_cleanup_pop(1);
  850. return NULL;
  851. }