ebpf_process.c 48 KB

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