ebpf_process.c 44 KB

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