ebpf_swap.c 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703
  1. // SPDX-License-Identifier: GPL-3.0-or-later
  2. #include "ebpf.h"
  3. #include "ebpf_swap.h"
  4. static char *swap_dimension_name[NETDATA_SWAP_END] = { "read", "write" };
  5. static netdata_syscall_stat_t swap_aggregated_data[NETDATA_SWAP_END];
  6. static netdata_publish_syscall_t swap_publish_aggregated[NETDATA_SWAP_END];
  7. static int read_thread_closed = 1;
  8. netdata_publish_swap_t *swap_vector = NULL;
  9. static netdata_idx_t swap_hash_values[NETDATA_SWAP_END];
  10. static netdata_idx_t *swap_values = NULL;
  11. netdata_publish_swap_t **swap_pid = NULL;
  12. struct config swap_config = { .first_section = NULL,
  13. .last_section = NULL,
  14. .mutex = NETDATA_MUTEX_INITIALIZER,
  15. .index = { .avl_tree = { .root = NULL, .compar = appconfig_section_compare },
  16. .rwlock = AVL_LOCK_INITIALIZER } };
  17. static ebpf_local_maps_t swap_maps[] = {{.name = "tbl_pid_swap", .internal_input = ND_EBPF_DEFAULT_PID_SIZE,
  18. .user_input = 0,
  19. .type = NETDATA_EBPF_MAP_RESIZABLE | NETDATA_EBPF_MAP_PID,
  20. .map_fd = ND_EBPF_MAP_FD_NOT_INITIALIZED},
  21. {.name = "swap_ctrl", .internal_input = NETDATA_CONTROLLER_END,
  22. .user_input = 0,
  23. .type = NETDATA_EBPF_MAP_CONTROLLER,
  24. .map_fd = ND_EBPF_MAP_FD_NOT_INITIALIZED},
  25. {.name = "tbl_swap", .internal_input = NETDATA_SWAP_END,
  26. .user_input = 0,
  27. .type = NETDATA_EBPF_MAP_STATIC,
  28. .map_fd = ND_EBPF_MAP_FD_NOT_INITIALIZED},
  29. {.name = NULL, .internal_input = 0, .user_input = 0}};
  30. static struct bpf_link **probe_links = NULL;
  31. static struct bpf_object *objects = NULL;
  32. struct netdata_static_thread swap_threads = {"SWAP KERNEL", NULL, NULL, 1,
  33. NULL, NULL, NULL};
  34. /*****************************************************************
  35. *
  36. * FUNCTIONS TO CLOSE THE THREAD
  37. *
  38. *****************************************************************/
  39. /**
  40. * Clean swap structure
  41. */
  42. void clean_swap_pid_structures() {
  43. struct pid_stat *pids = root_of_pids;
  44. while (pids) {
  45. freez(swap_pid[pids->pid]);
  46. pids = pids->next;
  47. }
  48. }
  49. /**
  50. * Clean up the main thread.
  51. *
  52. * @param ptr thread data.
  53. */
  54. static void ebpf_swap_cleanup(void *ptr)
  55. {
  56. ebpf_module_t *em = (ebpf_module_t *)ptr;
  57. if (!em->enabled)
  58. return;
  59. heartbeat_t hb;
  60. heartbeat_init(&hb);
  61. uint32_t tick = 2 * USEC_PER_MS;
  62. while (!read_thread_closed) {
  63. usec_t dt = heartbeat_next(&hb, tick);
  64. UNUSED(dt);
  65. }
  66. ebpf_cleanup_publish_syscall(swap_publish_aggregated);
  67. freez(swap_vector);
  68. freez(swap_values);
  69. if (probe_links) {
  70. struct bpf_program *prog;
  71. size_t i = 0 ;
  72. bpf_object__for_each_program(prog, objects) {
  73. bpf_link__destroy(probe_links[i]);
  74. i++;
  75. }
  76. bpf_object__close(objects);
  77. }
  78. }
  79. /*****************************************************************
  80. *
  81. * COLLECTOR THREAD
  82. *
  83. *****************************************************************/
  84. /**
  85. * Apps Accumulator
  86. *
  87. * Sum all values read from kernel and store in the first address.
  88. *
  89. * @param out the vector with read values.
  90. */
  91. static void swap_apps_accumulator(netdata_publish_swap_t *out)
  92. {
  93. int i, end = (running_on_kernel >= NETDATA_KERNEL_V4_15) ? ebpf_nprocs : 1;
  94. netdata_publish_swap_t *total = &out[0];
  95. for (i = 1; i < end; i++) {
  96. netdata_publish_swap_t *w = &out[i];
  97. total->write += w->write;
  98. total->read += w->read;
  99. }
  100. }
  101. /**
  102. * Fill PID
  103. *
  104. * Fill PID structures
  105. *
  106. * @param current_pid pid that we are collecting data
  107. * @param out values read from hash tables;
  108. */
  109. static void swap_fill_pid(uint32_t current_pid, netdata_publish_swap_t *publish)
  110. {
  111. netdata_publish_swap_t *curr = swap_pid[current_pid];
  112. if (!curr) {
  113. curr = callocz(1, sizeof(netdata_publish_swap_t));
  114. swap_pid[current_pid] = curr;
  115. }
  116. memcpy(curr, publish, sizeof(netdata_publish_swap_t));
  117. }
  118. /**
  119. * Update cgroup
  120. *
  121. * Update cgroup data based in
  122. */
  123. static void ebpf_update_swap_cgroup()
  124. {
  125. ebpf_cgroup_target_t *ect ;
  126. netdata_publish_swap_t *cv = swap_vector;
  127. int fd = swap_maps[NETDATA_PID_SWAP_TABLE].map_fd;
  128. size_t length = sizeof(netdata_publish_swap_t)*ebpf_nprocs;
  129. pthread_mutex_lock(&mutex_cgroup_shm);
  130. for (ect = ebpf_cgroup_pids; ect; ect = ect->next) {
  131. struct pid_on_target2 *pids;
  132. for (pids = ect->pids; pids; pids = pids->next) {
  133. int pid = pids->pid;
  134. netdata_publish_swap_t *out = &pids->swap;
  135. if (likely(swap_pid) && swap_pid[pid]) {
  136. netdata_publish_swap_t *in = swap_pid[pid];
  137. memcpy(out, in, sizeof(netdata_publish_swap_t));
  138. } else {
  139. memset(cv, 0, length);
  140. if (!bpf_map_lookup_elem(fd, &pid, cv)) {
  141. swap_apps_accumulator(cv);
  142. memcpy(out, cv, sizeof(netdata_publish_swap_t));
  143. }
  144. }
  145. }
  146. }
  147. pthread_mutex_unlock(&mutex_cgroup_shm);
  148. }
  149. /**
  150. * Read APPS table
  151. *
  152. * Read the apps table and store data inside the structure.
  153. */
  154. static void read_apps_table()
  155. {
  156. netdata_publish_swap_t *cv = swap_vector;
  157. uint32_t key;
  158. struct pid_stat *pids = root_of_pids;
  159. int fd = swap_maps[NETDATA_PID_SWAP_TABLE].map_fd;
  160. size_t length = sizeof(netdata_publish_swap_t)*ebpf_nprocs;
  161. while (pids) {
  162. key = pids->pid;
  163. if (bpf_map_lookup_elem(fd, &key, cv)) {
  164. pids = pids->next;
  165. continue;
  166. }
  167. swap_apps_accumulator(cv);
  168. swap_fill_pid(key, cv);
  169. // We are cleaning to avoid passing data read from one process to other.
  170. memset(cv, 0, length);
  171. pids = pids->next;
  172. }
  173. }
  174. /**
  175. * Send global
  176. *
  177. * Send global charts to Netdata
  178. */
  179. static void swap_send_global()
  180. {
  181. write_io_chart(NETDATA_MEM_SWAP_CHART, NETDATA_EBPF_SYSTEM_GROUP,
  182. swap_publish_aggregated[NETDATA_KEY_SWAP_WRITEPAGE_CALL].dimension,
  183. (long long) swap_hash_values[NETDATA_KEY_SWAP_WRITEPAGE_CALL],
  184. swap_publish_aggregated[NETDATA_KEY_SWAP_READPAGE_CALL].dimension,
  185. (long long) swap_hash_values[NETDATA_KEY_SWAP_READPAGE_CALL]);
  186. }
  187. /**
  188. * Read global counter
  189. *
  190. * Read the table with number of calls to all functions
  191. */
  192. static void read_global_table()
  193. {
  194. netdata_idx_t *stored = swap_values;
  195. netdata_idx_t *val = swap_hash_values;
  196. int fd = swap_maps[NETDATA_SWAP_GLOBAL_TABLE].map_fd;
  197. uint32_t i, end = NETDATA_SWAP_END;
  198. for (i = NETDATA_KEY_SWAP_READPAGE_CALL; i < end; i++) {
  199. if (!bpf_map_lookup_elem(fd, &i, stored)) {
  200. int j;
  201. int last = ebpf_nprocs;
  202. netdata_idx_t total = 0;
  203. for (j = 0; j < last; j++)
  204. total += stored[j];
  205. val[i] = total;
  206. }
  207. }
  208. }
  209. /**
  210. * Swap read hash
  211. *
  212. * This is the thread callback.
  213. *
  214. * @param ptr It is a NULL value for this thread.
  215. *
  216. * @return It always returns NULL.
  217. */
  218. void *ebpf_swap_read_hash(void *ptr)
  219. {
  220. read_thread_closed = 0;
  221. heartbeat_t hb;
  222. heartbeat_init(&hb);
  223. ebpf_module_t *em = (ebpf_module_t *)ptr;
  224. usec_t step = NETDATA_SWAP_SLEEP_MS * em->update_every;
  225. while (!close_ebpf_plugin) {
  226. usec_t dt = heartbeat_next(&hb, step);
  227. (void)dt;
  228. read_global_table();
  229. }
  230. read_thread_closed = 1;
  231. return NULL;
  232. }
  233. /**
  234. * Sum PIDs
  235. *
  236. * Sum values for all targets.
  237. *
  238. * @param swap
  239. * @param root
  240. */
  241. static void ebpf_swap_sum_pids(netdata_publish_swap_t *swap, struct pid_on_target *root)
  242. {
  243. uint64_t local_read = 0;
  244. uint64_t local_write = 0;
  245. while (root) {
  246. int32_t pid = root->pid;
  247. netdata_publish_swap_t *w = swap_pid[pid];
  248. if (w) {
  249. local_write += w->write;
  250. local_read += w->read;
  251. }
  252. root = root->next;
  253. }
  254. // These conditions were added, because we are using incremental algorithm
  255. swap->write = (local_write >= swap->write) ? local_write : swap->write;
  256. swap->read = (local_read >= swap->read) ? local_read : swap->read;
  257. }
  258. /**
  259. * Send data to Netdata calling auxiliary functions.
  260. *
  261. * @param root the target list.
  262. */
  263. void ebpf_swap_send_apps_data(struct target *root)
  264. {
  265. struct target *w;
  266. for (w = root; w; w = w->next) {
  267. if (unlikely(w->exposed && w->processes)) {
  268. ebpf_swap_sum_pids(&w->swap, w->root_pid);
  269. }
  270. }
  271. write_begin_chart(NETDATA_APPS_FAMILY, NETDATA_MEM_SWAP_READ_CHART);
  272. for (w = root; w; w = w->next) {
  273. if (unlikely(w->exposed && w->processes)) {
  274. write_chart_dimension(w->name, (long long) w->swap.read);
  275. }
  276. }
  277. write_end_chart();
  278. write_begin_chart(NETDATA_APPS_FAMILY, NETDATA_MEM_SWAP_WRITE_CHART);
  279. for (w = root; w; w = w->next) {
  280. if (unlikely(w->exposed && w->processes)) {
  281. write_chart_dimension(w->name, (long long) w->swap.write);
  282. }
  283. }
  284. write_end_chart();
  285. }
  286. /**
  287. * Sum PIDs
  288. *
  289. * Sum values for all targets.
  290. *
  291. * @param swap
  292. * @param root
  293. */
  294. static void ebpf_swap_sum_cgroup_pids(netdata_publish_swap_t *swap, struct pid_on_target2 *pids)
  295. {
  296. uint64_t local_read = 0;
  297. uint64_t local_write = 0;
  298. while (pids) {
  299. netdata_publish_swap_t *w = &pids->swap;
  300. local_write += w->write;
  301. local_read += w->read;
  302. pids = pids->next;
  303. }
  304. // These conditions were added, because we are using incremental algorithm
  305. swap->write = (local_write >= swap->write) ? local_write : swap->write;
  306. swap->read = (local_read >= swap->read) ? local_read : swap->read;
  307. }
  308. /**
  309. * Send Systemd charts
  310. *
  311. * Send collected data to Netdata.
  312. *
  313. * @return It returns the status for chart creation, if it is necessary to remove a specific dimension, zero is returned
  314. * otherwise function returns 1 to avoid chart recreation
  315. */
  316. static int ebpf_send_systemd_swap_charts()
  317. {
  318. int ret = 1;
  319. ebpf_cgroup_target_t *ect;
  320. write_begin_chart(NETDATA_SERVICE_FAMILY, NETDATA_MEM_SWAP_READ_CHART);
  321. for (ect = ebpf_cgroup_pids; ect ; ect = ect->next) {
  322. if (unlikely(ect->systemd) && unlikely(ect->updated)) {
  323. write_chart_dimension(ect->name, (long long) ect->publish_systemd_swap.read);
  324. } else
  325. ret = 0;
  326. }
  327. write_end_chart();
  328. write_begin_chart(NETDATA_SERVICE_FAMILY, NETDATA_MEM_SWAP_WRITE_CHART);
  329. for (ect = ebpf_cgroup_pids; ect ; ect = ect->next) {
  330. if (unlikely(ect->systemd) && unlikely(ect->updated)) {
  331. write_chart_dimension(ect->name, (long long) ect->publish_systemd_swap.write);
  332. }
  333. }
  334. write_end_chart();
  335. return ret;
  336. }
  337. /**
  338. * Create specific swap charts
  339. *
  340. * Create charts for cgroup/application.
  341. *
  342. * @param type the chart type.
  343. * @param update_every value to overwrite the update frequency set by the server.
  344. */
  345. static void ebpf_create_specific_swap_charts(char *type, int update_every)
  346. {
  347. ebpf_create_chart(type, NETDATA_MEM_SWAP_READ_CHART,
  348. "Calls to function <code>swap_readpage</code>.",
  349. EBPF_COMMON_DIMENSION_CALL, NETDATA_SYSTEM_CGROUP_SWAP_SUBMENU,
  350. NETDATA_CGROUP_SWAP_READ_CONTEXT, NETDATA_EBPF_CHART_TYPE_LINE,
  351. NETDATA_CHART_PRIO_CGROUPS_CONTAINERS + 5100,
  352. ebpf_create_global_dimension,
  353. swap_publish_aggregated, 1, update_every, NETDATA_EBPF_MODULE_NAME_SWAP);
  354. ebpf_create_chart(type, NETDATA_MEM_SWAP_WRITE_CHART,
  355. "Calls to function <code>swap_writepage</code>.",
  356. EBPF_COMMON_DIMENSION_CALL, NETDATA_SYSTEM_CGROUP_SWAP_SUBMENU,
  357. NETDATA_CGROUP_SWAP_WRITE_CONTEXT, NETDATA_EBPF_CHART_TYPE_LINE,
  358. NETDATA_CHART_PRIO_CGROUPS_CONTAINERS + 5101,
  359. ebpf_create_global_dimension,
  360. &swap_publish_aggregated[NETDATA_KEY_SWAP_WRITEPAGE_CALL], 1,
  361. update_every, NETDATA_EBPF_MODULE_NAME_SWAP);
  362. }
  363. /**
  364. * Create specific swap charts
  365. *
  366. * Create charts for cgroup/application.
  367. *
  368. * @param type the chart type.
  369. * @param update_every value to overwrite the update frequency set by the server.
  370. */
  371. static void ebpf_obsolete_specific_swap_charts(char *type, int update_every)
  372. {
  373. ebpf_write_chart_obsolete(type, NETDATA_MEM_SWAP_READ_CHART,"Calls to function <code>swap_readpage</code>.",
  374. EBPF_COMMON_DIMENSION_CALL, NETDATA_SYSTEM_CGROUP_SWAP_SUBMENU,
  375. NETDATA_EBPF_CHART_TYPE_LINE, NETDATA_CGROUP_SWAP_READ_CONTEXT,
  376. NETDATA_CHART_PRIO_CGROUPS_CONTAINERS + 5100, update_every);
  377. ebpf_write_chart_obsolete(type, NETDATA_MEM_SWAP_WRITE_CHART, "Calls to function <code>swap_writepage</code>.",
  378. EBPF_COMMON_DIMENSION_CALL, NETDATA_SYSTEM_CGROUP_SWAP_SUBMENU,
  379. NETDATA_EBPF_CHART_TYPE_LINE, NETDATA_CGROUP_SWAP_WRITE_CONTEXT,
  380. NETDATA_CHART_PRIO_CGROUPS_CONTAINERS + 5101, update_every);
  381. }
  382. /*
  383. * Send Specific Swap data
  384. *
  385. * Send data for specific cgroup/apps.
  386. *
  387. * @param type chart type
  388. * @param values structure with values that will be sent to netdata
  389. */
  390. static void ebpf_send_specific_swap_data(char *type, netdata_publish_swap_t *values)
  391. {
  392. write_begin_chart(type, NETDATA_MEM_SWAP_READ_CHART);
  393. write_chart_dimension(swap_publish_aggregated[NETDATA_KEY_SWAP_READPAGE_CALL].name, (long long) values->read);
  394. write_end_chart();
  395. write_begin_chart(type, NETDATA_MEM_SWAP_WRITE_CHART);
  396. write_chart_dimension(swap_publish_aggregated[NETDATA_KEY_SWAP_WRITEPAGE_CALL].name, (long long) values->write);
  397. write_end_chart();
  398. }
  399. /**
  400. * Create Systemd Swap Charts
  401. *
  402. * Create charts when systemd is enabled
  403. *
  404. * @param update_every value to overwrite the update frequency set by the server.
  405. **/
  406. static void ebpf_create_systemd_swap_charts(int update_every)
  407. {
  408. ebpf_create_charts_on_systemd(NETDATA_MEM_SWAP_READ_CHART,
  409. "Calls to <code>swap_readpage</code>.",
  410. EBPF_COMMON_DIMENSION_CALL, NETDATA_SYSTEM_CGROUP_SWAP_SUBMENU,
  411. NETDATA_EBPF_CHART_TYPE_STACKED, 20191,
  412. ebpf_algorithms[NETDATA_EBPF_INCREMENTAL_IDX], NETDATA_SYSTEMD_SWAP_READ_CONTEXT,
  413. NETDATA_EBPF_MODULE_NAME_SWAP, update_every);
  414. ebpf_create_charts_on_systemd(NETDATA_MEM_SWAP_WRITE_CHART,
  415. "Calls to function <code>swap_writepage</code>.",
  416. EBPF_COMMON_DIMENSION_CALL, NETDATA_SYSTEM_CGROUP_SWAP_SUBMENU,
  417. NETDATA_EBPF_CHART_TYPE_STACKED, 20192,
  418. ebpf_algorithms[NETDATA_EBPF_INCREMENTAL_IDX], NETDATA_SYSTEMD_SWAP_WRITE_CONTEXT,
  419. NETDATA_EBPF_MODULE_NAME_SWAP, update_every);
  420. }
  421. /**
  422. * Send data to Netdata calling auxiliary functions.
  423. *
  424. * @param update_every value to overwrite the update frequency set by the server.
  425. */
  426. void ebpf_swap_send_cgroup_data(int update_every)
  427. {
  428. if (!ebpf_cgroup_pids)
  429. return;
  430. pthread_mutex_lock(&mutex_cgroup_shm);
  431. ebpf_cgroup_target_t *ect;
  432. for (ect = ebpf_cgroup_pids; ect ; ect = ect->next) {
  433. ebpf_swap_sum_cgroup_pids(&ect->publish_systemd_swap, ect->pids);
  434. }
  435. int has_systemd = shm_ebpf_cgroup.header->systemd_enabled;
  436. if (has_systemd) {
  437. static int systemd_charts = 0;
  438. if (!systemd_charts) {
  439. ebpf_create_systemd_swap_charts(update_every);
  440. systemd_charts = 1;
  441. fflush(stdout);
  442. }
  443. systemd_charts = ebpf_send_systemd_swap_charts();
  444. }
  445. for (ect = ebpf_cgroup_pids; ect ; ect = ect->next) {
  446. if (ect->systemd)
  447. continue;
  448. if (!(ect->flags & NETDATA_EBPF_CGROUP_HAS_SWAP_CHART) && ect->updated) {
  449. ebpf_create_specific_swap_charts(ect->name, update_every);
  450. ect->flags |= NETDATA_EBPF_CGROUP_HAS_SWAP_CHART;
  451. }
  452. if (ect->flags & NETDATA_EBPF_CGROUP_HAS_SWAP_CHART) {
  453. if (ect->updated) {
  454. ebpf_send_specific_swap_data(ect->name, &ect->publish_systemd_swap);
  455. } else {
  456. ebpf_obsolete_specific_swap_charts(ect->name, update_every);
  457. ect->flags &= ~NETDATA_EBPF_CGROUP_HAS_SWAP_CHART;
  458. }
  459. }
  460. }
  461. pthread_mutex_unlock(&mutex_cgroup_shm);
  462. }
  463. /**
  464. * Main loop for this collector.
  465. */
  466. static void swap_collector(ebpf_module_t *em)
  467. {
  468. swap_threads.thread = mallocz(sizeof(netdata_thread_t));
  469. swap_threads.start_routine = ebpf_swap_read_hash;
  470. netdata_thread_create(swap_threads.thread, swap_threads.name, NETDATA_THREAD_OPTION_JOINABLE,
  471. ebpf_swap_read_hash, em);
  472. int apps = em->apps_charts;
  473. int cgroup = em->cgroup_charts;
  474. int update_every = em->update_every;
  475. int counter = update_every - 1;
  476. while (!close_ebpf_plugin) {
  477. pthread_mutex_lock(&collect_data_mutex);
  478. pthread_cond_wait(&collect_data_cond_var, &collect_data_mutex);
  479. if (++counter == update_every) {
  480. counter = 0;
  481. if (apps)
  482. read_apps_table();
  483. if (cgroup)
  484. ebpf_update_swap_cgroup();
  485. pthread_mutex_lock(&lock);
  486. swap_send_global();
  487. if (apps)
  488. ebpf_swap_send_apps_data(apps_groups_root_target);
  489. if (cgroup)
  490. ebpf_swap_send_cgroup_data(update_every);
  491. pthread_mutex_unlock(&lock);
  492. }
  493. pthread_mutex_unlock(&collect_data_mutex);
  494. }
  495. }
  496. /*****************************************************************
  497. *
  498. * INITIALIZE THREAD
  499. *
  500. *****************************************************************/
  501. /**
  502. * Create apps charts
  503. *
  504. * Call ebpf_create_chart to create the charts on apps submenu.
  505. *
  506. * @param em a pointer to the structure with the default values.
  507. */
  508. void ebpf_swap_create_apps_charts(struct ebpf_module *em, void *ptr)
  509. {
  510. struct target *root = ptr;
  511. ebpf_create_charts_on_apps(NETDATA_MEM_SWAP_READ_CHART,
  512. "Calls to function <code>swap_readpage</code>.",
  513. EBPF_COMMON_DIMENSION_CALL,
  514. NETDATA_SWAP_SUBMENU,
  515. NETDATA_EBPF_CHART_TYPE_STACKED,
  516. 20191,
  517. ebpf_algorithms[NETDATA_EBPF_INCREMENTAL_IDX],
  518. root, em->update_every, NETDATA_EBPF_MODULE_NAME_SWAP);
  519. ebpf_create_charts_on_apps(NETDATA_MEM_SWAP_WRITE_CHART,
  520. "Calls to function <code>swap_writepage</code>.",
  521. EBPF_COMMON_DIMENSION_CALL,
  522. NETDATA_SWAP_SUBMENU,
  523. NETDATA_EBPF_CHART_TYPE_STACKED,
  524. 20192,
  525. ebpf_algorithms[NETDATA_EBPF_INCREMENTAL_IDX],
  526. root, em->update_every, NETDATA_EBPF_MODULE_NAME_SWAP);
  527. }
  528. /**
  529. * Allocate vectors used with this thread.
  530. *
  531. * We are not testing the return, because callocz does this and shutdown the software
  532. * case it was not possible to allocate.
  533. *
  534. * @param apps is apps enabled?
  535. */
  536. static void ebpf_swap_allocate_global_vectors(int apps)
  537. {
  538. if (apps)
  539. swap_pid = callocz((size_t)pid_max, sizeof(netdata_publish_swap_t *));
  540. swap_vector = callocz((size_t)ebpf_nprocs, sizeof(netdata_publish_swap_t));
  541. swap_values = callocz((size_t)ebpf_nprocs, sizeof(netdata_idx_t));
  542. memset(swap_hash_values, 0, sizeof(swap_hash_values));
  543. }
  544. /*****************************************************************
  545. *
  546. * MAIN THREAD
  547. *
  548. *****************************************************************/
  549. /**
  550. * Create global charts
  551. *
  552. * Call ebpf_create_chart to create the charts for the collector.
  553. *
  554. * @param update_every value to overwrite the update frequency set by the server.
  555. */
  556. static void ebpf_create_swap_charts(int update_every)
  557. {
  558. ebpf_create_chart(NETDATA_EBPF_SYSTEM_GROUP, NETDATA_MEM_SWAP_CHART,
  559. "Calls to access swap memory",
  560. EBPF_COMMON_DIMENSION_CALL, NETDATA_SYSTEM_SWAP_SUBMENU,
  561. NULL,
  562. NETDATA_EBPF_CHART_TYPE_LINE,
  563. 202,
  564. ebpf_create_global_dimension,
  565. swap_publish_aggregated, NETDATA_SWAP_END,
  566. update_every, NETDATA_EBPF_MODULE_NAME_SWAP);
  567. }
  568. /**
  569. * SWAP thread
  570. *
  571. * Thread used to make swap thread
  572. *
  573. * @param ptr a pointer to `struct ebpf_module`
  574. *
  575. * @return It always return NULL
  576. */
  577. void *ebpf_swap_thread(void *ptr)
  578. {
  579. netdata_thread_cleanup_push(ebpf_swap_cleanup, ptr);
  580. ebpf_module_t *em = (ebpf_module_t *)ptr;
  581. em->maps = swap_maps;
  582. ebpf_update_pid_table(&swap_maps[NETDATA_PID_SWAP_TABLE], em);
  583. if (!em->enabled)
  584. goto endswap;
  585. probe_links = ebpf_load_program(ebpf_plugin_dir, em, running_on_kernel, isrh, &objects);
  586. if (!probe_links) {
  587. em->enabled = CONFIG_BOOLEAN_NO;
  588. goto endswap;
  589. }
  590. ebpf_swap_allocate_global_vectors(em->apps_charts);
  591. int algorithms[NETDATA_SWAP_END] = { NETDATA_EBPF_INCREMENTAL_IDX, NETDATA_EBPF_INCREMENTAL_IDX };
  592. ebpf_global_labels(swap_aggregated_data, swap_publish_aggregated, swap_dimension_name, swap_dimension_name,
  593. algorithms, NETDATA_SWAP_END);
  594. pthread_mutex_lock(&lock);
  595. ebpf_create_swap_charts(em->update_every);
  596. ebpf_update_stats(&plugin_statistics, em);
  597. pthread_mutex_unlock(&lock);
  598. swap_collector(em);
  599. endswap:
  600. if (!em->enabled)
  601. ebpf_update_disabled_plugin_stats(em);
  602. netdata_thread_cleanup_pop(1);
  603. return NULL;
  604. }