ebpf_process.c 49 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371
  1. // SPDX-License-Identifier: GPL-3.0-or-later
  2. #include <sys/resource.h>
  3. #include "ebpf.h"
  4. #include "ebpf_process.h"
  5. /*****************************************************************
  6. *
  7. * GLOBAL VARIABLES
  8. *
  9. *****************************************************************/
  10. static char *process_dimension_names[NETDATA_KEY_PUBLISH_PROCESS_END] = { "process", "task", "process", "thread" };
  11. static char *process_id_names[NETDATA_KEY_PUBLISH_PROCESS_END] = { "do_exit", "release_task", "_do_fork", "sys_clone" };
  12. static char *status[] = { "process", "zombie" };
  13. static ebpf_local_maps_t process_maps[] = {{.name = "tbl_pid_stats", .internal_input = ND_EBPF_DEFAULT_PID_SIZE,
  14. .user_input = 0,
  15. .type = NETDATA_EBPF_MAP_RESIZABLE | NETDATA_EBPF_MAP_PID,
  16. .map_fd = ND_EBPF_MAP_FD_NOT_INITIALIZED},
  17. {.name = "tbl_total_stats", .internal_input = NETDATA_KEY_END_VECTOR,
  18. .user_input = 0, .type = NETDATA_EBPF_MAP_STATIC,
  19. .map_fd = ND_EBPF_MAP_FD_NOT_INITIALIZED},
  20. {.name = "process_ctrl", .internal_input = NETDATA_CONTROLLER_END,
  21. .user_input = 0,
  22. .type = NETDATA_EBPF_MAP_CONTROLLER,
  23. .map_fd = ND_EBPF_MAP_FD_NOT_INITIALIZED},
  24. {.name = NULL, .internal_input = 0, .user_input = 0,
  25. .type = NETDATA_EBPF_MAP_CONTROLLER,
  26. .map_fd = ND_EBPF_MAP_FD_NOT_INITIALIZED}};
  27. char *tracepoint_sched_type = { "sched" } ;
  28. char *tracepoint_sched_process_exit = { "sched_process_exit" };
  29. char *tracepoint_sched_process_exec = { "sched_process_exec" };
  30. char *tracepoint_sched_process_fork = { "sched_process_fork" };
  31. static int was_sched_process_exit_enabled = 0;
  32. static int was_sched_process_exec_enabled = 0;
  33. static int was_sched_process_fork_enabled = 0;
  34. static netdata_idx_t *process_hash_values = NULL;
  35. static netdata_syscall_stat_t process_aggregated_data[NETDATA_KEY_PUBLISH_PROCESS_END];
  36. static netdata_publish_syscall_t process_publish_aggregated[NETDATA_KEY_PUBLISH_PROCESS_END];
  37. ebpf_process_stat_t **global_process_stats = NULL;
  38. ebpf_process_publish_apps_t **current_apps_data = NULL;
  39. int process_enabled = 0;
  40. bool publish_internal_metrics = true;
  41. struct config process_config = { .first_section = NULL,
  42. .last_section = NULL,
  43. .mutex = NETDATA_MUTEX_INITIALIZER,
  44. .index = { .avl_tree = { .root = NULL, .compar = appconfig_section_compare },
  45. .rwlock = AVL_LOCK_INITIALIZER } };
  46. static struct netdata_static_thread cgroup_thread = {
  47. .name = "EBPF CGROUP",
  48. .config_section = NULL,
  49. .config_name = NULL,
  50. .env_name = NULL,
  51. .enabled = 1,
  52. .thread = NULL,
  53. .init_routine = NULL,
  54. .start_routine = NULL
  55. };
  56. static enum ebpf_threads_status ebpf_process_exited = NETDATA_THREAD_EBPF_RUNNING;
  57. static char *threads_stat[NETDATA_EBPF_THREAD_STAT_END] = {"total", "running"};
  58. static char *load_event_stat[NETDATA_EBPF_LOAD_STAT_END] = {"legacy", "co-re"};
  59. /*****************************************************************
  60. *
  61. * PROCESS DATA AND SEND TO NETDATA
  62. *
  63. *****************************************************************/
  64. /**
  65. * Update publish structure before to send data to Netdata.
  66. *
  67. * @param publish the first output structure with independent dimensions
  68. * @param pvc the second output structure with correlated dimensions
  69. * @param input the structure with the input data.
  70. */
  71. static void ebpf_update_global_publish(netdata_publish_syscall_t *publish, netdata_publish_vfs_common_t *pvc,
  72. netdata_syscall_stat_t *input)
  73. {
  74. netdata_publish_syscall_t *move = publish;
  75. int selector = NETDATA_KEY_PUBLISH_PROCESS_EXIT;
  76. while (move) {
  77. move->ncall = (input->call > move->pcall) ? input->call - move->pcall : move->pcall - input->call;
  78. move->nbyte = (input->bytes > move->pbyte) ? input->bytes - move->pbyte : move->pbyte - input->bytes;
  79. move->nerr = (input->ecall > move->nerr) ? input->ecall - move->perr : move->perr - input->ecall;
  80. move->pcall = input->call;
  81. move->pbyte = input->bytes;
  82. move->perr = input->ecall;
  83. input = input->next;
  84. move = move->next;
  85. selector++;
  86. }
  87. pvc->running = (long)publish[NETDATA_KEY_PUBLISH_PROCESS_FORK].ncall -
  88. (long)publish[NETDATA_KEY_PUBLISH_PROCESS_CLONE].ncall;
  89. publish[NETDATA_KEY_PUBLISH_PROCESS_RELEASE_TASK].ncall = -publish[NETDATA_KEY_PUBLISH_PROCESS_RELEASE_TASK].ncall;
  90. pvc->zombie = (long)publish[NETDATA_KEY_PUBLISH_PROCESS_EXIT].ncall +
  91. (long)publish[NETDATA_KEY_PUBLISH_PROCESS_RELEASE_TASK].ncall;
  92. }
  93. /**
  94. * Call the necessary functions to create a chart.
  95. *
  96. * @param family the chart family
  97. * @param move the pointer with the values that will be published
  98. */
  99. static void write_status_chart(char *family, netdata_publish_vfs_common_t *pvc)
  100. {
  101. write_begin_chart(family, NETDATA_PROCESS_STATUS_NAME);
  102. write_chart_dimension(status[0], (long long)pvc->running);
  103. write_chart_dimension(status[1], (long long)pvc->zombie);
  104. write_end_chart();
  105. }
  106. /**
  107. * Send data to Netdata calling auxiliary functions.
  108. *
  109. * @param em the structure with thread information
  110. */
  111. static void ebpf_process_send_data(ebpf_module_t *em)
  112. {
  113. netdata_publish_vfs_common_t pvc;
  114. ebpf_update_global_publish(process_publish_aggregated, &pvc, process_aggregated_data);
  115. write_count_chart(NETDATA_EXIT_SYSCALL, NETDATA_EBPF_SYSTEM_GROUP,
  116. &process_publish_aggregated[NETDATA_KEY_PUBLISH_PROCESS_EXIT], 2);
  117. write_count_chart(NETDATA_PROCESS_SYSCALL, NETDATA_EBPF_SYSTEM_GROUP,
  118. &process_publish_aggregated[NETDATA_KEY_PUBLISH_PROCESS_FORK], 2);
  119. write_status_chart(NETDATA_EBPF_SYSTEM_GROUP, &pvc);
  120. if (em->mode < MODE_ENTRY) {
  121. write_err_chart(NETDATA_PROCESS_ERROR_NAME, NETDATA_EBPF_SYSTEM_GROUP,
  122. &process_publish_aggregated[NETDATA_KEY_PUBLISH_PROCESS_FORK], 2);
  123. }
  124. }
  125. /**
  126. * Sum values for pid
  127. *
  128. * @param root the structure with all available PIDs
  129. *
  130. * @param offset the address that we are reading
  131. *
  132. * @return it returns the sum of all PIDs
  133. */
  134. long long ebpf_process_sum_values_for_pids(struct pid_on_target *root, size_t offset)
  135. {
  136. long long ret = 0;
  137. while (root) {
  138. int32_t pid = root->pid;
  139. ebpf_process_publish_apps_t *w = current_apps_data[pid];
  140. if (w) {
  141. ret += get_value_from_structure((char *)w, offset);
  142. }
  143. root = root->next;
  144. }
  145. return ret;
  146. }
  147. /**
  148. * Remove process pid
  149. *
  150. * Remove from PID task table when task_release was called.
  151. */
  152. void ebpf_process_remove_pids()
  153. {
  154. struct pid_stat *pids = root_of_pids;
  155. int pid_fd = process_maps[NETDATA_PROCESS_PID_TABLE].map_fd;
  156. while (pids) {
  157. uint32_t pid = pids->pid;
  158. ebpf_process_stat_t *w = global_process_stats[pid];
  159. if (w) {
  160. freez(w);
  161. global_process_stats[pid] = NULL;
  162. bpf_map_delete_elem(pid_fd, &pid);
  163. }
  164. pids = pids->next;
  165. }
  166. }
  167. /**
  168. * Send data to Netdata calling auxiliary functions.
  169. *
  170. * @param root the target list.
  171. */
  172. void ebpf_process_send_apps_data(struct target *root, ebpf_module_t *em)
  173. {
  174. struct target *w;
  175. collected_number value;
  176. write_begin_chart(NETDATA_APPS_FAMILY, NETDATA_SYSCALL_APPS_TASK_PROCESS);
  177. for (w = root; w; w = w->next) {
  178. if (unlikely(w->exposed && w->processes)) {
  179. value = ebpf_process_sum_values_for_pids(w->root_pid, offsetof(ebpf_process_publish_apps_t, create_process));
  180. write_chart_dimension(w->name, value);
  181. }
  182. }
  183. write_end_chart();
  184. write_begin_chart(NETDATA_APPS_FAMILY, NETDATA_SYSCALL_APPS_TASK_THREAD);
  185. for (w = root; w; w = w->next) {
  186. if (unlikely(w->exposed && w->processes)) {
  187. value = ebpf_process_sum_values_for_pids(w->root_pid, offsetof(ebpf_process_publish_apps_t, create_thread));
  188. write_chart_dimension(w->name, value);
  189. }
  190. }
  191. write_end_chart();
  192. write_begin_chart(NETDATA_APPS_FAMILY, NETDATA_SYSCALL_APPS_TASK_EXIT);
  193. for (w = root; w; w = w->next) {
  194. if (unlikely(w->exposed && w->processes)) {
  195. value = ebpf_process_sum_values_for_pids(w->root_pid, offsetof(ebpf_process_publish_apps_t,
  196. call_do_exit));
  197. write_chart_dimension(w->name, value);
  198. }
  199. }
  200. write_end_chart();
  201. write_begin_chart(NETDATA_APPS_FAMILY, NETDATA_SYSCALL_APPS_TASK_CLOSE);
  202. for (w = root; w; w = w->next) {
  203. if (unlikely(w->exposed && w->processes)) {
  204. value = ebpf_process_sum_values_for_pids(w->root_pid, offsetof(ebpf_process_publish_apps_t,
  205. call_release_task));
  206. write_chart_dimension(w->name, value);
  207. }
  208. }
  209. write_end_chart();
  210. if (em->mode < MODE_ENTRY) {
  211. write_begin_chart(NETDATA_APPS_FAMILY, NETDATA_SYSCALL_APPS_TASK_ERROR);
  212. for (w = root; w; w = w->next) {
  213. if (unlikely(w->exposed && w->processes)) {
  214. value = ebpf_process_sum_values_for_pids(w->root_pid, offsetof(ebpf_process_publish_apps_t,
  215. task_err));
  216. write_chart_dimension(w->name, value);
  217. }
  218. }
  219. write_end_chart();
  220. }
  221. ebpf_process_remove_pids();
  222. }
  223. /*****************************************************************
  224. *
  225. * READ INFORMATION FROM KERNEL RING
  226. *
  227. *****************************************************************/
  228. /**
  229. * Read the hash table and store data to allocated vectors.
  230. */
  231. static void read_hash_global_tables()
  232. {
  233. uint64_t idx;
  234. netdata_idx_t res[NETDATA_KEY_END_VECTOR];
  235. netdata_idx_t *val = process_hash_values;
  236. int fd = process_maps[NETDATA_PROCESS_GLOBAL_TABLE].map_fd;
  237. for (idx = 0; idx < NETDATA_KEY_END_VECTOR; idx++) {
  238. if (!bpf_map_lookup_elem(fd, &idx, val)) {
  239. uint64_t total = 0;
  240. int i;
  241. int end = ebpf_nprocs;
  242. for (i = 0; i < end; i++)
  243. total += val[i];
  244. res[idx] = total;
  245. } else {
  246. res[idx] = 0;
  247. }
  248. }
  249. process_aggregated_data[NETDATA_KEY_PUBLISH_PROCESS_EXIT].call = res[NETDATA_KEY_CALLS_DO_EXIT];
  250. process_aggregated_data[NETDATA_KEY_PUBLISH_PROCESS_RELEASE_TASK].call = res[NETDATA_KEY_CALLS_RELEASE_TASK];
  251. process_aggregated_data[NETDATA_KEY_PUBLISH_PROCESS_FORK].call = res[NETDATA_KEY_CALLS_DO_FORK];
  252. process_aggregated_data[NETDATA_KEY_PUBLISH_PROCESS_CLONE].call = res[NETDATA_KEY_CALLS_SYS_CLONE];
  253. process_aggregated_data[NETDATA_KEY_PUBLISH_PROCESS_FORK].ecall = res[NETDATA_KEY_ERROR_DO_FORK];
  254. process_aggregated_data[NETDATA_KEY_PUBLISH_PROCESS_CLONE].ecall = res[NETDATA_KEY_ERROR_SYS_CLONE];
  255. }
  256. /**
  257. * Read the hash table and store data to allocated vectors.
  258. */
  259. static void ebpf_process_update_apps_data()
  260. {
  261. struct pid_stat *pids = root_of_pids;
  262. while (pids) {
  263. uint32_t current_pid = pids->pid;
  264. ebpf_process_stat_t *ps = global_process_stats[current_pid];
  265. if (!ps) {
  266. pids = pids->next;
  267. continue;
  268. }
  269. ebpf_process_publish_apps_t *cad = current_apps_data[current_pid];
  270. if (!cad) {
  271. cad = callocz(1, sizeof(ebpf_process_publish_apps_t));
  272. current_apps_data[current_pid] = cad;
  273. }
  274. //Read data
  275. cad->call_do_exit = ps->exit_call;
  276. cad->call_release_task = ps->release_call;
  277. cad->create_process = ps->create_process;
  278. cad->create_thread = ps->create_thread;
  279. cad->task_err = ps->task_err;
  280. pids = pids->next;
  281. }
  282. }
  283. /**
  284. * Update cgroup
  285. *
  286. * Update cgroup data based in
  287. */
  288. static void ebpf_update_process_cgroup()
  289. {
  290. ebpf_cgroup_target_t *ect ;
  291. int pid_fd = process_maps[NETDATA_PROCESS_PID_TABLE].map_fd;
  292. pthread_mutex_lock(&mutex_cgroup_shm);
  293. for (ect = ebpf_cgroup_pids; ect; ect = ect->next) {
  294. struct pid_on_target2 *pids;
  295. for (pids = ect->pids; pids; pids = pids->next) {
  296. int pid = pids->pid;
  297. ebpf_process_stat_t *out = &pids->ps;
  298. if (global_process_stats[pid]) {
  299. ebpf_process_stat_t *in = global_process_stats[pid];
  300. memcpy(out, in, sizeof(ebpf_process_stat_t));
  301. } else {
  302. if (bpf_map_lookup_elem(pid_fd, &pid, out)) {
  303. memset(out, 0, sizeof(ebpf_process_stat_t));
  304. }
  305. }
  306. }
  307. }
  308. pthread_mutex_unlock(&mutex_cgroup_shm);
  309. }
  310. /*****************************************************************
  311. *
  312. * FUNCTIONS TO CREATE CHARTS
  313. *
  314. *****************************************************************/
  315. /**
  316. * Create process status chart
  317. *
  318. * @param family the chart family
  319. * @param name the chart name
  320. * @param axis the axis label
  321. * @param web the group name used to attach the chart on dashboard
  322. * @param order the order number of the specified chart
  323. * @param update_every value to overwrite the update frequency set by the server.
  324. */
  325. static void ebpf_process_status_chart(char *family, char *name, char *axis,
  326. char *web, char *algorithm, int order, int update_every)
  327. {
  328. printf("CHART %s.%s '' 'Process not closed' '%s' '%s' '' line %d %d '' 'ebpf.plugin' 'process'\n",
  329. family,
  330. name,
  331. axis,
  332. web,
  333. order,
  334. update_every);
  335. printf("DIMENSION %s '' %s 1 1\n", status[0], algorithm);
  336. printf("DIMENSION %s '' %s 1 1\n", status[1], algorithm);
  337. }
  338. /**
  339. * Create global charts
  340. *
  341. * Call ebpf_create_chart to create the charts for the collector.
  342. *
  343. * @param em a pointer to the structure with the default values.
  344. */
  345. static void ebpf_create_global_charts(ebpf_module_t *em)
  346. {
  347. ebpf_create_chart(NETDATA_EBPF_SYSTEM_GROUP,
  348. NETDATA_PROCESS_SYSCALL,
  349. "Start process",
  350. EBPF_COMMON_DIMENSION_CALL,
  351. NETDATA_PROCESS_GROUP,
  352. NULL,
  353. NETDATA_EBPF_CHART_TYPE_LINE,
  354. 21002,
  355. ebpf_create_global_dimension,
  356. &process_publish_aggregated[NETDATA_KEY_PUBLISH_PROCESS_FORK],
  357. 2, em->update_every, NETDATA_EBPF_MODULE_NAME_PROCESS);
  358. ebpf_create_chart(NETDATA_EBPF_SYSTEM_GROUP,
  359. NETDATA_EXIT_SYSCALL,
  360. "Exit process",
  361. EBPF_COMMON_DIMENSION_CALL,
  362. NETDATA_PROCESS_GROUP,
  363. NULL,
  364. NETDATA_EBPF_CHART_TYPE_LINE,
  365. 21003,
  366. ebpf_create_global_dimension,
  367. &process_publish_aggregated[NETDATA_KEY_PUBLISH_PROCESS_EXIT],
  368. 2, em->update_every, NETDATA_EBPF_MODULE_NAME_PROCESS);
  369. ebpf_process_status_chart(NETDATA_EBPF_SYSTEM_GROUP,
  370. NETDATA_PROCESS_STATUS_NAME,
  371. EBPF_COMMON_DIMENSION_DIFFERENCE,
  372. NETDATA_PROCESS_GROUP,
  373. ebpf_algorithms[NETDATA_EBPF_ABSOLUTE_IDX],
  374. 21004, em->update_every);
  375. if (em->mode < MODE_ENTRY) {
  376. ebpf_create_chart(NETDATA_EBPF_SYSTEM_GROUP,
  377. NETDATA_PROCESS_ERROR_NAME,
  378. "Fails to create process",
  379. EBPF_COMMON_DIMENSION_CALL,
  380. NETDATA_PROCESS_GROUP,
  381. NULL,
  382. NETDATA_EBPF_CHART_TYPE_LINE,
  383. 21005,
  384. ebpf_create_global_dimension,
  385. &process_publish_aggregated[NETDATA_KEY_PUBLISH_PROCESS_FORK],
  386. 2, em->update_every, NETDATA_EBPF_MODULE_NAME_PROCESS);
  387. }
  388. }
  389. /**
  390. * Create chart for Statistic Thread
  391. *
  392. * Write to standard output current values for threads.
  393. *
  394. * @param em a pointer to the structure with the default values.
  395. */
  396. static inline void ebpf_create_statistic_thread_chart(ebpf_module_t *em)
  397. {
  398. ebpf_write_chart_cmd(NETDATA_MONITORING_FAMILY,
  399. NETDATA_EBPF_THREADS,
  400. "Threads info.",
  401. "threads",
  402. NETDATA_EBPF_FAMILY,
  403. NETDATA_EBPF_CHART_TYPE_LINE,
  404. NULL,
  405. 140000,
  406. em->update_every,
  407. NETDATA_EBPF_MODULE_NAME_PROCESS);
  408. ebpf_write_global_dimension(threads_stat[NETDATA_EBPF_THREAD_STAT_TOTAL],
  409. threads_stat[NETDATA_EBPF_THREAD_STAT_TOTAL],
  410. ebpf_algorithms[NETDATA_EBPF_ABSOLUTE_IDX]);
  411. ebpf_write_global_dimension(threads_stat[NETDATA_EBPF_THREAD_STAT_RUNNING],
  412. threads_stat[NETDATA_EBPF_THREAD_STAT_RUNNING],
  413. ebpf_algorithms[NETDATA_EBPF_ABSOLUTE_IDX]);
  414. }
  415. /**
  416. * Create chart for Load Thread
  417. *
  418. * Write to standard output current values for load mode.
  419. *
  420. * @param em a pointer to the structure with the default values.
  421. */
  422. static inline void ebpf_create_statistic_load_chart(ebpf_module_t *em)
  423. {
  424. ebpf_write_chart_cmd(NETDATA_MONITORING_FAMILY,
  425. NETDATA_EBPF_LOAD_METHOD,
  426. "Load info.",
  427. "methods",
  428. NETDATA_EBPF_FAMILY,
  429. NETDATA_EBPF_CHART_TYPE_LINE,
  430. NULL,
  431. 140001,
  432. em->update_every,
  433. NETDATA_EBPF_MODULE_NAME_PROCESS);
  434. ebpf_write_global_dimension(load_event_stat[NETDATA_EBPF_LOAD_STAT_LEGACY],
  435. load_event_stat[NETDATA_EBPF_LOAD_STAT_LEGACY],
  436. ebpf_algorithms[NETDATA_EBPF_ABSOLUTE_IDX]);
  437. ebpf_write_global_dimension(load_event_stat[NETDATA_EBPF_LOAD_STAT_CORE],
  438. load_event_stat[NETDATA_EBPF_LOAD_STAT_CORE],
  439. ebpf_algorithms[NETDATA_EBPF_ABSOLUTE_IDX]);
  440. }
  441. /**
  442. * Update Internal Metric variable
  443. *
  444. * By default eBPF.plugin sends internal metrics for netdata, but user can
  445. * disable this.
  446. *
  447. * The function updates the variable used to send charts.
  448. */
  449. static void update_internal_metric_variable()
  450. {
  451. const char *s = getenv("NETDATA_INTERNALS_MONITORING");
  452. if (s && *s && strcmp(s, "NO") == 0)
  453. publish_internal_metrics = false;
  454. }
  455. /**
  456. * Create Statistics Charts
  457. *
  458. * Create charts that will show statistics related to eBPF plugin.
  459. *
  460. * @param em a pointer to the structure with the default values.
  461. */
  462. static void ebpf_create_statistic_charts(ebpf_module_t *em)
  463. {
  464. update_internal_metric_variable();
  465. if (!publish_internal_metrics)
  466. return;
  467. ebpf_create_statistic_thread_chart(em);
  468. ebpf_create_statistic_load_chart(em);
  469. }
  470. /**
  471. * Create process apps charts
  472. *
  473. * Call ebpf_create_chart to create the charts on apps submenu.
  474. *
  475. * @param em a pointer to the structure with the default values.
  476. * @param ptr a pointer for the targets.
  477. */
  478. void ebpf_process_create_apps_charts(struct ebpf_module *em, void *ptr)
  479. {
  480. struct target *root = ptr;
  481. ebpf_create_charts_on_apps(NETDATA_SYSCALL_APPS_TASK_PROCESS,
  482. "Process started",
  483. EBPF_COMMON_DIMENSION_CALL,
  484. NETDATA_PROCESS_GROUP,
  485. NETDATA_EBPF_CHART_TYPE_STACKED,
  486. 20065,
  487. ebpf_algorithms[NETDATA_EBPF_ABSOLUTE_IDX],
  488. root, em->update_every, NETDATA_EBPF_MODULE_NAME_PROCESS);
  489. ebpf_create_charts_on_apps(NETDATA_SYSCALL_APPS_TASK_THREAD,
  490. "Threads started",
  491. EBPF_COMMON_DIMENSION_CALL,
  492. NETDATA_PROCESS_GROUP,
  493. NETDATA_EBPF_CHART_TYPE_STACKED,
  494. 20066,
  495. ebpf_algorithms[NETDATA_EBPF_ABSOLUTE_IDX],
  496. root, em->update_every, NETDATA_EBPF_MODULE_NAME_PROCESS);
  497. ebpf_create_charts_on_apps(NETDATA_SYSCALL_APPS_TASK_EXIT,
  498. "Tasks starts exit process.",
  499. EBPF_COMMON_DIMENSION_CALL,
  500. NETDATA_PROCESS_GROUP,
  501. NETDATA_EBPF_CHART_TYPE_STACKED,
  502. 20067,
  503. ebpf_algorithms[NETDATA_EBPF_ABSOLUTE_IDX],
  504. root, em->update_every, NETDATA_EBPF_MODULE_NAME_PROCESS);
  505. ebpf_create_charts_on_apps(NETDATA_SYSCALL_APPS_TASK_CLOSE,
  506. "Tasks closed",
  507. EBPF_COMMON_DIMENSION_CALL,
  508. NETDATA_PROCESS_GROUP,
  509. NETDATA_EBPF_CHART_TYPE_STACKED,
  510. 20068,
  511. ebpf_algorithms[NETDATA_EBPF_ABSOLUTE_IDX],
  512. root, em->update_every, NETDATA_EBPF_MODULE_NAME_PROCESS);
  513. if (em->mode < MODE_ENTRY) {
  514. ebpf_create_charts_on_apps(NETDATA_SYSCALL_APPS_TASK_ERROR,
  515. "Errors to create process or threads.",
  516. EBPF_COMMON_DIMENSION_CALL,
  517. NETDATA_PROCESS_GROUP,
  518. NETDATA_EBPF_CHART_TYPE_STACKED,
  519. 20069,
  520. ebpf_algorithms[NETDATA_EBPF_ABSOLUTE_IDX],
  521. root,
  522. em->update_every, NETDATA_EBPF_MODULE_NAME_PROCESS);
  523. }
  524. em->apps_charts |= NETDATA_EBPF_APPS_FLAG_CHART_CREATED;
  525. }
  526. /**
  527. * Create apps charts
  528. *
  529. * Call ebpf_create_chart to create the charts on apps submenu.
  530. *
  531. * @param root a pointer for the targets.
  532. */
  533. static void ebpf_create_apps_charts(struct target *root)
  534. {
  535. if (unlikely(!all_pids))
  536. return;
  537. struct target *w;
  538. int newly_added = 0;
  539. for (w = root; w; w = w->next) {
  540. if (w->target)
  541. continue;
  542. if (unlikely(w->processes && (debug_enabled || w->debug_enabled))) {
  543. struct pid_on_target *pid_on_target;
  544. fprintf(
  545. stderr, "ebpf.plugin: target '%s' has aggregated %u process%s:", w->name, w->processes,
  546. (w->processes == 1) ? "" : "es");
  547. for (pid_on_target = w->root_pid; pid_on_target; pid_on_target = pid_on_target->next) {
  548. fprintf(stderr, " %d", pid_on_target->pid);
  549. }
  550. fputc('\n', stderr);
  551. }
  552. if (!w->exposed && w->processes) {
  553. newly_added++;
  554. w->exposed = 1;
  555. if (debug_enabled || w->debug_enabled)
  556. debug_log_int("%s just added - regenerating charts.", w->name);
  557. }
  558. }
  559. if (!newly_added)
  560. return;
  561. int counter;
  562. for (counter = 0; ebpf_modules[counter].thread_name; counter++) {
  563. ebpf_module_t *current = &ebpf_modules[counter];
  564. if (current->enabled && current->apps_charts && current->apps_routine)
  565. current->apps_routine(current, root);
  566. }
  567. }
  568. /*****************************************************************
  569. *
  570. * FUNCTIONS TO CLOSE THE THREAD
  571. *
  572. *****************************************************************/
  573. /**
  574. * Process disable tracepoints
  575. *
  576. * Disable tracepoints when the plugin was responsible to enable it.
  577. */
  578. static void ebpf_process_disable_tracepoints()
  579. {
  580. char *default_message = { "Cannot disable the tracepoint" };
  581. if (!was_sched_process_exit_enabled) {
  582. if (ebpf_disable_tracing_values(tracepoint_sched_type, tracepoint_sched_process_exit))
  583. error("%s %s/%s.", default_message, tracepoint_sched_type, tracepoint_sched_process_exit);
  584. }
  585. if (!was_sched_process_exec_enabled) {
  586. if (ebpf_disable_tracing_values(tracepoint_sched_type, tracepoint_sched_process_exec))
  587. error("%s %s/%s.", default_message, tracepoint_sched_type, tracepoint_sched_process_exec);
  588. }
  589. if (!was_sched_process_fork_enabled) {
  590. if (ebpf_disable_tracing_values(tracepoint_sched_type, tracepoint_sched_process_fork))
  591. error("%s %s/%s.", default_message, tracepoint_sched_type, tracepoint_sched_process_fork);
  592. }
  593. }
  594. /**
  595. * Process Exit
  596. *
  597. * Cancel child thread.
  598. *
  599. * @param ptr thread data.
  600. */
  601. static void ebpf_process_exit(void *ptr)
  602. {
  603. (void)ptr;
  604. ebpf_process_exited = NETDATA_THREAD_EBPF_STOPPING;
  605. }
  606. /**
  607. * Process cleanup
  608. *
  609. * Cleanup allocated memory.
  610. *
  611. * @param ptr thread data.
  612. */
  613. static void ebpf_process_cleanup(void *ptr)
  614. {
  615. ebpf_module_t *em = (ebpf_module_t *)ptr;
  616. if (ebpf_process_exited != NETDATA_THREAD_EBPF_STOPPED)
  617. return;
  618. ebpf_cleanup_publish_syscall(process_publish_aggregated);
  619. freez(process_hash_values);
  620. freez(cgroup_thread.thread);
  621. ebpf_process_disable_tracepoints();
  622. cgroup_thread.enabled = NETDATA_MAIN_THREAD_EXITED;
  623. em->enabled = NETDATA_MAIN_THREAD_EXITED;
  624. }
  625. /*****************************************************************
  626. *
  627. * FUNCTIONS WITH THE MAIN LOOP
  628. *
  629. *****************************************************************/
  630. /**
  631. * Cgroup update shm
  632. *
  633. * This is the thread callback.
  634. * This thread is necessary, because we cannot freeze the whole plugin to read the data from shared memory.
  635. *
  636. * @param ptr It is a NULL value for this thread.
  637. *
  638. * @return It always returns NULL.
  639. */
  640. void *ebpf_cgroup_update_shm(void *ptr)
  641. {
  642. netdata_thread_cleanup_push(ebpf_process_cleanup, ptr);
  643. heartbeat_t hb;
  644. heartbeat_init(&hb);
  645. usec_t step = 3 * USEC_PER_SEC;
  646. int counter = NETDATA_EBPF_CGROUP_UPDATE - 1;
  647. //This will be cancelled by its parent
  648. while (ebpf_process_exited == NETDATA_THREAD_EBPF_RUNNING) {
  649. usec_t dt = heartbeat_next(&hb, step);
  650. (void)dt;
  651. if (ebpf_process_exited == NETDATA_THREAD_EBPF_STOPPING)
  652. break;
  653. // We are using a small heartbeat time to wake up thread,
  654. // but we should not update so frequently the shared memory data
  655. if (++counter >= NETDATA_EBPF_CGROUP_UPDATE) {
  656. counter = 0;
  657. if (!shm_ebpf_cgroup.header)
  658. ebpf_map_cgroup_shared_memory();
  659. ebpf_parse_cgroup_shm_data();
  660. }
  661. }
  662. ebpf_process_exited = NETDATA_THREAD_EBPF_STOPPED;
  663. netdata_thread_cleanup_pop(1);
  664. return NULL;
  665. }
  666. /**
  667. * Sum PIDs
  668. *
  669. * Sum values for all targets.
  670. *
  671. * @param ps structure used to store data
  672. * @param pids input data
  673. */
  674. static void ebpf_process_sum_cgroup_pids(ebpf_process_stat_t *ps, struct pid_on_target2 *pids)
  675. {
  676. ebpf_process_stat_t accumulator;
  677. memset(&accumulator, 0, sizeof(accumulator));
  678. while (pids) {
  679. ebpf_process_stat_t *ps = &pids->ps;
  680. accumulator.exit_call += ps->exit_call;
  681. accumulator.release_call += ps->release_call;
  682. accumulator.create_process += ps->create_process;
  683. accumulator.create_thread += ps->create_thread;
  684. accumulator.task_err += ps->task_err;
  685. pids = pids->next;
  686. }
  687. ps->exit_call = (accumulator.exit_call >= ps->exit_call) ? accumulator.exit_call : ps->exit_call;
  688. ps->release_call = (accumulator.release_call >= ps->release_call) ? accumulator.release_call : ps->release_call;
  689. ps->create_process = (accumulator.create_process >= ps->create_process) ? accumulator.create_process : ps->create_process;
  690. ps->create_thread = (accumulator.create_thread >= ps->create_thread) ? accumulator.create_thread : ps->create_thread;
  691. ps->task_err = (accumulator.task_err >= ps->task_err) ? accumulator.task_err : ps->task_err;
  692. }
  693. /*
  694. * Send Specific Process data
  695. *
  696. * Send data for specific cgroup/apps.
  697. *
  698. * @param type chart type
  699. * @param values structure with values that will be sent to netdata
  700. * @param em the structure with thread information
  701. */
  702. static void ebpf_send_specific_process_data(char *type, ebpf_process_stat_t *values, ebpf_module_t *em)
  703. {
  704. write_begin_chart(type, NETDATA_SYSCALL_APPS_TASK_PROCESS);
  705. write_chart_dimension(process_publish_aggregated[NETDATA_KEY_PUBLISH_PROCESS_FORK].name,
  706. (long long) values->create_process);
  707. write_end_chart();
  708. write_begin_chart(type, NETDATA_SYSCALL_APPS_TASK_THREAD);
  709. write_chart_dimension(process_publish_aggregated[NETDATA_KEY_PUBLISH_PROCESS_CLONE].name,
  710. (long long) values->create_thread);
  711. write_end_chart();
  712. write_begin_chart(type, NETDATA_SYSCALL_APPS_TASK_EXIT);
  713. write_chart_dimension(process_publish_aggregated[NETDATA_KEY_PUBLISH_PROCESS_EXIT].name,
  714. (long long) values->release_call);
  715. write_end_chart();
  716. write_begin_chart(type, NETDATA_SYSCALL_APPS_TASK_CLOSE);
  717. write_chart_dimension(process_publish_aggregated[NETDATA_KEY_PUBLISH_PROCESS_RELEASE_TASK].name,
  718. (long long) values->release_call);
  719. write_end_chart();
  720. if (em->mode < MODE_ENTRY) {
  721. write_begin_chart(type, NETDATA_SYSCALL_APPS_TASK_ERROR);
  722. write_chart_dimension(process_publish_aggregated[NETDATA_KEY_PUBLISH_PROCESS_EXIT].name,
  723. (long long) values->task_err);
  724. write_end_chart();
  725. }
  726. }
  727. /**
  728. * Create specific process charts
  729. *
  730. * Create charts for cgroup/application
  731. *
  732. * @param type the chart type.
  733. * @param em the structure with thread information
  734. */
  735. static void ebpf_create_specific_process_charts(char *type, ebpf_module_t *em)
  736. {
  737. ebpf_create_chart(type, NETDATA_SYSCALL_APPS_TASK_PROCESS, "Process started",
  738. EBPF_COMMON_DIMENSION_CALL, NETDATA_PROCESS_CGROUP_GROUP,
  739. NETDATA_CGROUP_PROCESS_CREATE_CONTEXT, NETDATA_EBPF_CHART_TYPE_LINE,
  740. NETDATA_CHART_PRIO_CGROUPS_CONTAINERS + 5000,
  741. ebpf_create_global_dimension, &process_publish_aggregated[NETDATA_KEY_PUBLISH_PROCESS_FORK],
  742. 1, em->update_every, NETDATA_EBPF_MODULE_NAME_PROCESS);
  743. ebpf_create_chart(type, NETDATA_SYSCALL_APPS_TASK_THREAD, "Threads started",
  744. EBPF_COMMON_DIMENSION_CALL, NETDATA_PROCESS_CGROUP_GROUP,
  745. NETDATA_CGROUP_THREAD_CREATE_CONTEXT, NETDATA_EBPF_CHART_TYPE_LINE,
  746. NETDATA_CHART_PRIO_CGROUPS_CONTAINERS + 5001,
  747. ebpf_create_global_dimension,
  748. &process_publish_aggregated[NETDATA_KEY_PUBLISH_PROCESS_CLONE],
  749. 1, em->update_every, NETDATA_EBPF_MODULE_NAME_PROCESS);
  750. ebpf_create_chart(type, NETDATA_SYSCALL_APPS_TASK_EXIT, "Tasks starts exit process.",
  751. EBPF_COMMON_DIMENSION_CALL, NETDATA_PROCESS_CGROUP_GROUP,
  752. NETDATA_CGROUP_PROCESS_EXIT_CONTEXT,
  753. NETDATA_EBPF_CHART_TYPE_LINE, NETDATA_CHART_PRIO_CGROUPS_CONTAINERS + 5002,
  754. ebpf_create_global_dimension,
  755. &process_publish_aggregated[NETDATA_KEY_PUBLISH_PROCESS_EXIT],
  756. 1, em->update_every, NETDATA_EBPF_MODULE_NAME_PROCESS);
  757. ebpf_create_chart(type, NETDATA_SYSCALL_APPS_TASK_CLOSE, "Tasks closed",
  758. EBPF_COMMON_DIMENSION_CALL, NETDATA_PROCESS_CGROUP_GROUP,
  759. NETDATA_CGROUP_PROCESS_CLOSE_CONTEXT,
  760. NETDATA_EBPF_CHART_TYPE_LINE, NETDATA_CHART_PRIO_CGROUPS_CONTAINERS + 5003,
  761. ebpf_create_global_dimension,
  762. &process_publish_aggregated[NETDATA_KEY_PUBLISH_PROCESS_RELEASE_TASK],
  763. 1, em->update_every, NETDATA_EBPF_MODULE_NAME_PROCESS);
  764. if (em->mode < MODE_ENTRY) {
  765. ebpf_create_chart(type, NETDATA_SYSCALL_APPS_TASK_ERROR, "Errors to create process or threads.",
  766. EBPF_COMMON_DIMENSION_CALL, NETDATA_PROCESS_CGROUP_GROUP,
  767. NETDATA_CGROUP_PROCESS_ERROR_CONTEXT,
  768. NETDATA_EBPF_CHART_TYPE_LINE, NETDATA_CHART_PRIO_CGROUPS_CONTAINERS + 5004,
  769. ebpf_create_global_dimension,
  770. &process_publish_aggregated[NETDATA_KEY_PUBLISH_PROCESS_EXIT],
  771. 1, em->update_every, NETDATA_EBPF_MODULE_NAME_PROCESS);
  772. }
  773. }
  774. /**
  775. * Obsolete specific process charts
  776. *
  777. * Obsolete charts for cgroup/application
  778. *
  779. * @param type the chart type.
  780. * @param em the structure with thread information
  781. */
  782. static void ebpf_obsolete_specific_process_charts(char *type, ebpf_module_t *em)
  783. {
  784. ebpf_write_chart_obsolete(type, NETDATA_SYSCALL_APPS_TASK_PROCESS, "Process started",
  785. EBPF_COMMON_DIMENSION_CALL, NETDATA_PROCESS_GROUP, NETDATA_EBPF_CHART_TYPE_LINE,
  786. NETDATA_CGROUP_PROCESS_CREATE_CONTEXT, NETDATA_CHART_PRIO_CGROUPS_CONTAINERS + 5000,
  787. em->update_every);
  788. ebpf_write_chart_obsolete(type, NETDATA_SYSCALL_APPS_TASK_THREAD, "Threads started",
  789. EBPF_COMMON_DIMENSION_CALL, NETDATA_PROCESS_GROUP, NETDATA_EBPF_CHART_TYPE_LINE,
  790. NETDATA_CGROUP_THREAD_CREATE_CONTEXT, NETDATA_CHART_PRIO_CGROUPS_CONTAINERS + 5001,
  791. em->update_every);
  792. ebpf_write_chart_obsolete(type, NETDATA_SYSCALL_APPS_TASK_EXIT,"Tasks starts exit process.",
  793. EBPF_COMMON_DIMENSION_CALL, NETDATA_PROCESS_GROUP, NETDATA_EBPF_CHART_TYPE_LINE,
  794. NETDATA_CGROUP_PROCESS_EXIT_CONTEXT, NETDATA_CHART_PRIO_CGROUPS_CONTAINERS + 5002,
  795. em->update_every);
  796. ebpf_write_chart_obsolete(type, NETDATA_SYSCALL_APPS_TASK_CLOSE,"Tasks closed",
  797. EBPF_COMMON_DIMENSION_CALL, NETDATA_PROCESS_GROUP, NETDATA_EBPF_CHART_TYPE_LINE,
  798. NETDATA_CGROUP_PROCESS_CLOSE_CONTEXT, NETDATA_CHART_PRIO_CGROUPS_CONTAINERS + 5003,
  799. em->update_every);
  800. if (em->mode < MODE_ENTRY) {
  801. ebpf_write_chart_obsolete(type, NETDATA_SYSCALL_APPS_TASK_ERROR,"Errors to create process or threads.",
  802. EBPF_COMMON_DIMENSION_CALL, NETDATA_PROCESS_GROUP, NETDATA_EBPF_CHART_TYPE_LINE,
  803. NETDATA_CGROUP_PROCESS_ERROR_CONTEXT, NETDATA_CHART_PRIO_CGROUPS_CONTAINERS + 5004,
  804. em->update_every);
  805. }
  806. }
  807. /**
  808. * Create Systemd process Charts
  809. *
  810. * Create charts when systemd is enabled
  811. *
  812. * @param em the structure with thread information
  813. **/
  814. static void ebpf_create_systemd_process_charts(ebpf_module_t *em)
  815. {
  816. ebpf_create_charts_on_systemd(NETDATA_SYSCALL_APPS_TASK_PROCESS, "Process started",
  817. EBPF_COMMON_DIMENSION_CALL, NETDATA_APPS_PROCESS_GROUP,
  818. NETDATA_EBPF_CHART_TYPE_STACKED, 20065,
  819. ebpf_algorithms[NETDATA_EBPF_INCREMENTAL_IDX], NETDATA_SYSTEMD_PROCESS_CREATE_CONTEXT,
  820. NETDATA_EBPF_MODULE_NAME_PROCESS, em->update_every);
  821. ebpf_create_charts_on_systemd(NETDATA_SYSCALL_APPS_TASK_THREAD, "Threads started",
  822. EBPF_COMMON_DIMENSION_CALL, NETDATA_APPS_PROCESS_GROUP,
  823. NETDATA_EBPF_CHART_TYPE_STACKED, 20066,
  824. ebpf_algorithms[NETDATA_EBPF_INCREMENTAL_IDX], NETDATA_SYSTEMD_THREAD_CREATE_CONTEXT,
  825. NETDATA_EBPF_MODULE_NAME_PROCESS, em->update_every);
  826. ebpf_create_charts_on_systemd(NETDATA_SYSCALL_APPS_TASK_CLOSE, "Tasks starts exit process.",
  827. EBPF_COMMON_DIMENSION_CALL, NETDATA_APPS_PROCESS_GROUP,
  828. NETDATA_EBPF_CHART_TYPE_STACKED, 20067,
  829. ebpf_algorithms[NETDATA_EBPF_INCREMENTAL_IDX], NETDATA_SYSTEMD_PROCESS_EXIT_CONTEXT,
  830. NETDATA_EBPF_MODULE_NAME_PROCESS, em->update_every);
  831. ebpf_create_charts_on_systemd(NETDATA_SYSCALL_APPS_TASK_EXIT, "Tasks closed",
  832. EBPF_COMMON_DIMENSION_CALL, NETDATA_APPS_PROCESS_GROUP,
  833. NETDATA_EBPF_CHART_TYPE_STACKED, 20068,
  834. ebpf_algorithms[NETDATA_EBPF_INCREMENTAL_IDX], NETDATA_SYSTEMD_PROCESS_CLOSE_CONTEXT,
  835. NETDATA_EBPF_MODULE_NAME_PROCESS, em->update_every);
  836. if (em->mode < MODE_ENTRY) {
  837. ebpf_create_charts_on_systemd(NETDATA_SYSCALL_APPS_TASK_ERROR, "Errors to create process or threads.",
  838. EBPF_COMMON_DIMENSION_CALL, NETDATA_APPS_PROCESS_GROUP,
  839. NETDATA_EBPF_CHART_TYPE_STACKED, 20069,
  840. ebpf_algorithms[NETDATA_EBPF_INCREMENTAL_IDX], NETDATA_SYSTEMD_PROCESS_ERROR_CONTEXT,
  841. NETDATA_EBPF_MODULE_NAME_PROCESS, em->update_every);
  842. }
  843. }
  844. /**
  845. * Send Systemd charts
  846. *
  847. * Send collected data to Netdata.
  848. *
  849. * @param em the structure with thread information
  850. *
  851. * @return It returns the status for chart creation, if it is necessary to remove a specific dimension, zero is returned
  852. * otherwise function returns 1 to avoid chart recreation
  853. */
  854. static int ebpf_send_systemd_process_charts(ebpf_module_t *em)
  855. {
  856. int ret = 1;
  857. ebpf_cgroup_target_t *ect;
  858. write_begin_chart(NETDATA_SERVICE_FAMILY, NETDATA_SYSCALL_APPS_TASK_PROCESS);
  859. for (ect = ebpf_cgroup_pids; ect ; ect = ect->next) {
  860. if (unlikely(ect->systemd) && unlikely(ect->updated)) {
  861. write_chart_dimension(ect->name, ect->publish_systemd_ps.create_process);
  862. } else if (unlikely(ect->systemd))
  863. ret = 0;
  864. }
  865. write_end_chart();
  866. write_begin_chart(NETDATA_SERVICE_FAMILY, NETDATA_SYSCALL_APPS_TASK_THREAD);
  867. for (ect = ebpf_cgroup_pids; ect ; ect = ect->next) {
  868. if (unlikely(ect->systemd) && unlikely(ect->updated)) {
  869. write_chart_dimension(ect->name, ect->publish_systemd_ps.create_thread);
  870. }
  871. }
  872. write_end_chart();
  873. write_begin_chart(NETDATA_SERVICE_FAMILY, NETDATA_SYSCALL_APPS_TASK_EXIT);
  874. for (ect = ebpf_cgroup_pids; ect ; ect = ect->next) {
  875. if (unlikely(ect->systemd) && unlikely(ect->updated)) {
  876. write_chart_dimension(ect->name, ect->publish_systemd_ps.exit_call);
  877. }
  878. }
  879. write_end_chart();
  880. write_begin_chart(NETDATA_SERVICE_FAMILY, NETDATA_SYSCALL_APPS_TASK_CLOSE);
  881. for (ect = ebpf_cgroup_pids; ect ; ect = ect->next) {
  882. if (unlikely(ect->systemd) && unlikely(ect->updated)) {
  883. write_chart_dimension(ect->name, ect->publish_systemd_ps.release_call);
  884. }
  885. }
  886. write_end_chart();
  887. if (em->mode < MODE_ENTRY) {
  888. write_begin_chart(NETDATA_SERVICE_FAMILY, NETDATA_SYSCALL_APPS_TASK_ERROR);
  889. for (ect = ebpf_cgroup_pids; ect ; ect = ect->next) {
  890. if (unlikely(ect->systemd) && unlikely(ect->updated)) {
  891. write_chart_dimension(ect->name, ect->publish_systemd_ps.task_err);
  892. }
  893. }
  894. write_end_chart();
  895. }
  896. return ret;
  897. }
  898. /**
  899. * Send data to Netdata calling auxiliary functions.
  900. *
  901. * @param em the structure with thread information
  902. */
  903. static void ebpf_process_send_cgroup_data(ebpf_module_t *em)
  904. {
  905. if (!ebpf_cgroup_pids)
  906. return;
  907. pthread_mutex_lock(&mutex_cgroup_shm);
  908. ebpf_cgroup_target_t *ect;
  909. for (ect = ebpf_cgroup_pids; ect ; ect = ect->next) {
  910. ebpf_process_sum_cgroup_pids(&ect->publish_systemd_ps, ect->pids);
  911. }
  912. int has_systemd = shm_ebpf_cgroup.header->systemd_enabled;
  913. if (has_systemd) {
  914. static int systemd_chart = 0;
  915. if (!systemd_chart) {
  916. ebpf_create_systemd_process_charts(em);
  917. systemd_chart = 1;
  918. }
  919. systemd_chart = ebpf_send_systemd_process_charts(em);
  920. }
  921. for (ect = ebpf_cgroup_pids; ect ; ect = ect->next) {
  922. if (ect->systemd)
  923. continue;
  924. if (!(ect->flags & NETDATA_EBPF_CGROUP_HAS_PROCESS_CHART) && ect->updated) {
  925. ebpf_create_specific_process_charts(ect->name, em);
  926. ect->flags |= NETDATA_EBPF_CGROUP_HAS_PROCESS_CHART;
  927. }
  928. if (ect->flags & NETDATA_EBPF_CGROUP_HAS_PROCESS_CHART) {
  929. if (ect->updated) {
  930. ebpf_send_specific_process_data(ect->name, &ect->publish_systemd_ps, em);
  931. } else {
  932. ebpf_obsolete_specific_process_charts(ect->name, em);
  933. ect->flags &= ~NETDATA_EBPF_CGROUP_HAS_PROCESS_CHART;
  934. }
  935. }
  936. }
  937. pthread_mutex_unlock(&mutex_cgroup_shm);
  938. }
  939. /**
  940. * Update Cgroup algorithm
  941. *
  942. * Change algorithm from absolute to incremental
  943. */
  944. void ebpf_process_update_cgroup_algorithm()
  945. {
  946. int i;
  947. for (i = 0; i < NETDATA_KEY_PUBLISH_PROCESS_END; i++) {
  948. netdata_publish_syscall_t *ptr = &process_publish_aggregated[i];
  949. freez(ptr->algorithm);
  950. ptr->algorithm = strdupz(ebpf_algorithms[NETDATA_EBPF_INCREMENTAL_IDX]);
  951. }
  952. }
  953. /**
  954. * Send Statistic Data
  955. *
  956. * Send statistic information to netdata.
  957. */
  958. void ebpf_send_statistic_data()
  959. {
  960. if (!publish_internal_metrics)
  961. return;
  962. write_begin_chart(NETDATA_MONITORING_FAMILY, NETDATA_EBPF_THREADS);
  963. write_chart_dimension(threads_stat[NETDATA_EBPF_THREAD_STAT_TOTAL], (long long)plugin_statistics.threads);
  964. write_chart_dimension(threads_stat[NETDATA_EBPF_THREAD_STAT_RUNNING], (long long)plugin_statistics.running);
  965. write_end_chart();
  966. write_begin_chart(NETDATA_MONITORING_FAMILY, NETDATA_EBPF_LOAD_METHOD);
  967. write_chart_dimension(load_event_stat[NETDATA_EBPF_LOAD_STAT_LEGACY], (long long)plugin_statistics.legacy);
  968. write_chart_dimension(load_event_stat[NETDATA_EBPF_LOAD_STAT_CORE], (long long)plugin_statistics.core);
  969. write_end_chart();
  970. }
  971. /**
  972. * Main loop for this collector.
  973. *
  974. * @param em the structure with thread information
  975. */
  976. static void process_collector(ebpf_module_t *em)
  977. {
  978. cgroup_thread.thread = mallocz(sizeof(netdata_thread_t));
  979. cgroup_thread.start_routine = ebpf_cgroup_update_shm;
  980. netdata_thread_create(cgroup_thread.thread, cgroup_thread.name, NETDATA_THREAD_OPTION_DEFAULT,
  981. ebpf_cgroup_update_shm, em);
  982. heartbeat_t hb;
  983. heartbeat_init(&hb);
  984. int publish_global = em->global_charts;
  985. int cgroups = em->cgroup_charts;
  986. int thread_enabled = em->enabled;
  987. if (cgroups)
  988. ebpf_process_update_cgroup_algorithm();
  989. int update_apps_every = (int) EBPF_CFG_UPDATE_APPS_EVERY_DEFAULT;
  990. int pid_fd = process_maps[NETDATA_PROCESS_PID_TABLE].map_fd;
  991. int update_every = em->update_every;
  992. int counter = update_every - 1;
  993. int update_apps_list = update_apps_every - 1;
  994. while (!ebpf_exit_plugin) {
  995. usec_t dt = heartbeat_next(&hb, USEC_PER_SEC);
  996. (void)dt;
  997. if (ebpf_exit_plugin)
  998. break;
  999. pthread_mutex_lock(&collect_data_mutex);
  1000. if (++update_apps_list == update_apps_every) {
  1001. update_apps_list = 0;
  1002. cleanup_exited_pids();
  1003. collect_data_for_all_processes(pid_fd);
  1004. ebpf_create_apps_charts(apps_groups_root_target);
  1005. }
  1006. pthread_mutex_unlock(&collect_data_mutex);
  1007. if (++counter == update_every) {
  1008. counter = 0;
  1009. read_hash_global_tables();
  1010. netdata_apps_integration_flags_t apps_enabled = em->apps_charts;
  1011. pthread_mutex_lock(&collect_data_mutex);
  1012. if (all_pids_count > 0) {
  1013. if (apps_enabled) {
  1014. ebpf_process_update_apps_data();
  1015. }
  1016. if (cgroups) {
  1017. ebpf_update_process_cgroup();
  1018. }
  1019. }
  1020. pthread_mutex_lock(&lock);
  1021. ebpf_send_statistic_data();
  1022. if (thread_enabled) {
  1023. if (publish_global) {
  1024. ebpf_process_send_data(em);
  1025. }
  1026. if (apps_enabled & NETDATA_EBPF_APPS_FLAG_CHART_CREATED) {
  1027. ebpf_process_send_apps_data(apps_groups_root_target, em);
  1028. }
  1029. if (cgroups) {
  1030. ebpf_process_send_cgroup_data(em);
  1031. }
  1032. }
  1033. pthread_mutex_unlock(&lock);
  1034. pthread_mutex_unlock(&collect_data_mutex);
  1035. }
  1036. fflush(stdout);
  1037. }
  1038. }
  1039. /*****************************************************************
  1040. *
  1041. * FUNCTIONS TO START THREAD
  1042. *
  1043. *****************************************************************/
  1044. /**
  1045. * Allocate vectors used with this thread.
  1046. * We are not testing the return, because callocz does this and shutdown the software
  1047. * case it was not possible to allocate.
  1048. *
  1049. * @param length is the length for the vectors used inside the collector.
  1050. */
  1051. static void ebpf_process_allocate_global_vectors(size_t length)
  1052. {
  1053. memset(process_aggregated_data, 0, length * sizeof(netdata_syscall_stat_t));
  1054. memset(process_publish_aggregated, 0, length * sizeof(netdata_publish_syscall_t));
  1055. process_hash_values = callocz(ebpf_nprocs, sizeof(netdata_idx_t));
  1056. global_process_stats = callocz((size_t)pid_max, sizeof(ebpf_process_stat_t *));
  1057. current_apps_data = callocz((size_t)pid_max, sizeof(ebpf_process_publish_apps_t *));
  1058. }
  1059. static void change_syscalls()
  1060. {
  1061. static char *lfork = { "do_fork" };
  1062. process_id_names[NETDATA_KEY_PUBLISH_PROCESS_FORK] = lfork;
  1063. }
  1064. /**
  1065. * Set local variables
  1066. *
  1067. */
  1068. static void set_local_pointers()
  1069. {
  1070. if (isrh >= NETDATA_MINIMUM_RH_VERSION && isrh < NETDATA_RH_8)
  1071. change_syscalls();
  1072. }
  1073. /*****************************************************************
  1074. *
  1075. * EBPF PROCESS THREAD
  1076. *
  1077. *****************************************************************/
  1078. /**
  1079. *
  1080. */
  1081. static void wait_for_all_threads_die()
  1082. {
  1083. ebpf_modules[EBPF_MODULE_PROCESS_IDX].enabled = 0;
  1084. heartbeat_t hb;
  1085. heartbeat_init(&hb);
  1086. int max = 10;
  1087. int i;
  1088. for (i = 0; i < max; i++) {
  1089. heartbeat_next(&hb, 200000);
  1090. size_t j, counter = 0, compare = 0;
  1091. for (j = 0; ebpf_modules[j].thread_name; j++) {
  1092. if (!ebpf_modules[j].enabled)
  1093. counter++;
  1094. compare++;
  1095. }
  1096. if (counter == compare)
  1097. break;
  1098. }
  1099. }
  1100. /**
  1101. * Enable tracepoints
  1102. *
  1103. * Enable necessary tracepoints for thread.
  1104. *
  1105. * @return It returns 0 on success and -1 otherwise
  1106. */
  1107. static int ebpf_process_enable_tracepoints()
  1108. {
  1109. int test = ebpf_is_tracepoint_enabled(tracepoint_sched_type, tracepoint_sched_process_exit);
  1110. if (test == -1)
  1111. return -1;
  1112. else if (!test) {
  1113. if (ebpf_enable_tracing_values(tracepoint_sched_type, tracepoint_sched_process_exit))
  1114. return -1;
  1115. }
  1116. was_sched_process_exit_enabled = test;
  1117. test = ebpf_is_tracepoint_enabled(tracepoint_sched_type, tracepoint_sched_process_exec);
  1118. if (test == -1)
  1119. return -1;
  1120. else if (!test) {
  1121. if (ebpf_enable_tracing_values(tracepoint_sched_type, tracepoint_sched_process_exec))
  1122. return -1;
  1123. }
  1124. was_sched_process_exec_enabled = test;
  1125. test = ebpf_is_tracepoint_enabled(tracepoint_sched_type, tracepoint_sched_process_fork);
  1126. if (test == -1)
  1127. return -1;
  1128. else if (!test) {
  1129. if (ebpf_enable_tracing_values(tracepoint_sched_type, tracepoint_sched_process_fork))
  1130. return -1;
  1131. }
  1132. was_sched_process_fork_enabled = test;
  1133. return 0;
  1134. }
  1135. /**
  1136. * Process thread
  1137. *
  1138. * Thread used to generate process charts.
  1139. *
  1140. * @param ptr a pointer to `struct ebpf_module`
  1141. *
  1142. * @return It always return NULL
  1143. */
  1144. void *ebpf_process_thread(void *ptr)
  1145. {
  1146. netdata_thread_cleanup_push(ebpf_process_exit, ptr);
  1147. ebpf_module_t *em = (ebpf_module_t *)ptr;
  1148. em->maps = process_maps;
  1149. if (ebpf_process_enable_tracepoints()) {
  1150. em->enabled = em->global_charts = em->apps_charts = em->cgroup_charts = CONFIG_BOOLEAN_NO;
  1151. }
  1152. process_enabled = em->enabled;
  1153. pthread_mutex_lock(&lock);
  1154. ebpf_process_allocate_global_vectors(NETDATA_KEY_PUBLISH_PROCESS_END);
  1155. ebpf_update_pid_table(&process_maps[0], em);
  1156. set_local_pointers();
  1157. em->probe_links = ebpf_load_program(ebpf_plugin_dir, em, running_on_kernel, isrh, &em->objects);
  1158. if (!em->probe_links) {
  1159. em->enabled = CONFIG_BOOLEAN_NO;
  1160. pthread_mutex_unlock(&lock);
  1161. goto endprocess;
  1162. }
  1163. int algorithms[NETDATA_KEY_PUBLISH_PROCESS_END] = {
  1164. NETDATA_EBPF_ABSOLUTE_IDX, NETDATA_EBPF_ABSOLUTE_IDX, NETDATA_EBPF_ABSOLUTE_IDX, NETDATA_EBPF_ABSOLUTE_IDX
  1165. };
  1166. ebpf_global_labels(
  1167. process_aggregated_data, process_publish_aggregated, process_dimension_names, process_id_names,
  1168. algorithms, NETDATA_KEY_PUBLISH_PROCESS_END);
  1169. if (process_enabled) {
  1170. ebpf_create_global_charts(em);
  1171. }
  1172. ebpf_update_stats(&plugin_statistics, em);
  1173. ebpf_create_statistic_charts(em);
  1174. pthread_mutex_unlock(&lock);
  1175. process_collector(em);
  1176. endprocess:
  1177. if (!em->enabled)
  1178. ebpf_update_disabled_plugin_stats(em);
  1179. wait_for_all_threads_die();
  1180. netdata_thread_cleanup_pop(1);
  1181. return NULL;
  1182. }