ebpf_process.c 46 KB

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