From 52b10383fe6a3b78364f1f2f363f6fccf7531d39 Mon Sep 17 00:00:00 2001 From: xietangxin Date: Fri, 7 Apr 2023 17:52:28 +0800 Subject: [PATCH] sync bugfix patch from openeuler/gala-gopher (cherry picked from commit 4ea8a981b29acd853dd2d279d658055e0e6e79a1) --- Fix-for-popen-cannot-get-stderr.patch | 33 + ...-check-whether-cadvisor-is-installed.patch | 84 ++ bugfix-fix-system_proc-collect-data-err.patch | 163 +++ ...turn-type-of-uprobe-from-void-to-int.patch | 629 +++++++++ ...odify-unit-of-some-metrics-to-second.patch | 102 ++ gala-gopher.spec | 26 +- refactor-modify-jvmprobe-to-support-pod.patch | 1191 +++++++++++++++++ ...naccurate-call-stack-count.-add-samp.patch | 668 +++++++++ 8 files changed, 2892 insertions(+), 4 deletions(-) create mode 100644 Fix-for-popen-cannot-get-stderr.patch create mode 100644 bugfix-add-check-whether-cadvisor-is-installed.patch create mode 100644 bugfix-fix-system_proc-collect-data-err.patch create mode 100644 change-return-type-of-uprobe-from-void-to-int.patch create mode 100644 fix-modify-unit-of-some-metrics-to-second.patch create mode 100644 refactor-modify-jvmprobe-to-support-pod.patch create mode 100644 stackprobe-fix-inaccurate-call-stack-count.-add-samp.patch diff --git a/Fix-for-popen-cannot-get-stderr.patch b/Fix-for-popen-cannot-get-stderr.patch new file mode 100644 index 0000000..8ea6875 --- /dev/null +++ b/Fix-for-popen-cannot-get-stderr.patch @@ -0,0 +1,33 @@ +From 0f5572c6ee1847ac6b8d5fa892c83797ac4cbc6f Mon Sep 17 00:00:00 2001 +From: htpeng +Date: Wed, 29 Mar 2023 08:37:46 +0800 +Subject: [PATCH 27/30] Fix for popen() cannot get stderr + +Signed-off-by: htpeng +--- + src/probes/virtualized_infos.probe/virt_proc.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/src/probes/virtualized_infos.probe/virt_proc.c b/src/probes/virtualized_infos.probe/virt_proc.c +index d5972a5..b52c63e 100644 +--- a/src/probes/virtualized_infos.probe/virt_proc.c ++++ b/src/probes/virtualized_infos.probe/virt_proc.c +@@ -72,7 +72,7 @@ static int is_virsh_installed(void) + char line[LINE_BUF_LEN]; + int is_installed = 0; + +- if (do_read_line("which virsh", line) < 0) { ++ if (do_read_line("which virsh 2>&1", line) < 0) { + ERROR("[VIRT_PROC] find virsh failed.\n"); + return -1; + } +@@ -199,4 +199,4 @@ int virt_proc_init(void) + { + g_host_type_is_pm = 0; + is_host_type_pm(&g_host_type_is_pm); +-} +\ No newline at end of file ++} +-- +2.33.0 + diff --git a/bugfix-add-check-whether-cadvisor-is-installed.patch b/bugfix-add-check-whether-cadvisor-is-installed.patch new file mode 100644 index 0000000..b9671d6 --- /dev/null +++ b/bugfix-add-check-whether-cadvisor-is-installed.patch @@ -0,0 +1,84 @@ +From b5fae1956af6c3c7f151bbf8919eb1c1a69a28ba Mon Sep 17 00:00:00 2001 +From: xietangxin +Date: Wed, 29 Mar 2023 09:26:34 +0800 +Subject: [PATCH 28/30] bugfix:add check whether cadvisor is installed + +--- + src/common/container.c | 2 +- + .../cadvisor.probe/cadvisor_probe.py | 19 +++++++++++++++---- + 2 files changed, 16 insertions(+), 5 deletions(-) + +diff --git a/src/common/container.c b/src/common/container.c +index c5b64a4..7d6ab27 100644 +--- a/src/common/container.c ++++ b/src/common/container.c +@@ -117,7 +117,7 @@ static bool __is_dockerd() + static bool __is_isulad() + { + if (__is_install_rpm("/bin/rpm -ql iSulad")) { +- return __is_service_running("/usr/bin/systemctl service iSulad"); { ++ return __is_service_running("/usr/bin/systemctl status isulad"); { + current_docker_command = ISULAD; + return true; + } +diff --git a/src/probes/extends/python.probe/cadvisor.probe/cadvisor_probe.py b/src/probes/extends/python.probe/cadvisor.probe/cadvisor_probe.py +index 8b65117..81226d0 100644 +--- a/src/probes/extends/python.probe/cadvisor.probe/cadvisor_probe.py ++++ b/src/probes/extends/python.probe/cadvisor.probe/cadvisor_probe.py +@@ -16,7 +16,7 @@ CONTAINER_NAME_LEN = 64 + CONTAINER_STATUS_RUNNING = 0 + FILTER_BY_TASKPROBE = "task" + PROJECT_PATH = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) # /opt/gala-gopher/ +-PATTERN = re.compile(r'/[a-z0-9]+') ++PATTERN = re.compile(r'[/-][a-z0-9]+') + COUNTER = "counter" + LABEL = "label" + g_meta = None +@@ -248,6 +248,10 @@ class CadvisorProbe(Probe): + return False + + def start_cadvisor(self): ++ p = subprocess.Popen("which cadvisor", stdout=subprocess.PIPE, shell=True) ++ p.communicate(timeout=5) ++ if p.returncode != 0: ++ raise Exception('[cadvisor_probe] cAdvisor not installed') + p = subprocess.Popen("/usr/bin/ps -ef | /usr/bin/grep /usr/bin/cadvisor | /usr/bin/grep -v grep | \ + /usr/bin/awk '{print $2}'", stdout=subprocess.PIPE, shell=True) + (rawout, serr) = p.communicate(timeout=5) +@@ -310,7 +314,13 @@ class CadvisorProbe(Probe): + g_metric[table_name] = dict() + + metric_str = libconf.loads(line[(line.index("{") + 1):line.index("} ")]) +- if metric_str.id.startswith("/system.slice"): ++ ''' ++ docker use systemd as cgroupfs in k8s, cadvisor metric id like: ++ {id="/system.slice/docker-1044qbdeeedqdff...scope"} ++ normal metric_id like: ++ {id="/docker/1044qbdeeedqdff..."} ++ ''' ++ if metric_str.id.startswith("/system.slice") and 'docker-' not in metric_str.id: + continue + if metric_str.id.startswith("/user.slice"): + continue +@@ -388,7 +398,8 @@ if __name__ == "__main__": + cadvisor_probe = CadvisorProbe(object_lib, container_lib, params.port) + try: + cadvisor_probe.start_cadvisor() +- except ParamException as e: ++ except Exception as e: ++ print(e) + cadvisor_running_flag = False + basic_probe = BasicLabelProbe(object_lib, container_lib) + +@@ -401,7 +412,7 @@ if __name__ == "__main__": + basic_probe.get_basic_infos() + if cadvisor_running_flag: + try: +- cadvisor_probe.get_metrics(s, params.port) ++ cadvisor_probe.get_metrics(s, cadvisor_probe.port) + except Exception as e: + print("[cadvisor_probe]get metrics failed. Err: %s" % repr(e)) + s = requests.Session() +-- +2.33.0 + diff --git a/bugfix-fix-system_proc-collect-data-err.patch b/bugfix-fix-system_proc-collect-data-err.patch new file mode 100644 index 0000000..f6b53c9 --- /dev/null +++ b/bugfix-fix-system_proc-collect-data-err.patch @@ -0,0 +1,163 @@ +From 3bc3d1d20a220ab3a0a9093059289cc841bd45e2 Mon Sep 17 00:00:00 2001 +From: xietangxin +Date: Mon, 27 Mar 2023 11:38:26 +0800 +Subject: [PATCH 26/30] bugfix: fix system_proc collect data err + +--- + src/daemon/daemon.c | 2 +- + .../ebpf.probe/src/lvsprobe/trace_lvs.bpf.c | 2 +- + .../cadvisor.probe/cadvisor_probe.py | 4 ++++ + src/probes/system_infos.probe/system_net.c | 4 ++-- + src/probes/system_infos.probe/system_procs.c | 18 +++++++++++++----- + src/probes/system_infos.probe/system_procs.h | 11 +---------- + 6 files changed, 22 insertions(+), 19 deletions(-) + +diff --git a/src/daemon/daemon.c b/src/daemon/daemon.c +index f3ab821..b10ca60 100644 +--- a/src/daemon/daemon.c ++++ b/src/daemon/daemon.c +@@ -26,7 +26,7 @@ + #include "daemon.h" + #include "object.h" + +-#define RM_MAP_CMD "/usr/bin/find %s/* | /usr/bin/grep -v '%s\\|%s\\|%s' | /usr/bin/xargs rm -f" ++#define RM_MAP_CMD "/usr/bin/find %s/* 2> /dev/null | /usr/bin/grep -v '%s\\|%s\\|%s' | /usr/bin/xargs rm -f" + static const ResourceMgr *resouce_msg; + + #if GALA_GOPHER_INFO("inner func declaration") +diff --git a/src/probes/extends/ebpf.probe/src/lvsprobe/trace_lvs.bpf.c b/src/probes/extends/ebpf.probe/src/lvsprobe/trace_lvs.bpf.c +index cc2747c..ceb6548 100644 +--- a/src/probes/extends/ebpf.probe/src/lvsprobe/trace_lvs.bpf.c ++++ b/src/probes/extends/ebpf.probe/src/lvsprobe/trace_lvs.bpf.c +@@ -187,7 +187,7 @@ KPROBE(ip_vs_conn_expire, pt_regs) + value_p = bpf_map_lookup_elem(&lvs_link_map, &key); + if (value_p == (void *)0) { + bpf_printk("===LVS ubind dest not in hash map.\n"); +- return; ++ return 0; + } + value_p->state = IP_VS_TCP_S_CLOSE; + value_p->close_ts = bpf_ktime_get_ns(); +diff --git a/src/probes/extends/python.probe/cadvisor.probe/cadvisor_probe.py b/src/probes/extends/python.probe/cadvisor.probe/cadvisor_probe.py +index 65db0f5..8b65117 100644 +--- a/src/probes/extends/python.probe/cadvisor.probe/cadvisor_probe.py ++++ b/src/probes/extends/python.probe/cadvisor.probe/cadvisor_probe.py +@@ -200,6 +200,10 @@ class BasicLabelProbe(Probe): + self.container_lib.get_all_container.restype = POINTER(ContainerTbl) + tbl_p = self.container_lib.get_all_container() + ++ if not tbl_p: ++ print("[cadvisor_probe] no active containers in system") ++ return 0 ++ + for i in range(tbl_p.contents.num): + if tbl_p.contents.cs[i].status != CONTAINER_STATUS_RUNNING: + continue +diff --git a/src/probes/system_infos.probe/system_net.c b/src/probes/system_infos.probe/system_net.c +index 0962a9b..ce5cc04 100644 +--- a/src/probes/system_infos.probe/system_net.c ++++ b/src/probes/system_infos.probe/system_net.c +@@ -99,7 +99,7 @@ int system_tcp_probe(void) + /* output */ + (void)nprobe_fprintf(stdout, "|%s|%s|%llu|%llu|%llu|%llu|%llu|\n", + METRICS_TCP_NAME, +- "/proc/dev/snmp", ++ "/proc/net/snmp", + g_snmp_stats.tcp_curr_estab, + (g_snmp_stats.tcp_in_segs > temp.tcp_in_segs) ? (g_snmp_stats.tcp_in_segs - temp.tcp_in_segs) : 0, + (g_snmp_stats.tcp_out_segs > temp.tcp_out_segs) ? (g_snmp_stats.tcp_out_segs - temp.tcp_out_segs) : 0, +@@ -109,7 +109,7 @@ int system_tcp_probe(void) + + (void)nprobe_fprintf(stdout, "|%s|%s|%llu|%llu|\n", + METRICS_UDP_NAME, +- "/proc/dev/snmp", ++ "/proc/net/snmp", + (g_snmp_stats.udp_in_datagrams > temp.udp_in_datagrams) ? + (g_snmp_stats.udp_in_datagrams - temp.udp_in_datagrams) : 0, + (g_snmp_stats.udp_out_datagrams > temp.udp_out_datagrams) ? +diff --git a/src/probes/system_infos.probe/system_procs.c b/src/probes/system_infos.probe/system_procs.c +index d2d3c9a..1c32f53 100644 +--- a/src/probes/system_infos.probe/system_procs.c ++++ b/src/probes/system_infos.probe/system_procs.c +@@ -27,7 +27,7 @@ + #define PROC_STAT "/proc/%s/stat" + #define PROC_START_TIME_CMD "/usr/bin/cat /proc/%s/stat | awk '{print $22}'" + #define PROC_FD "/proc/%s/fd" +-#define PROC_FD_CNT_CMD "/usr/bin/ls -l /proc/%s/fd 2>/dev/null | wc -l 2>/dev/null" ++#define PROC_FD_CNT_CMD "/usr/bin/ls /proc/%s/fd 2>/dev/null | wc -l 2>/dev/null" + #define PROC_IO "/proc/%s/io" + #define PROC_IO_CMD "/usr/bin/cat /proc/%s/io" + #define PROC_SMAPS "/proc/%s/smaps_rollup" +@@ -459,6 +459,10 @@ static int get_proc_mss(const char *pid, proc_info_t *proc_info) + u32 value = 0; + char fname_or_cmd[LINE_BUF_LEN]; + char line[LINE_BUF_LEN]; ++ char key[LINE_BUF_LEN]; ++ char smap_key_list[PROC_MSS_MAX][LINE_BUF_LEN] = {"Shared_Clean:", "Shared_Dirty:", "Private_Clean:", ++ "Private_Dirty:", "Referenced:", "LazyFree:", "Swap:", "SwapPss:"}; ++ int smap_index = 0; + + fname_or_cmd[0] = 0; + (void)snprintf(fname_or_cmd, LINE_BUF_LEN, PROC_SMAPS, pid); +@@ -471,8 +475,9 @@ static int get_proc_mss(const char *pid, proc_info_t *proc_info) + if (f == NULL) { + goto out; + } +- while (!feof(f) && (index < PROC_MSS_MAX)) { ++ while (!feof(f)) { + line[0] = 0; ++ key[0] = 0; + if (fgets(line, LINE_BUF_LEN, f) == NULL) { + goto out; + } +@@ -481,12 +486,15 @@ static int get_proc_mss(const char *pid, proc_info_t *proc_info) + continue; + } + value = 0; +- int ret = sscanf(line, "%*s %lu %*s", &value); ++ int ret = sscanf(line, "%s %lu %*s", key, &value); + if (ret < 1) { + goto out; + } +- do_set_proc_mss(proc_info, value, index); +- index++; ++ if (strcmp(smap_key_list[smap_index], key) != 0) { ++ continue; ++ } ++ do_set_proc_mss(proc_info, value, smap_index); ++ smap_index++; + } + out: + if (f != NULL) { +diff --git a/src/probes/system_infos.probe/system_procs.h b/src/probes/system_infos.probe/system_procs.h +index 9c9a77d..58cf4f8 100644 +--- a/src/probes/system_infos.probe/system_procs.h ++++ b/src/probes/system_infos.probe/system_procs.h +@@ -50,23 +50,14 @@ enum proc_stat_e { + }; + + enum proc_mss_e { +- PROC_MSS_RESIDENT = 0, +- PROC_MSS_SHARED_CLEAN, ++ PROC_MSS_SHARED_CLEAN = 0, + PROC_MSS_SHARED_DIRTY, + PROC_MSS_PRIVATE_CLEAN, + PROC_MSS_PROVATE_DIRTY, + PROC_MSS_REFERENCED, +- PROC_MSS_ANONYMOUS, + PROC_MSS_LAZYFREE, +- PROC_MSS_ANONYMOUS_THP, + PROC_MSS_SWAP, +- PROC_MSS_SHARED_HUGETLB, +- PROC_MSS_PRIVATE_HUGETLB, +- PROC_MSS_PSS, +- PROC_MSS_PSS_LOCKED, + PROC_MSS_SWAP_PSS, +- PROC_MSS_CHECK_SHNEM_SWAP, +- + PROC_MSS_MAX + }; + +-- +2.33.0 + diff --git a/change-return-type-of-uprobe-from-void-to-int.patch b/change-return-type-of-uprobe-from-void-to-int.patch new file mode 100644 index 0000000..bd277a5 --- /dev/null +++ b/change-return-type-of-uprobe-from-void-to-int.patch @@ -0,0 +1,629 @@ +From 7e2c2a1364b0e26098927ad5e976b6f9cddb5744 Mon Sep 17 00:00:00 2001 +From: wo_cow +Date: Mon, 20 Mar 2023 14:51:22 +0800 +Subject: [PATCH 19/30] change return type of uprobe from void to int + +--- + .../src/dnsmasqprobe/trace_dnsmasq.bpf.c | 2 +- + .../src/haproxyprobe/trace_haproxy.bpf.c | 6 ++-- + .../ebpf.probe/src/httpprobe/sslprobe.bpf.c | 17 ++++++----- + .../ebpf.probe/src/include/__bpf_usr.h | 17 ++++++----- + .../src/nginxprobe/nginx_probe.bpf.c | 29 ++++++++++--------- + .../src/pgsliprobe/pgsli_uprobe.bpf.c | 10 +++---- + .../ebpf.probe/src/sliprobe/redissli.bpf.c | 26 ++++++++++------- + .../src/stackprobe/stack_bpf/memleak.bpf.c | 24 +++++++++++++-- + .../ebpf.probe/src/taskprobe/glibc.bpf.c | 2 ++ + 9 files changed, 81 insertions(+), 52 deletions(-) + +diff --git a/src/probes/extends/ebpf.probe/src/dnsmasqprobe/trace_dnsmasq.bpf.c b/src/probes/extends/ebpf.probe/src/dnsmasqprobe/trace_dnsmasq.bpf.c +index 7338fce..cc49723 100644 +--- a/src/probes/extends/ebpf.probe/src/dnsmasqprobe/trace_dnsmasq.bpf.c ++++ b/src/probes/extends/ebpf.probe/src/dnsmasqprobe/trace_dnsmasq.bpf.c +@@ -63,5 +63,5 @@ UPROBE(send_from, pt_regs) + /* update hash map */ + bpf_map_update_elem(&dns_query_link_map, &key, &value, BPF_ANY); + +- return; ++ return 0; + } +\ No newline at end of file +diff --git a/src/probes/extends/ebpf.probe/src/haproxyprobe/trace_haproxy.bpf.c b/src/probes/extends/ebpf.probe/src/haproxyprobe/trace_haproxy.bpf.c +index 6280ce8..ff0c9e1 100644 +--- a/src/probes/extends/ebpf.probe/src/haproxyprobe/trace_haproxy.bpf.c ++++ b/src/probes/extends/ebpf.probe/src/haproxyprobe/trace_haproxy.bpf.c +@@ -127,7 +127,7 @@ UPROBE(back_establish, pt_regs) + /* update hash map */ + bpf_map_update_elem(&haproxy_link_map, &key, &value, BPF_ANY); + +- return; ++ return 0; + } + + UPROBE(stream_free, pt_regs) +@@ -142,7 +142,7 @@ UPROBE(stream_free, pt_regs) + value_p = bpf_map_lookup_elem(&haproxy_link_map, &key); + if (value_p == (void *)0) { + bpf_printk("===haproxy free stream not in hash map.\n"); +- return; ++ return 0; + } + /* update link state */ + value_p->state = SI_ST_CLO; +@@ -150,5 +150,5 @@ UPROBE(stream_free, pt_regs) + /* update hash map */ + bpf_map_update_elem(&haproxy_link_map, &key, value_p, BPF_ANY); + +- return; ++ return 0; + } +\ No newline at end of file +diff --git a/src/probes/extends/ebpf.probe/src/httpprobe/sslprobe.bpf.c b/src/probes/extends/ebpf.probe/src/httpprobe/sslprobe.bpf.c +index 00e41e8..478baae 100644 +--- a/src/probes/extends/ebpf.probe/src/httpprobe/sslprobe.bpf.c ++++ b/src/probes/extends/ebpf.probe/src/httpprobe/sslprobe.bpf.c +@@ -72,23 +72,24 @@ UPROBE_RET(SSL_read, pt_regs, CTX_USER) + + if (PROBE_GET_PARMS(SSL_read, ctx, val, CTX_USER) < 0 || (int)PT_REGS_RC(ctx) < REQ_BUF_SIZE) { + bpf_printk("SSL_read fail..."); +- return; ++ return 0; + } + key.tgid = bpf_get_current_pid_tgid() >> TGID_LSHIFT_LEN; + ssl_st_p = (struct ssl_st*)PROBE_PARM1(val); + key.skfd = get_fd_from_ssl(ssl_st_p, MSG_READ); + data = bpf_map_lookup_elem(&conn_map, &key); + if (data == NULL || data->status == READY_FOR_SEND) { +- return; ++ return 0; + } + bpf_probe_read(buf, REQ_BUF_SIZE, (const char *)PROBE_PARM2(val)); + data->method = parse_req_method(buf); + if (data->method == HTTP_UNKNOWN) { + data->status = READY_FOR_RECVIVE; +- return; ++ return 0; + } + data->status = READY_FOR_SEND; + data->recvtime = bpf_ktime_get_ns(); ++ return 0; + } + + UPROBE_RET(SSL_write, pt_regs, CTX_USER) +@@ -102,23 +103,23 @@ UPROBE_RET(SSL_write, pt_regs, CTX_USER) + + if (PROBE_GET_PARMS(SSL_write, ctx, val, CTX_USER) < 0 || (int)PT_REGS_RC(ctx) <= REQ_BUF_SIZE - 1) { + bpf_printk("SSL_write fail..."); +- return; ++ return 0; + } + ckey.tgid = bpf_get_current_pid_tgid() >> TGID_LSHIFT_LEN ; + ssl_st_p = (struct ssl_st*)PROBE_PARM1(val); + ckey.skfd = get_fd_from_ssl(ssl_st_p, MSG_WRITE); + cdata = bpf_map_lookup_elem(&conn_map, &ckey); + if (cdata == NULL || cdata->status == READY_FOR_RECVIVE) { +- return; ++ return 0; + } + + cskey.sk = (struct sock *)cdata->sock; + if (cskey.sk == 0) { +- return; ++ return 0; + } + csdata = (struct conn_samp_data_t *)bpf_map_lookup_elem(&conn_samp_map, &cskey); + if (csdata == NULL) { +- return; ++ return 0; + } + csdata->method = cdata->method; + csdata->status = READY_FOR_SKBSENT; +@@ -128,5 +129,5 @@ UPROBE_RET(SSL_write, pt_regs, CTX_USER) + cdata->status = READY_FOR_RECVIVE; + cdata->recvtime = 0; + cdata->method = HTTP_UNKNOWN; +- return; ++ return 0; + } +\ No newline at end of file +diff --git a/src/probes/extends/ebpf.probe/src/include/__bpf_usr.h b/src/probes/extends/ebpf.probe/src/include/__bpf_usr.h +index 95e7160..75ac747 100644 +--- a/src/probes/extends/ebpf.probe/src/include/__bpf_usr.h ++++ b/src/probes/extends/ebpf.probe/src/include/__bpf_usr.h +@@ -53,40 +53,41 @@ + if (ret < 0) { \ + bpf_printk("---UPROBE_RET[" #func "] push failed.\n"); \ + } \ ++ return 0; \ + } while (0) + + #if (CURRENT_LIBBPF_VERSION >= LIBBPF_VERSION(0, 8)) + #define UPROBE(func, type) \ + bpf_section("uprobe") \ +- void ubpf_##func(struct type *ctx) ++ int ubpf_##func(struct type *ctx) + + #define URETPROBE(func, type) \ + bpf_section("uretprobe") \ +- void ubpf_ret_##func(struct type *ctx) ++ int ubpf_ret_##func(struct type *ctx) + #define UPROBE_RET(func, type, prog_id) \ + bpf_section("uprobe") \ +- void __uprobe_bpf_##func(struct type *ctx) { \ ++ int __uprobe_bpf_##func(struct type *ctx) { \ + UPROBE_PARMS_STASH(func, ctx, prog_id); \ + } \ + \ + bpf_section("uretprobe") \ +- void __uprobe_ret_bpf_##func(struct type *ctx) ++ int __uprobe_ret_bpf_##func(struct type *ctx) + #else + #define UPROBE(func, type) \ + bpf_section("uprobe/" #func) \ +- void ubpf_##func(struct type *ctx) ++ int ubpf_##func(struct type *ctx) + + #define URETPROBE(func, type) \ + bpf_section("uretprobe/" #func) \ +- void ubpf_ret_##func(struct type *ctx) ++ int ubpf_ret_##func(struct type *ctx) + #define UPROBE_RET(func, type, prog_id) \ + bpf_section("uprobe/" #func) \ +- void __uprobe_bpf_##func(struct type *ctx) { \ ++ int __uprobe_bpf_##func(struct type *ctx) { \ + UPROBE_PARMS_STASH(func, ctx, prog_id); \ + } \ + \ + bpf_section("uretprobe/" #func) \ +- void __uprobe_ret_bpf_##func(struct type *ctx) ++ int __uprobe_ret_bpf_##func(struct type *ctx) + #endif + + #endif +diff --git a/src/probes/extends/ebpf.probe/src/nginxprobe/nginx_probe.bpf.c b/src/probes/extends/ebpf.probe/src/nginxprobe/nginx_probe.bpf.c +index 159966d..a710d07 100644 +--- a/src/probes/extends/ebpf.probe/src/nginxprobe/nginx_probe.bpf.c ++++ b/src/probes/extends/ebpf.probe/src/nginxprobe/nginx_probe.bpf.c +@@ -66,19 +66,19 @@ UPROBE(ngx_http_upstream_handler, pt_regs) + + struct ngx_connection_s *c = (struct ngx_connection_s *)_(evt->data); + if (c == (void *)0) +- return; ++ return 0; + + struct ngx_http_request_s *r = (struct ngx_http_request_s *)_(c->data); + if (r == (void *)0) +- return; ++ return 0; + + struct ngx_http_upstream_s *u = (struct ngx_http_upstream_s *)_(r->upstream); + if (u == (void *)0) +- return; ++ return 0; + + c = (struct ngx_connection_s *)_(r->connection); + if (c == (void *)0) +- return; ++ return 0; + + struct ngx_metric metric = {0}; + +@@ -92,17 +92,17 @@ UPROBE(ngx_http_upstream_handler, pt_regs) + ngx_str_t *p_name; + bpf_probe_read_user(&p_name, sizeof(void **), &(u->peer.name)); + if (p_name == (void *)0) +- return; ++ return 0; + + unsigned char *dt; + bpf_probe_read_user(&dt, sizeof(void **), &(p_name->data)); + if (dt == (void *)0) +- return; ++ return 0; + + bpf_probe_read_user_str(metric.dst_ip_str, INET6_ADDRSTRLEN, dt); + + bpf_map_update_elem(&hs, &(metric.src_ip), &metric, BPF_ANY); +- return; ++ return 0; + } + + UPROBE(ngx_stream_proxy_init_upstream, pt_regs) +@@ -112,6 +112,7 @@ UPROBE(ngx_stream_proxy_init_upstream, pt_regs) + struct ngx_stream_session_s *s = (struct ngx_stream_session_s *)PT_REGS_PARM1(ctx); + + bpf_map_update_elem(¶_hs, &tid, &s, BPF_ANY); ++ return 0; + } + + URETPROBE(ngx_stream_proxy_init_upstream, pt_regs) +@@ -132,7 +133,7 @@ URETPROBE(ngx_stream_proxy_init_upstream, pt_regs) + t = (struct ngx_stream_session_s **)bpf_map_lookup_elem(¶_hs, &tid); + if (t == (void *)0) { + bpf_printk("bpf_map_lookup_elem para_hs tid:%lu failed\n", tid); +- return; ++ return 0; + } + + s = *t; +@@ -147,24 +148,24 @@ URETPROBE(ngx_stream_proxy_init_upstream, pt_regs) + bpf_probe_read_user(&stream, sizeof(void **), &(s->upstream)); + if (stream == (void *)0) { + bpf_printk("stream null:%p\n", stream); +- return; ++ return 0; + } + + p_name = _(stream->peer.name); + if (p_name == (void *)0) { + bpf_printk("peer.name null\n"); +- return; ++ return 0; + } + + unsigned char *dt = _(p_name->data); + if (dt == (void *)0) { + bpf_printk("name->data null\n"); +- return; ++ return 0; + } + bpf_probe_read_user_str(metric.dst_ip_str, INET6_ADDRSTRLEN, dt); + bpf_map_update_elem(&hs, &(metric.src_ip), &metric, BPF_ANY); + +- return; ++ return 0; + } + + UPROBE(ngx_close_connection, pt_regs) +@@ -179,9 +180,9 @@ UPROBE(ngx_close_connection, pt_regs) + bpf_copy_ip_addr(client_addr, &src_ip); + metric = (struct ngx_metric *)bpf_map_lookup_elem(&hs, &src_ip); + if (metric == (void *)0) +- return; ++ return 0; + + metric->is_finish = 1; + bpf_map_update_elem(&hs, &src_ip, metric, BPF_ANY); +- return; ++ return 0; + } +\ No newline at end of file +diff --git a/src/probes/extends/ebpf.probe/src/pgsliprobe/pgsli_uprobe.bpf.c b/src/probes/extends/ebpf.probe/src/pgsliprobe/pgsli_uprobe.bpf.c +index 2630ce9..eb1241c 100644 +--- a/src/probes/extends/ebpf.probe/src/pgsliprobe/pgsli_uprobe.bpf.c ++++ b/src/probes/extends/ebpf.probe/src/pgsliprobe/pgsli_uprobe.bpf.c +@@ -77,29 +77,29 @@ UPROBE(SSL_read, pt_regs) + + URETPROBE(SSL_read, pt_regs) + { +- u32 tgid __maybe_unused = bpf_get_current_pid_tgid() >> INT_LEN; + struct probe_val val; + if (PROBE_GET_PARMS(SSL_read, ctx, val, PROG_SSL_READ) < 0) { +- return; ++ return 0; + } + + struct ssl_st* ssl_st_p = (struct ssl_st*)PROBE_PARM1(val); + int fd = get_fd_from_ssl(ssl_st_p, MSG_READ); + if (fd < 0) { +- return; ++ return 0; + } + + process_rdwr_msg(fd, (const char *)PROBE_PARM2(val), (int)PT_REGS_RC(ctx), MSG_READ, ctx); ++ return 0; + } + + UPROBE(SSL_write, pt_regs) + { +- u32 tgid __maybe_unused = bpf_get_current_pid_tgid() >> INT_LEN; + struct ssl_st* ssl_st_p = (struct ssl_st*)PT_REGS_PARM1(ctx); + int fd = get_fd_from_ssl(ssl_st_p, MSG_WRITE); + if (fd < 0) { +- return; ++ return 0; + } + + process_rdwr_msg(fd, (char *)PT_REGS_PARM2(ctx), (int)PT_REGS_PARM3(ctx), MSG_WRITE, ctx); ++ return 0; + } +diff --git a/src/probes/extends/ebpf.probe/src/sliprobe/redissli.bpf.c b/src/probes/extends/ebpf.probe/src/sliprobe/redissli.bpf.c +index 207ac00..f3f609c 100644 +--- a/src/probes/extends/ebpf.probe/src/sliprobe/redissli.bpf.c ++++ b/src/probes/extends/ebpf.probe/src/sliprobe/redissli.bpf.c +@@ -126,17 +126,18 @@ UPROBE(readQueryFromClient, pt_regs) + conn_data = create_conn_from_client(c); + } + if (conn_data == (void *)0) { +- return; ++ return 0; + } + + // 当前周期已有采样数据时,不更新客户端连接 + if (conn_data->cmd_nums > 0) { +- return; ++ return 0; + } + + conn_data->last_read_ts_nsec = ts_nsec; + conn_data->rd_bufsize = 0; + conn_data->rd_listsize = 0; ++ return 0; + } + + // 监控 redis 命令处理函数,获取命令的元数据信息 +@@ -152,12 +153,12 @@ UPROBE(processCommand, pt_regs) + + conn_data = get_conn_from_client(c); + if (conn_data == (void *)0) { +- return; ++ return 0; + } + + // 当前周期已有采样数据时,后续数据不再处理 + if (conn_data->cmd_nums > 0) { +- return; ++ return 0; + } + + // 添加一个新请求 +@@ -189,13 +190,13 @@ URETPROBE(processCommand, pt_regs) + u64 cur_listpos; + + if (PROBE_GET_PARMS(processCommand, ctx, val, PROG_PROCESSCOMMAND) < 0) { +- return; ++ return 0; + } + c = (client *)PROBE_PARM1(val); + + conn_data = get_conn_from_client(c); + if (conn_data == (void *)0) { +- return; ++ return 0; + } + + cmd = &(conn_data->cmds[0]); +@@ -215,6 +216,7 @@ URETPROBE(processCommand, pt_regs) + cmd->end_ts_nsec = ts_nsec; + cmd->finished = 1; + } ++ return 0; + } + + // 监控 writeToClient 事件,获取应答消息离开应用层的时间点 +@@ -227,7 +229,7 @@ UPROBE(writeToClient, pt_regs) + + conn_data = get_conn_from_client(c); + if (conn_data == (void *)0) { +- return; ++ return 0; + } + conn_data->cur_bufpos = _(c->bufpos); + conn_data->cur_listpos = _(c->reply_bytes); +@@ -258,13 +260,13 @@ URETPROBE(writeToClient, pt_regs) + u64 period; + + if (PROBE_GET_PARMS(writeToClient, ctx, val, PROG_WRITETOCLIENT) < 0) { +- return; ++ return 0; + } + c = (client *)PROBE_PARM1(val); + + conn_data = get_conn_from_client(c); + if (conn_data == (void *)0) { +- return; ++ return 0; + } + + // 更新客户端连接已处理的响应字节数 +@@ -278,7 +280,7 @@ URETPROBE(writeToClient, pt_regs) + } + + if (conn_data->cmd_nums == 0) { +- return; ++ return 0; + } + + // 当已处理的响应字节数大于 redis 请求的写入位置时,则该请求在应用层处理完毕,记录该请求的结束时间点 +@@ -302,6 +304,7 @@ URETPROBE(writeToClient, pt_regs) + conn_data->last_smp_ts_nsec = ts_nsec; + conn_data->cmd_nums = 0; + } ++ return 0; + } + + // 端口 redis 客户端连接 +@@ -317,7 +320,7 @@ UPROBE(freeClient, pt_regs) + init_conn_key(&conn_key, fd, tgid); + conn_data = (struct conn_data_t *)bpf_map_lookup_elem(&conn_map, &conn_key); + if (conn_data == (void *)0) { +- return; ++ return 0; + } + + if (conn_data->cmd_nums > 0 && conn_data->cmds[0].finished) { +@@ -325,4 +328,5 @@ UPROBE(freeClient, pt_regs) + } + + bpf_map_delete_elem(&conn_map, &conn_key); ++ return 0; + } +\ No newline at end of file +diff --git a/src/probes/extends/ebpf.probe/src/stackprobe/stack_bpf/memleak.bpf.c b/src/probes/extends/ebpf.probe/src/stackprobe/stack_bpf/memleak.bpf.c +index 280b614..a7759d6 100644 +--- a/src/probes/extends/ebpf.probe/src/stackprobe/stack_bpf/memleak.bpf.c ++++ b/src/probes/extends/ebpf.probe/src/stackprobe/stack_bpf/memleak.bpf.c +@@ -185,6 +185,7 @@ UPROBE(malloc, pt_regs) + { + u64 size = (u64)PT_REGS_PARM1(ctx); + alloc_enter(size); ++ return 0; + } + + URETPROBE(malloc, pt_regs) +@@ -192,6 +193,7 @@ URETPROBE(malloc, pt_regs) + + u64 ret = (u64)PT_REGS_RC(ctx); + alloc_exit(ctx, ret); ++ return 0; + } + + UPROBE(calloc, pt_regs) +@@ -199,12 +201,14 @@ UPROBE(calloc, pt_regs) + u64 nmemb = (u64)PT_REGS_PARM1(ctx); + u64 size = (u64)PT_REGS_PARM2(ctx); + alloc_enter(nmemb * size); ++ return 0; + } + + URETPROBE(calloc, pt_regs) + { + u64 ret = (u64)PT_REGS_RC(ctx); + alloc_exit(ctx, ret); ++ return 0; + } + + UPROBE(realloc, pt_regs) +@@ -214,24 +218,28 @@ UPROBE(realloc, pt_regs) + + free_enter(ctx, ptr); + alloc_enter(size); ++ return 0; + } + + URETPROBE(realloc, pt_regs) + { + u64 ret = (u64)PT_REGS_RC(ctx); + alloc_exit(ctx, ret); ++ return 0; + } + + UPROBE(mmap, pt_regs) + { + u64 size = (u64)PT_REGS_PARM2(ctx); + alloc_enter(size); ++ return 0; + } + + URETPROBE(mmap, pt_regs) + { + u64 ret = (u64)PT_REGS_RC(ctx); + alloc_exit(ctx, ret); ++ return 0; + } + + UPROBE(posix_memalign, pt_regs) +@@ -241,6 +249,7 @@ UPROBE(posix_memalign, pt_regs) + u64 pid = bpf_get_current_pid_tgid(); + bpf_map_update_elem(&memalign_allocate, &pid, &memptr, BPF_ANY); + alloc_enter(size); ++ return 0; + } + + URETPROBE(posix_memalign, pt_regs) +@@ -249,72 +258,83 @@ URETPROBE(posix_memalign, pt_regs) + u64 addr; + u64 *memptr = (u64 *)bpf_map_lookup_elem(&memalign_allocate, &pid); + if (memptr == 0) +- return; ++ return 0; + bpf_map_delete_elem(&memalign_allocate, &pid); + + if (bpf_probe_read_user(&addr, sizeof(u64), &memptr)) +- return; ++ return 0; + + alloc_exit(ctx, addr); ++ return 0; + } + + UPROBE(valloc, pt_regs) + { + u64 size = (u64)PT_REGS_PARM1(ctx); + alloc_enter(size); ++ return 0; + } + + URETPROBE(valloc, pt_regs) + { + u64 ret = (u64)PT_REGS_RC(ctx); + alloc_exit(ctx, ret); ++ return 0; + } + + UPROBE(memalign, pt_regs) + { + u64 size = (u64)PT_REGS_PARM1(ctx); + alloc_enter(size); ++ return 0; + } + + URETPROBE(memalign, pt_regs) + { + u64 ret = (u64)PT_REGS_RC(ctx); + alloc_exit(ctx, ret); ++ return 0; + } + + UPROBE(pvalloc, pt_regs) + { + u64 size = (u64)PT_REGS_PARM1(ctx); + alloc_enter(size); ++ return 0; + } + + URETPROBE(pvalloc, pt_regs) + { + u64 ret = (u64)PT_REGS_RC(ctx); + alloc_exit(ctx, ret); ++ return 0; + } + + UPROBE(aligned_alloc, pt_regs) + { + u64 size = (u64)PT_REGS_PARM2(ctx); + alloc_enter(size); ++ return 0; + } + + URETPROBE(aligned_alloc, pt_regs) + { + u64 ret = (u64)PT_REGS_RC(ctx); + alloc_exit(ctx, ret); ++ return 0; + } + + UPROBE(free, pt_regs) + { + u64 size = (u64)PT_REGS_PARM2(ctx); + free_enter(ctx, size); ++ return 0; + } + + UPROBE(munmap, pt_regs) + { + u64 size = (u64)PT_REGS_PARM1(ctx); + free_enter(ctx, size); ++ return 0; + } + +diff --git a/src/probes/extends/ebpf.probe/src/taskprobe/glibc.bpf.c b/src/probes/extends/ebpf.probe/src/taskprobe/glibc.bpf.c +index 3487b22..d4e4373 100644 +--- a/src/probes/extends/ebpf.probe/src/taskprobe/glibc.bpf.c ++++ b/src/probes/extends/ebpf.probe/src/taskprobe/glibc.bpf.c +@@ -72,11 +72,13 @@ static __always_inline void update_gethostname_res(struct pt_regs* ctx) + UPROBE(func, pt_regs) \ + { \ + start_fn(); \ ++ return 0; \ + } \ + \ + URETPROBE(func, pt_regs) \ + { \ + stop_fn(ctx); \ ++ return 0; \ + } + + UPROBE_GLIBC(getaddrinfo, store_dns_op_start_ts, update_gethostname_res) +-- +2.33.0 + diff --git a/fix-modify-unit-of-some-metrics-to-second.patch b/fix-modify-unit-of-some-metrics-to-second.patch new file mode 100644 index 0000000..62a08d1 --- /dev/null +++ b/fix-modify-unit-of-some-metrics-to-second.patch @@ -0,0 +1,102 @@ +From 9ad26e3d4abfb78e99b8d75da384e36badbde75a Mon Sep 17 00:00:00 2001 +From: dowzyx +Date: Thu, 16 Mar 2023 16:09:07 +0800 +Subject: [PATCH 23/30] fix: modify unit of some metrics to second + +--- + .../extends/java.probe/jvm.probe/jvm_probe.meta | 14 +++++++------- + .../jvm.probe/src/agent/JvmProbeAgent.java | 13 +++++++------ + 2 files changed, 14 insertions(+), 13 deletions(-) + +diff --git a/src/probes/extends/java.probe/jvm.probe/jvm_probe.meta b/src/probes/extends/java.probe/jvm.probe/jvm_probe.meta +index bb9d01a..d80341a 100755 +--- a/src/probes/extends/java.probe/jvm.probe/jvm_probe.meta ++++ b/src/probes/extends/java.probe/jvm.probe/jvm_probe.meta +@@ -18,12 +18,12 @@ measurements: + name: "runtime", + }, + { +- description: "....", ++ description: "JVM implementation vender.", + type: "label", + name: "vendor", + }, + { +- description: "....", ++ description: "the JVM implementation version.", + type: "label", + name: "version", + }, +@@ -163,7 +163,7 @@ measurements: + name: "tgid", + }, + { +- description: "....", ++ description: "name representing a memory pool.", + type: "key", + name: "pool", + }, +@@ -210,8 +210,8 @@ measurements: + name: "tgid", + }, + { +- description: "....", +- type: "label", ++ description: "name representing a buffer pool.", ++ type: "key", + name: "pool", + }, + { +@@ -242,8 +242,8 @@ measurements: + name: "tgid", + }, + { +- description: "....", +- type: "label", ++ description: "name representing a GC.", ++ type: "key", + name: "gc", + }, + { +diff --git a/src/probes/extends/java.probe/jvm.probe/src/agent/JvmProbeAgent.java b/src/probes/extends/java.probe/jvm.probe/src/agent/JvmProbeAgent.java +index 488c73c..d7f635d 100644 +--- a/src/probes/extends/java.probe/jvm.probe/src/agent/JvmProbeAgent.java ++++ b/src/probes/extends/java.probe/jvm.probe/src/agent/JvmProbeAgent.java +@@ -22,7 +22,7 @@ import java.lang.reflect.InvocationTargetException; + public class JvmProbeAgent { + + private static final int MSEC_PER_SEC = 1000; +- private static final int NSEC_PER_SEC = 1000000; ++ private static final int NSEC_PER_SEC = 1000000000; + private static final String METRIC_FILE_NAME = "jvm-metrics.txt"; + private static String pid; + private static String nspid; +@@ -79,10 +79,11 @@ public class JvmProbeAgent { + } + + private static void processCollector(RuntimeMXBean runtimeBean, OperatingSystemMXBean osBean) { +- long processStartTime = runtimeBean.getStartTime(); // ms ++ long processStartTime = runtimeBean.getStartTime(); // ms + try { +- Long processCpuTime = callLongGetter(osBean.getClass().getMethod("getProcessCpuTime"), osBean); // ns +- writeMetricRecords(String.format("|jvm_process|%s|%d|%d|\n", pid, processStartTime, processCpuTime)); ++ Long processCpuTime = callLongGetter(osBean.getClass().getMethod("getProcessCpuTime"), osBean); // ns ++ writeMetricRecords(String.format("|jvm_process|%s|%f|%f|\n", ++ pid, ((double)processStartTime / MSEC_PER_SEC), ((double)processCpuTime / NSEC_PER_SEC))); + } catch (Exception e) { + //System.out.println("error"); + } +@@ -169,8 +170,8 @@ public class JvmProbeAgent { + // gc + private static void gcCollector(List garbageCollectors) { + for (GarbageCollectorMXBean gc : garbageCollectors) { +- writeMetricRecords(String.format("|jvm_gc|%s|%s|%d|%d|\n", +- pid, gc.getName(), gc.getCollectionCount(), gc.getCollectionTime())); // ms ++ writeMetricRecords(String.format("|jvm_gc|%s|%s|%d|%f|\n", ++ pid, gc.getName(), gc.getCollectionCount(), ((double)gc.getCollectionTime() / MSEC_PER_SEC))); + } + } + +-- +2.33.0 + diff --git a/gala-gopher.spec b/gala-gopher.spec index 5515093..c668ff3 100644 --- a/gala-gopher.spec +++ b/gala-gopher.spec @@ -6,7 +6,7 @@ Summary: Intelligent ops toolkit for openEuler Name: gala-gopher Version: 1.0.2 -Release: 1 +Release: 2 License: Mulan PSL v2 URL: https://gitee.com/openeuler/gala-gopher Source: %{name}-%{version}.tar.gz @@ -15,10 +15,18 @@ BuildRequires: systemd cmake gcc-c++ elfutils-devel libcurl-devel BuildRequires: clang >= 10.0.1 llvm java-1.8.0-openjdk-devel BuildRequires: libconfig-devel librdkafka-devel libmicrohttpd-devel BuildRequires: libbpf-devel >= 2:0.3 uthash-devel log4cplus-devel -BuildRequires: CUnit CUnit-devel dmidecode junit ethtool bpftool procps-ng -Requires: bash glibc elfutils zlib bpftool dmidecode +BuildRequires: CUnit CUnit-devel dmidecode junit ethtool bpftool procps-ng iproute +Requires: bash glibc elfutils bpftool dmidecode Requires: python3-psycopg2 python3-yaml flamegraph iproute libcurl -Requires: libbpf >= 2:0.3 kmod net-tools ethtool +Requires: libbpf >= 2:0.3 kmod net-tools ethtool cadvisor python3-libconf python3-requests + +Patch1: refactor-modify-jvmprobe-to-support-pod.patch +Patch2: change-return-type-of-uprobe-from-void-to-int.patch +Patch3: fix-modify-unit-of-some-metrics-to-second.patch +Patch4: bugfix-fix-system_proc-collect-data-err.patch +Patch5: Fix-for-popen-cannot-get-stderr.patch +Patch6: bugfix-add-check-whether-cadvisor-is-installed.patch +Patch7: stackprobe-fix-inaccurate-call-stack-count.-add-samp.patch %description gala-gopher is a low-overhead eBPF-based probes framework @@ -78,6 +86,16 @@ fi /usr/lib/systemd/system/gala-gopher.service %changelog +* Fri Apr 7 2023 Tangxin Xie - 1.0.2-2 +- bugfix add check whether cadvisor is installed + bugfix fix system_proc collect data err + change return type of uprobe from void to int + Fix for popen cannot get stderr + fix modify unit of some metrics to second + refactor modify jvmprobe to support pod + stackprobe fix inaccurate call stack count add samp + add python3-libconf and python3-request deps + * Fri Mar 3 2023 Tangxin Xie - 1.0.2-1 - update to 1.0.2 diff --git a/refactor-modify-jvmprobe-to-support-pod.patch b/refactor-modify-jvmprobe-to-support-pod.patch new file mode 100644 index 0000000..0b4f528 --- /dev/null +++ b/refactor-modify-jvmprobe-to-support-pod.patch @@ -0,0 +1,1191 @@ +From 5b8ecf7c24ca91a37b2073d4ee1a462f7aab5760 Mon Sep 17 00:00:00 2001 +From: dowzyx +Date: Thu, 9 Mar 2023 20:30:06 +0800 +Subject: [PATCH 16/30] refactor: modify jvmprobe to support pod + +--- + src/probes/extends/java.probe/build.sh | 100 +++--- + src/probes/extends/java.probe/install.sh | 5 +- + .../jvm.probe/config/META-INF/MANIFEST.MF | 1 - + .../java.probe/jvm.probe/jvm_probe.meta | 231 ++++++++++--- + .../java.probe/jvm.probe/src/JvmProbe.java | 305 +++++++++++++----- + .../extends/java.probe/jvm.probe/src/Vm.java | 173 ---------- + .../jvm.probe/src/agent/JvmProbeAgent.java | 188 +++++++++++ + .../src/agent/config/META-INF/MANIFEST.MF | 6 + + 8 files changed, 657 insertions(+), 352 deletions(-) + delete mode 100644 src/probes/extends/java.probe/jvm.probe/src/Vm.java + create mode 100644 src/probes/extends/java.probe/jvm.probe/src/agent/JvmProbeAgent.java + create mode 100644 src/probes/extends/java.probe/jvm.probe/src/agent/config/META-INF/MANIFEST.MF + +diff --git a/src/probes/extends/java.probe/build.sh b/src/probes/extends/java.probe/build.sh +index 0ea7782..3c6f4e0 100755 +--- a/src/probes/extends/java.probe/build.sh ++++ b/src/probes/extends/java.probe/build.sh +@@ -4,95 +4,79 @@ PRJ_DIR=$(dirname $(readlink -f "$0")) + BUILD_FILES=${PRJ_DIR}/jvm.probe + cd ${BUILD_FILES} + +-function find_jars() ++function find_cmd_jar() + { +- if [ -z $JAVA_HOME ]; +- then +- # find jdk +- clink_path=$(echo $(ls -lrt $javac_link) | awk -F " " '{print $NF}' ) +- link_path=$(echo $(ls -lrt $clink_path) | awk -F " " '{print $NF}' ) +- jdk_path=$(dirname $(dirname $link_path)) +- dir=$jdk_path +- else +- dir=$JAVA_HOME +- fi +- +- #tools.jar +- if [ -e $dir/lib/tools.jar ]; +- then +- mkdir -p lib +- cp $dir/lib/tools.jar lib/ +- else +- echo "Error: tools.jar not found" +- return 1 +- fi +- +- #management.jar +- if [ -e $dir/jre/lib/management-agent.jar ]; ++ if [ -z $(which jar 2>/dev/null) ]; + then +- cp $dir/jre/lib/management-agent.jar lib/ +- else +- echo "Error: management-agent.jar not found" ++ echo "Error: jar command not found" + return 1 +- fi +- +- return 0 ++ else ++ return 0 ++ fi + } + +-function make_probe_jar() ++function make_probe_agent_jar() + { +- mkdir -p tmp +- cd tmp +- javac -cp ../lib/tools.jar ../src/*.java -d ./ ++ mkdir -p tmp ++ cd tmp ++ javac ../src/agent/JvmProbeAgent.java -d ./ ++ cd .. ++ jar cfm JvmProbeAgent.jar src/agent/config/META-INF/MANIFEST.MF -C tmp/ . + +- if [ -z $(which jar 2>/dev/null) ]; +- then +- echo "Error: jar command not found" +- return 1 +- else +- jar xf ../lib/tools.jar #>/dev/null 2>&1 +- cp ../lib/management-agent.jar ./ +- cd .. +- jar cfm JvmProbe.jar config/META-INF/MANIFEST.MF -C tmp/ . #2>/dev/null +- fi ++ rm -rf tmp 2>/dev/null ++ return 0 ++} ++ ++function make_probe_jar() ++{ ++ mkdir -p tmp ++ cd tmp/ ++ javac ../src/JvmProbe.java -d . ++ cd .. ++ jar cfm JvmProbe.jar config/META-INF/MANIFEST.MF -C tmp/ . + +- rm -rf tmp 2>/dev/null +- +- return 0 ++ rm -rf tmp 2>/dev/null ++ return 0 + } + + function compile_clean() + { +- rm -rf lib 2>/dev/null +- rm -rf tmp 2>/dev/null ++ rm -rf tmp 2>/dev/null + } + + if [ "$1" == "-c" -o "$1" == "--clean" ]; + then + compile_clean ++ rm -f *.jar 2>/dev/null + exit + fi + + java_link=$(which java 2>/dev/null) + javac_link=$(which javac 2>/dev/null) +- +-if [ -z $java_link ] || [ -z $javac_link ]; ++ ++if [ -z $java_link ] || [ -z $javac_link ]; + then + echo "Error: java and javac : command not found" + exit 1 +-else +- find_jars ++else ++ find_cmd_jar + if [ $? -eq 1 ]; + then +- exit 1 +- fi +- ++ exit 1 ++ fi ++ ++ make_probe_agent_jar ++ if [ $? -eq 1 ]; ++ then ++ exit 1 ++ fi ++ + make_probe_jar + if [ $? -eq 1 ]; + then +- exit 1 ++ exit 1 + fi +- ++ + compile_clean + exit + fi +diff --git a/src/probes/extends/java.probe/install.sh b/src/probes/extends/java.probe/install.sh +index ee653b5..4111fb3 100755 +--- a/src/probes/extends/java.probe/install.sh ++++ b/src/probes/extends/java.probe/install.sh +@@ -2,6 +2,7 @@ + PROGRAM=$0 + PRJ_DIR=$(dirname $(readlink -f "$0")) + INSTALL_FILES="jvm.probe/JvmProbe.jar" ++INSTALL_FILES+=" jvm.probe/JvmProbeAgent.jar" + + while getopts ":b:c:" opt + do +@@ -15,6 +16,8 @@ done + cd ${PRJ_DIR} + if [ ${INSTALL_PATH} ]; then + mkdir -p ${INSTALL_PATH} +- \cp ${INSTALL_FILES} ${INSTALL_PATH} ++ for file in ${INSTALL_FILES}; do ++ cp ${file} ${INSTALL_PATH} ++ done + fi + +diff --git a/src/probes/extends/java.probe/jvm.probe/config/META-INF/MANIFEST.MF b/src/probes/extends/java.probe/jvm.probe/config/META-INF/MANIFEST.MF +index 9f2a9af..fd73d72 100644 +--- a/src/probes/extends/java.probe/jvm.probe/config/META-INF/MANIFEST.MF ++++ b/src/probes/extends/java.probe/jvm.probe/config/META-INF/MANIFEST.MF +@@ -1,5 +1,4 @@ + Manifest-Version: 1.0 +-Class-Path: management-agent.jar + Created-By: 1.8.0_333 (Oracle Corporation) + Main-Class: JvmProbe + +diff --git a/src/probes/extends/java.probe/jvm.probe/jvm_probe.meta b/src/probes/extends/java.probe/jvm.probe/jvm_probe.meta +index bcce601..bb9d01a 100755 +--- a/src/probes/extends/java.probe/jvm.probe/jvm_probe.meta ++++ b/src/probes/extends/java.probe/jvm.probe/jvm_probe.meta +@@ -3,100 +3,259 @@ version = "1.0.0" + measurements: + ( + { +- table_name: "jvm", ++ table_name: "jvm_info", + entity_name: "jvm", + fields: + ( + { +- description: "ID of current java process ", ++ description: "ID of current java process.", + type: "key", + name: "tgid", + }, + { +- description: "pkg_name-java_main_class", ++ description: "JVM runtime Environment.", + type: "label", +- name: "pkg_name_main_class", ++ name: "runtime", + }, + { +- description: "JVM specification version ", ++ description: "....", + type: "label", +- name: "jvm_version", ++ name: "vendor", + }, + { +- description: "JVM implementation name ", ++ description: "....", + type: "label", +- name: "jvm_type", ++ name: "version", + }, + { +- description: "Garbage collectors` average usage", ++ description: "a fixed num 1 as metric", + type: "gauge", +- name: "gc_activity_util", ++ name: "info", ++ } ++ ) ++ }, ++ { ++ table_name: "jvm_process", ++ entity_name: "jvm", ++ fields: ++ ( ++ { ++ description: "ID of current java process.", ++ type: "key", ++ name: "tgid", + }, + { +- description: "Garbage collector collection counts", ++ description: "Start time of the process since unix epoch in seconds.", + type: "gauge", +- name: "gc_total_count", ++ name: "process_start_time_seconds", + }, + { +- description: "Total garbage collector collection time", ++ description: "Total user and system CPU time spent in seconds.", + type: "gauge", +- name: "gc_total_seconds", ++ name: "process_cpu_seconds_total", + }, ++ ) ++ }, ++ { ++ table_name: "jvm_class", ++ entity_name: "jvm", ++ fields: ++ ( + { +- description: "Process start time in seconds", ++ description: "ID of current java process.", ++ type: "key", ++ name: "tgid", ++ }, ++ { ++ description: "Start time of the process since unix epoch in seconds.", + type: "gauge", +- name: "process_start_time_seconds", ++ name: "classes_currently_loaded", + }, + { +- description: "Process run time in seconds", ++ description: "Total user and system CPU time spent in seconds.", + type: "gauge", +- name: "process_run_time_seconds", ++ name: "classes_loaded_total", ++ }, ++ ) ++ }, ++ { ++ table_name: "jvm_thread", ++ entity_name: "jvm", ++ fields: ++ ( ++ { ++ description: "ID of current java process.", ++ type: "key", ++ name: "tgid", + }, + { +- description: "The number of threads in the current process", ++ description: "Current thread count of a JVM.", + type: "gauge", + name: "threads_current", + }, + { +- description: "The peak number of threads of the java process", ++ description: "Daemon thread count of a JVM.", ++ type: "gauge", ++ name: "threads_daemon", ++ }, ++ { ++ description: "Peak thread count of a JVM.", + type: "gauge", + name: "threads_peak", + }, + { +- description: "Deadlocked JVM thread number", ++ description: "Started thread count of a JVM.", ++ type: "gauge", ++ name: "threads_started_total", ++ }, ++ { ++ description: "Cycles of JVM-threads that are in deadlock waiting to acquire object monitors or ownable synchronizers.", + type: "gauge", + name: "threads_deadlocked", + }, ++ ) ++ }, ++ { ++ table_name: "jvm_mem", ++ entity_name: "jvm", ++ fields: ++ ( ++ { ++ description: "ID of current java process.", ++ type: "key", ++ name: "tgid", ++ }, ++ { ++ description: "type of JVM memory type: heap or noheap.", ++ type: "key", ++ name: "area", ++ }, + { +- description: "Used bytes of JVM _Heap memory area", ++ description: "Used bytes of a given JVM memory area.", + type: "gauge", +- name: "heap_memory_bytes_used", ++ name: "memory_bytes_used", + }, + { +- description: "JVM _Heap occupation", ++ description: "Committed (bytes) of a given JVM memory area.", + type: "gauge", +- name: "heap_occuped_percent", ++ name: "memory_bytes_committed", + }, + { +- description: "Used bytes of JVM _NonHeap memory area", ++ description: "Max (bytes) of a given JVM memory area.", + type: "gauge", +- name: "nonheap_memory_bytes_used", ++ name: "memory_bytes_max", + }, + { +- description: "JVM _NonHeap occupation", ++ description: "Initial bytes of a given JVM memory area.", + type: "gauge", +- name: "nonheap_occuped_percent", ++ name: "memory_bytes_init", + }, ++ ) ++ }, ++ { ++ table_name: "jvm_mem_pool", ++ entity_name: "jvm", ++ fields: ++ ( + { +- description: "The total capacity of the JVM buffer pools", +- type: "gauge", +- name: "buffer_pool_total_size", ++ description: "ID of current java process.", ++ type: "key", ++ name: "tgid", + }, + { +- description: "the memory that the JVM uses for buffer pools", +- type: "gauge", +- name: "buffer_pool_used_bytes", +- } ++ description: "....", ++ type: "key", ++ name: "pool", ++ }, ++ { ++ description: "Used bytes of a given JVM memory pool.", ++ type: "gauge", ++ name: "memory_pool_bytes_used", ++ }, ++ { ++ description: "Committed bytes of a given JVM memory pool.", ++ type: "gauge", ++ name: "memory_pool_bytes_committed", ++ }, ++ { ++ description: "Max bytes of a given JVM memory pool.", ++ type: "gauge", ++ name: "memory_pool_bytes_max", ++ }, ++ { ++ description: "Used bytes after last collection of a given JVM memory pool.", ++ type: "gauge", ++ name: "memory_pool_collection_used_bytes", ++ }, ++ { ++ description: "Committed after last collection bytes of a given JVM memory pool.", ++ type: "gauge", ++ name: "memory_pool_collection_committed_bytes", ++ }, ++ { ++ description: "Max bytes after last collection of a given JVM memory pool.", ++ type: "gauge", ++ name: "memory_pool_collection_max_bytes", ++ }, ++ ) ++ }, ++ { ++ table_name: "jvm_buf_pool", ++ entity_name: "jvm", ++ fields: ++ ( ++ { ++ description: "ID of current java process.", ++ type: "key", ++ name: "tgid", ++ }, ++ { ++ description: "....", ++ type: "label", ++ name: "pool", ++ }, ++ { ++ description: "Used bytes of a given JVM buffer pool.", ++ type: "gauge", ++ name: "buffer_pool_used_bytes", ++ }, ++ { ++ description: "Used buffers of a given JVM buffer pool.", ++ type: "gauge", ++ name: "buffer_pool_used_buffers", ++ }, ++ { ++ description: "Bytes capacity of a given JVM buffer pool.", ++ type: "gauge", ++ name: "buffer_pool_capacity_bytes", ++ }, ++ ) ++ }, ++ { ++ table_name: "jvm_gc", ++ entity_name: "jvm", ++ fields: ++ ( ++ { ++ description: "ID of current java process.", ++ type: "key", ++ name: "tgid", ++ }, ++ { ++ description: "....", ++ type: "label", ++ name: "gc", ++ }, ++ { ++ description: "Collection count of a given JVM garbage collector.", ++ type: "gauge", ++ name: "gc_collection_seconds_count", ++ }, ++ { ++ description: "Time spent in a given JVM garbage collector in seconds.", ++ type: "gauge", ++ name: "gc_collection_seconds_sum", ++ }, + ) + } + ) +diff --git a/src/probes/extends/java.probe/jvm.probe/src/JvmProbe.java b/src/probes/extends/java.probe/jvm.probe/src/JvmProbe.java +index 9c67f17..81d64ba 100644 +--- a/src/probes/extends/java.probe/jvm.probe/src/JvmProbe.java ++++ b/src/probes/extends/java.probe/jvm.probe/src/JvmProbe.java +@@ -1,83 +1,222 @@ +-import com.sun.tools.attach.*; +-import java.io.File; +-import java.io.IOException; +-import java.io.InputStream; +-import java.nio.file.Files; +-import java.nio.file.StandardCopyOption; +-import java.util.List; +-import java.util.HashMap; +-import java.util.concurrent.ExecutorService; +-import java.util.concurrent.Executors; +-import java.util.concurrent.TimeUnit; +- +-public class JvmProbe { +- +- public static List virtualMachineDescriptors; +- public static ExecutorService executorService; +- public static int time = 5; +- public static String agentPath; +- final static String agent = "management-agent.jar"; +- +- public static void main(String[] args) { +- ArgsParse(args); +- try { +- agentPath = getTemporaryRes(agent); +- } catch (IOException e) { +- System.out.println(e.getMessage()); +- System.exit(1); +- } +- +- while (true) { +- try { +- probe(); +- TimeUnit.SECONDS.sleep(time); +- } catch (InterruptedException e) { +- System.out.println(e.getMessage()); +- } +- } +- } +- +- public static void ArgsParse(String[] args) { +- int argsLen = args.length; +- HashMap argsMap = new HashMap<>(); +- for (int i = 0; i < argsLen / 2; i++) { +- argsMap.put(args[i], args[i + 1]); +- } +- //set +- if (argsMap.containsKey("-t")) { +- time = Integer.parseInt(argsMap.get("-t")); +- } +- } +- +- public static void probe() { +- virtualMachineDescriptors = VirtualMachine.list(); +- if (executorService == null) { +- executorService = Executors.newFixedThreadPool(5); +- } +- +- for (VirtualMachineDescriptor virtualMachineDescriptor : virtualMachineDescriptors) { +- executorService.submit(() -> { +- try { +- Vm vm = new Vm(virtualMachineDescriptor, agentPath); +- vm.getData(); +- } catch (IOException | AgentLoadException | AttachNotSupportedException | AgentInitializationException e) { +- System.out.println(e.getMessage()); +- } +- }); +- } +- } +- +- public static String getTemporaryRes(String resource) throws IOException { +- //read embedded resource from this JAR +- InputStream inputStream = JvmProbe.class.getResourceAsStream(resource); +- if(inputStream == null){ +- throw new IOException("Resource not found in the JAR"); +- } +- // create a temporary file +- File temporaryFile = File.createTempFile("resource", null); +- temporaryFile.deleteOnExit(); +- // Copy the resource data into the temporary file +- Files.copy(inputStream, temporaryFile.toPath(), StandardCopyOption.REPLACE_EXISTING); +- return temporaryFile.getAbsolutePath(); +- } +-} ++import java.io.IOException; ++import java.io.File; ++import java.util.List; ++import java.util.ArrayList; ++import java.util.Map; ++import java.util.HashMap; ++import java.util.concurrent.TimeUnit; ++import java.lang.Process; ++import java.lang.ProcessBuilder; ++import java.io.BufferedReader; ++import java.io.InputStreamReader; ++import java.io.FileInputStream; ++import java.nio.file.Files; ++import java.nio.file.StandardCopyOption; ++ ++public class JvmProbe { ++ ++ private static String PROC_COMM_CMD = "/usr/bin/cat /proc/%d/comm 2> /dev/null"; ++ private static String PROC_STATUS_CMD = ++ "/usr/bin/cat /proc/%s/status 2> /dev/null | grep -w NStgid | awk -F ' ' '{print $NF}'"; ++ private static String BPFTOOL_DUMP_PROCMAP_CMD = ++ "bpftool map dump pinned /sys/fs/bpf/probe/proc_map 2> /dev/null | grep key | awk -F ' ' '{print $5$4$3$2}'"; ++ // jvm_attach load instrument false "/tmp/JvmProbeAgent.jar=," ++ private static String ATTACH_CMD = "%s %s %s load instrument false \"%s=%s,%s\""; ++ private final static String ATTACH_BIN_PATH = "/opt/gala-gopher/extend_probes/jvm_attach"; ++ private final static String HOST_JAR_DIR = "/opt/gala-gopher/extend_probes"; ++ private final static String NS_TMP_DIR = "/tmp"; ++ private final static String AGENT_JAR_NAME = "JvmProbeAgent.jar"; ++ private static final String METRIC_FILE_NAME = "jvm-metrics.txt"; ++ private static int period = 5; ++ ++ private static class ProcessInfo { ++ String pid; ++ String nspid; ++ } ++ ++ private static void argsParse(String[] args) { ++ int argsLen = args.length; ++ HashMap argsMap = new HashMap<>(); ++ for (int i = 0; i < argsLen / 2; i++) { ++ argsMap.put(args[i], args[i + 1]); ++ } ++ //set ++ if (argsMap.containsKey("-t")) { ++ period = Integer.parseInt(argsMap.get("-t")); ++ } ++ } ++ ++ private static Boolean detactProcIsJava(int procId) throws IOException { ++ List commandList = new ArrayList<>(); ++ commandList.add("sh"); ++ commandList.add("-c"); ++ commandList.add(String.format(PROC_COMM_CMD, procId)); ++ ++ ProcessBuilder pb = new ProcessBuilder(commandList); ++ Process process = pb.start(); ++ ++ BufferedReader br = new BufferedReader(new InputStreamReader(process.getInputStream())); ++ String line = null; ++ while ((line = br.readLine()) != null) { ++ if (line.equals("java")) { ++ return true; ++ } ++ } ++ return false; ++ } ++ ++ private static List checkProcessToAttach() throws IOException, InterruptedException { ++ List pidList = new ArrayList<>(); ++ List commandList = new ArrayList<>(); ++ commandList.add("sh"); ++ commandList.add("-c"); ++ commandList.add(BPFTOOL_DUMP_PROCMAP_CMD); ++ ++ ProcessBuilder pb = new ProcessBuilder(commandList); ++ Process process = pb.start(); ++ int ret = process.waitFor(); ++ if (ret != 0) { ++ System.out.println("Process exited with code: " + ret + " cmd: " + commandList); ++ return pidList; // empty list ++ } ++ BufferedReader br = new BufferedReader(new InputStreamReader(process.getInputStream())); ++ String line = null; ++ while ((line = br.readLine()) != null) { ++ int decimal = Integer.decode(String.format("0x%s", line)); ++ if (detactProcIsJava(decimal)) { ++ pidList.add(decimal); ++ } ++ } ++ ++ return pidList; ++ } ++ ++ private static ProcessInfo setEffectiveId(String pid) throws IOException { ++ ProcessInfo attachInfo = new ProcessInfo(); ++ List commandList = new ArrayList<>(); ++ commandList.add("sh"); ++ commandList.add("-c"); ++ commandList.add(String.format(PROC_STATUS_CMD, pid)); ++ ++ ProcessBuilder pb = new ProcessBuilder(commandList); ++ Process process = pb.start(); ++ ++ BufferedReader br = new BufferedReader(new InputStreamReader(process.getInputStream())); ++ String line = null; ++ while ((line = br.readLine()) != null) { ++ attachInfo.nspid = line; ++ } ++ ++ attachInfo.pid = pid; ++ return attachInfo; ++ } ++ ++ private static void setJarFileToTmp(String Pid) throws IOException { ++ File nsAgentPath = new File(String.format("/proc/%s/root%s/%s", Pid, NS_TMP_DIR, AGENT_JAR_NAME)); ++ File hostAgentJarPath = new File(String.format("%s/%s", HOST_JAR_DIR, AGENT_JAR_NAME)); ++ ++ Files.copy(hostAgentJarPath.toPath(), nsAgentPath.toPath(), StandardCopyOption.REPLACE_EXISTING); ++ } ++ ++ private static Boolean getNsJarPath(ProcessInfo attachInfo) { ++ if (attachInfo.nspid.equals(attachInfo.pid)) { ++ return true; ++ } ++ return false; ++ } ++ ++ private static void delTmpFile(File file) { ++ if (file.delete() != true) { ++ System.out.println("delete file failed.\n"); ++ } ++ } ++ ++ private static int doAttach(ProcessInfo attachInfo) throws IOException, InterruptedException { ++ int ret = -1; ++ List commandList = new ArrayList<>(); ++ if (attachInfo.pid == null || attachInfo.nspid == null) { ++ System.out.println("attach failed becase null pid or nspid"); ++ return -1; ++ } ++ String nsJarPath; ++ if (getNsJarPath(attachInfo)) { ++ nsJarPath = String.format("/proc/%s/root%s/%s", attachInfo.pid, NS_TMP_DIR, AGENT_JAR_NAME); ++ } else { ++ nsJarPath = String.format("%s/%s", NS_TMP_DIR, AGENT_JAR_NAME); ++ } ++ ++ commandList.add("sh"); ++ commandList.add("-c"); ++ commandList.add(String.format(ATTACH_CMD, ++ ATTACH_BIN_PATH, attachInfo.pid, attachInfo.nspid, nsJarPath, attachInfo.pid, attachInfo.nspid)); ++ ++ ProcessBuilder pb = new ProcessBuilder(commandList); ++ Process process = pb.start(); ++ ret = process.waitFor(); ++ if (ret != 0) { ++ System.out.println("Program attach exited with code: " + ret + " command: " + commandList); ++ } ++ ++ return ret; ++ } ++ ++ private static int readMetricFile(ProcessInfo attachInfo) throws IOException { ++ File jvmMetricFile = new File(String.format("/proc/%s/root/tmp/%s", attachInfo.pid, METRIC_FILE_NAME)); ++ if (!jvmMetricFile.exists()) { ++ System.out.printf("Proc[%s] has no jvm metric file in /tmp path.\n", attachInfo.pid); ++ return 0; ++ } ++ ++ InputStreamReader streamReader = new InputStreamReader(new FileInputStream(jvmMetricFile)); ++ BufferedReader br = new BufferedReader(streamReader); ++ String line = null; ++ while ((line = br.readLine()) != null) { ++ System.out.println(line); ++ } ++ ++ // del metric file after read ++ if (jvmMetricFile.delete() != true) { ++ System.out.println("delete jvm metric file failed.\n"); ++ return -1; ++ } ++ ++ return 0; ++ } ++ ++ private static void probe() throws IOException, InterruptedException { ++ List jvmProcList = checkProcessToAttach(); ++ System.out.println(jvmProcList); ++ ++ for (int i = 0; i < jvmProcList.size(); i++) { ++ ProcessInfo attachInfo = setEffectiveId(jvmProcList.get(i).toString()); ++ try { ++ setJarFileToTmp(attachInfo.pid); ++ } catch (IOException e) { ++ System.out.println("copy host_jar to ns_tmp failed, err: %s" + e.getMessage()); ++ continue; ++ } ++ doAttach(attachInfo); ++ readMetricFile(attachInfo); ++ } ++ } ++ ++ public static void main(String[] args) { ++ argsParse(args); ++ while (true) { ++ try { ++ probe(); ++ } catch (IOException e) { ++ System.out.println(e.getMessage()); ++ } catch (InterruptedException e) { ++ System.out.println(e.getMessage()); ++ } ++ // sleep ++ try { ++ TimeUnit.SECONDS.sleep(period); ++ } catch (InterruptedException e) { ++ System.out.println(e.getMessage()); ++ } ++ } ++ } ++ ++} +diff --git a/src/probes/extends/java.probe/jvm.probe/src/Vm.java b/src/probes/extends/java.probe/jvm.probe/src/Vm.java +deleted file mode 100644 +index 61d111d..0000000 +--- a/src/probes/extends/java.probe/jvm.probe/src/Vm.java ++++ /dev/null +@@ -1,173 +0,0 @@ +-import com.sun.tools.attach.*; +-import javax.management.MBeanServerConnection; +-import javax.management.remote.JMXConnector; +-import javax.management.remote.JMXConnectorFactory; +-import javax.management.remote.JMXServiceURL; +-import java.io.IOException; +-import java.lang.management.*; +-import java.util.List; +-import java.util.concurrent.TimeUnit; +- +- +-public class Vm { +- public VirtualMachineDescriptor virtualMachineDescriptor; +- public MBeanServerConnection mBeanServerConnection; +- public JMXConnector connector; +- public final String canonicalPath; +- public StringBuilder res; +- +- final String localConnectorAddress = "com.sun.management.jmxremote.localConnectorAddress"; +- +- public Vm(VirtualMachineDescriptor virtualMachineDescriptor,String canonicalPath) throws AgentLoadException, IOException, AttachNotSupportedException, AgentInitializationException { +- this.virtualMachineDescriptor = virtualMachineDescriptor; +- this.canonicalPath = canonicalPath; +- getTargetVmConnection(virtualMachineDescriptor.id()); +- res = new StringBuilder(); +- } +- +- private void getTargetVmConnection(String vmId) throws IOException, AttachNotSupportedException, AgentLoadException, AgentInitializationException { +- +- VirtualMachine virtualMachine = VirtualMachine.attach(vmId); +- virtualMachine.loadAgent(canonicalPath); +- +- String connectorAddress = (String) virtualMachine.getAgentProperties().get(localConnectorAddress); +- virtualMachine.detach(); +- this.connector = JMXConnectorFactory.connect(new JMXServiceURL(connectorAddress)); +- this.mBeanServerConnection = connector.getMBeanServerConnection(); +- } +- +- public void getData() { +- try { +- getInfo(this.mBeanServerConnection); +- } catch (IOException e) { +- System.out.println(e.getMessage()); +- } finally { +- try { +- connector.close(); +- } catch (IOException e) { +- System.out.println(e.getMessage()); +- } +- } +- } +- +- private void getInfo(MBeanServerConnection connection) throws IOException { +- RuntimeMXBean runtimeMXBean = ManagementFactory.newPlatformMXBeanProxy( +- connection, ManagementFactory.RUNTIME_MXBEAN_NAME, RuntimeMXBean.class); +- com.sun.management.OperatingSystemMXBean operatingSystemMXBean = ManagementFactory.newPlatformMXBeanProxy(connection, +- ManagementFactory.OPERATING_SYSTEM_MXBEAN_NAME, com.sun.management.OperatingSystemMXBean.class); +- List garbageCollectorMXBeans = ManagementFactory.getPlatformMXBeans( +- connection,GarbageCollectorMXBean.class); +- ThreadMXBean threadMXBean = ManagementFactory.newPlatformMXBeanProxy( +- connection, ManagementFactory.THREAD_MXBEAN_NAME, ThreadMXBean.class); +- MemoryMXBean memoryMXBean = ManagementFactory.newPlatformMXBeanProxy( +- connection, ManagementFactory.MEMORY_MXBEAN_NAME, MemoryMXBean.class); +- List pools = ManagementFactory.getPlatformMXBeans( +- connection,BufferPoolMXBean.class); +- // tid % mainclass +- String jvmPid = virtualMachineDescriptor.id(); +- String[] split = virtualMachineDescriptor.displayName().split(" "); +- String pkgNameMainClass = split[0]; +- res.append(String.format("|jvm|%s|%s|", jvmPid, pkgNameMainClass)); +- +- // vesion % type +- String jvmVersion = runtimeMXBean.getSpecVersion(); +- String jvmType = runtimeMXBean.getVmName(); +- res.append(String.format("%s|%s|", jvmVersion, jvmType)); +- +- // gc +- double gcDetail = getGarbageCollectionUsage(runtimeMXBean, operatingSystemMXBean, garbageCollectorMXBeans); +- long gc_counts = getTotalGarbageCollectionCount(garbageCollectorMXBeans); +- long gc_time_ms = getTotalGarbageCollectionTime(garbageCollectorMXBeans); +- res.append(String.format("%.2f|%d|%d|", gcDetail, gc_counts, gc_time_ms)); +- // process & thread +- Long processStartTimeSeconds = runtimeMXBean.getStartTime(); +- Long processCpuSecondsTotal = runtimeMXBean.getUptime(); +- +- int threadsCurrent = threadMXBean.getThreadCount(); +- int threadsPeak = threadMXBean.getPeakThreadCount(); +- int threadsDeadlocked = 0; +- if(threadMXBean.findDeadlockedThreads() != null) { +- threadsDeadlocked = threadMXBean.findDeadlockedThreads().length; +- } +- +- res.append(String.format("%d|%d|%d|%d|%d|", processStartTimeSeconds, processCpuSecondsTotal, threadsCurrent, threadsPeak, threadsDeadlocked)); +- +- // heap +- double heap_occupied = 100.0 * Double.valueOf(memoryMXBean.getHeapMemoryUsage().getCommitted()) / memoryMXBean.getHeapMemoryUsage().getMax(); +- long heap_used = memoryMXBean.getHeapMemoryUsage().getUsed(); +- res.append(String.format("%d|%.2f|", heap_used, heap_occupied)); +- +- // noheap +- long noheap_used = memoryMXBean.getNonHeapMemoryUsage().getUsed(); +- double noheap_occupied = memoryMXBean.getNonHeapMemoryUsage().getMax(); +- if(noheap_occupied > 0) { +- noheap_occupied = 100.0 * Double.valueOf(memoryMXBean.getNonHeapMemoryUsage().getCommitted()) / noheap_occupied; +- res.append(String.format("%d|%.2f|", noheap_used, noheap_occupied)); +- } +- else { +- res.append(String.format("%d|%.0f|", noheap_used,noheap_occupied)); +- } +- // bufferpool +- long bf_capacity = getTotalBufferPoolsCapacity(pools); +- long bf_used = getTotalBufferPoolsUsed(pools); +- res.append(String.format("%d|%d|\n", bf_capacity, bf_used)); +- System.out.printf(res.toString()); +- } +- +- private long getTotalGarbageCollectionCount(List garbageCollectorMXBeans) { +- long gc_count=0; +- for(GarbageCollectorMXBean gc :garbageCollectorMXBeans) { +- gc_count +=gc.getCollectionCount(); +- } +- return gc_count; +- } +- +- private long getTotalGarbageCollectionTime(List gcmList) { +- long total_ms=0; +- for(GarbageCollectorMXBean gc :gcmList) { +- total_ms += gc.getCollectionTime(); +- } +- return total_ms; +- } +- +- private double getGarbageCollectionUsage(RuntimeMXBean runtime, com.sun.management.OperatingSystemMXBean os, List gcmList) { +- // the uptime of the Java virtual machine +- long prevUpTime = runtime.getUptime(); +- // the approximate accumulated collection elapsed time +- long prevProcessGcTime = getTotalGarbageCollectionTime(gcmList); +- // the number of processors available to the Java virtual machine +- int processorCount = os.getAvailableProcessors(); +- try { +- TimeUnit.SECONDS.sleep(1); +- } catch (InterruptedException e) { +- System.out.println(e.getMessage()); +- System.exit(1); +- } +- +- long upTime = runtime.getUptime(); +- long processGcTime = getTotalGarbageCollectionTime(gcmList); +- long upTimeDiff = upTime - prevUpTime; +- long processGcTimeDiff = processGcTime - prevProcessGcTime; +- +- double gcDetail = (processGcTimeDiff * 100.0 / processorCount / upTimeDiff); +- return gcDetail; +- } +- +- private long getTotalBufferPoolsCapacity(List bufferpools) { +- long total_bytes = 0; +- for (BufferPoolMXBean bpool : bufferpools) { +- total_bytes += bpool.getTotalCapacity(); +- } +- return total_bytes; +- } +- +- private long getTotalBufferPoolsUsed(List bufferpools) { +- long total_bytes = 0; +- for (BufferPoolMXBean bpool : bufferpools) { +- total_bytes += bpool.getMemoryUsed(); +- } +- return total_bytes; +- } +- +-} +- +diff --git a/src/probes/extends/java.probe/jvm.probe/src/agent/JvmProbeAgent.java b/src/probes/extends/java.probe/jvm.probe/src/agent/JvmProbeAgent.java +new file mode 100644 +index 0000000..488c73c +--- /dev/null ++++ b/src/probes/extends/java.probe/jvm.probe/src/agent/JvmProbeAgent.java +@@ -0,0 +1,188 @@ ++package agent; ++ ++import java.util.List; ++import java.io.IOException; ++import java.io.BufferedWriter; ++import java.io.File; ++import java.io.FileWriter; ++import java.lang.management.ManagementFactory; ++import com.sun.management.OperatingSystemMXBean; ++import java.lang.management.RuntimeMXBean; ++import java.lang.management.ThreadMXBean; ++import java.lang.management.ClassLoadingMXBean; ++import java.lang.management.MemoryMXBean; ++import java.lang.management.MemoryUsage; ++import java.lang.management.MemoryPoolMXBean; ++import java.lang.management.BufferPoolMXBean; ++import java.lang.management.GarbageCollectorMXBean; ++import java.lang.reflect.Method; ++import java.lang.reflect.InvocationTargetException; ++ ++ ++public class JvmProbeAgent { ++ ++ private static final int MSEC_PER_SEC = 1000; ++ private static final int NSEC_PER_SEC = 1000000; ++ private static final String METRIC_FILE_NAME = "jvm-metrics.txt"; ++ private static String pid; ++ private static String nspid; ++ ++ private static String getMetricFilePath() { ++ String filePath = String.format("/proc/%s/root/tmp/%s", nspid, METRIC_FILE_NAME); ++ return filePath; ++ } ++ ++ private static void writeMetricRecords(String record) { ++ try { ++ File file = new File(getMetricFilePath()); ++ if (!file.exists()) { ++ file.createNewFile(); ++ } ++ FileWriter fw = new FileWriter(file.getAbsoluteFile(), true); ++ BufferedWriter bw = new BufferedWriter(fw); ++ bw.write(record); ++ bw.close(); ++ } catch (IOException e) { ++ e.printStackTrace(); ++ } ++ } ++ ++ private static void getJmxInfo() throws IOException { ++ RuntimeMXBean runtimeBean = ManagementFactory.getRuntimeMXBean(); ++ OperatingSystemMXBean osBean = (OperatingSystemMXBean) ManagementFactory.getOperatingSystemMXBean(); ++ ThreadMXBean threadBean = ManagementFactory.getThreadMXBean(); ++ ClassLoadingMXBean clBean = ManagementFactory.getClassLoadingMXBean(); ++ MemoryMXBean memoryBean = ManagementFactory.getMemoryMXBean(); ++ MemoryUsage heapUsage = memoryBean.getHeapMemoryUsage(); ++ MemoryUsage nonHeapUsage = memoryBean.getNonHeapMemoryUsage(); ++ List memPoolBeans = ManagementFactory.getMemoryPoolMXBeans(); ++ List bufPoolBeans = ManagementFactory.getPlatformMXBeans(BufferPoolMXBean.class); ++ List garbageCollectors = ManagementFactory.getGarbageCollectorMXBeans(); ++ ++ infoCollector(runtimeBean); ++ processCollector(runtimeBean, osBean); ++ classCollector(clBean); ++ threadCollector(threadBean); ++ memoryAreaCollector(heapUsage, "heap"); ++ memoryAreaCollector(nonHeapUsage, "nonheap"); ++ memoryPoolCollector(memPoolBeans); ++ bufferPoolCollector(bufPoolBeans); ++ gcCollector(garbageCollectors); ++ } ++ ++ private static void infoCollector(RuntimeMXBean runtimeBean) { ++ String jvmName = runtimeBean.getVmName(); ++ String jvmVersion = runtimeBean.getVmVersion(); // 原始的为getSpecVersion(); ++ String jvmVender = runtimeBean.getVmVendor(); ++ ++ writeMetricRecords(String.format("|jvm_info|%s|%s|%s|%s|%d|\n", pid, jvmName, jvmVender, jvmVersion, 1)); ++ } ++ ++ private static void processCollector(RuntimeMXBean runtimeBean, OperatingSystemMXBean osBean) { ++ long processStartTime = runtimeBean.getStartTime(); // ms ++ try { ++ Long processCpuTime = callLongGetter(osBean.getClass().getMethod("getProcessCpuTime"), osBean); // ns ++ writeMetricRecords(String.format("|jvm_process|%s|%d|%d|\n", pid, processStartTime, processCpuTime)); ++ } catch (Exception e) { ++ //System.out.println("error"); ++ } ++ } ++ ++ private static Long callLongGetter(Method method, Object obj) throws InvocationTargetException { ++ try { ++ return (Long) method.invoke(obj); ++ } catch (IllegalAccessException e) { ++ // Expected, the declaring class or interface might not be public. ++ } ++ ++ for (Class clazz : method.getDeclaringClass().getInterfaces()) { ++ try { ++ Method interfaceMethod = clazz.getMethod(method.getName(), method.getParameterTypes()); ++ Long result = callLongGetter(interfaceMethod, obj); ++ if (result != null) { ++ return result; ++ } ++ } catch (NoSuchMethodException e) { ++ // Expected, class might implement multiple, unrelated interfaces. ++ } ++ } ++ return null; ++ } ++ ++ // thread ++ private static void threadCollector(ThreadMXBean threadBean) { ++ int currentThreadCnt = threadBean.getThreadCount(); ++ int daemonThreadCnt = threadBean.getDaemonThreadCount(); ++ int peakThreadCnt = threadBean.getPeakThreadCount(); ++ long startThreadCnt = threadBean.getTotalStartedThreadCount(); ++ long cycleThreadDeadlocked = 0; ++ long[] deadlocks = threadBean.findDeadlockedThreads(); ++ if (deadlocks != null && deadlocks.length > 0) { ++ cycleThreadDeadlocked = deadlocks.length; ++ } ++ writeMetricRecords(String.format("|jvm_thread|%s|%d|%d|%d|%d|%d|\n", ++ pid, currentThreadCnt, daemonThreadCnt, peakThreadCnt, startThreadCnt, cycleThreadDeadlocked)); ++ } ++ ++ private static void classCollector(ClassLoadingMXBean clBean) { ++ int currentClassCnt = clBean.getLoadedClassCount(); ++ long totalClassCnt = clBean.getTotalLoadedClassCount(); ++ writeMetricRecords(String.format("|jvm_class|%s|%d|%d|\n", pid, currentClassCnt, totalClassCnt)); ++ } ++ ++ // memory ++ private static void memoryAreaCollector(MemoryUsage memUsage, String area) { ++ long memUsed = memUsage.getUsed(); ++ long memCommitted = memUsage.getCommitted(); ++ long memMax = memUsage.getMax(); ++ long memInit = memUsage.getInit(); ++ writeMetricRecords(String.format("|jvm_mem|%s|%s|%d|%d|%d|%d|\n", pid, area, memUsed, memCommitted, memMax, memInit)); ++ } ++ ++ // memory_pool ++ private static void memoryPoolCollector(List poolBeans) { ++ for (final MemoryPoolMXBean pool : poolBeans) { ++ MemoryUsage poolUsage = pool.getUsage(); ++ if (poolUsage != null) { ++ writeMetricRecords(String.format("|jvm_mem_pool|%s|%s|%d|%d|%d|", ++ pid, pool.getName(), poolUsage.getUsed(), poolUsage.getCommitted(), poolUsage.getMax())); ++ } ++ MemoryUsage colPoolUsage = pool.getCollectionUsage(); ++ if (colPoolUsage != null) { ++ writeMetricRecords(String.format("%d|%d|%d|", ++ colPoolUsage.getUsed(), colPoolUsage.getCommitted(), colPoolUsage.getMax())); ++ } else { ++ writeMetricRecords(String.format("-1|-1|-1|")); ++ } ++ writeMetricRecords(String.format("\n")); ++ } ++ } ++ ++ // buffer_pool ++ private static void bufferPoolCollector(List bufferPools) { ++ for (BufferPoolMXBean pool : bufferPools) { ++ writeMetricRecords(String.format("|jvm_buf_pool|%s|%s|%d|%d|%d|\n", ++ pid, pool.getName(), pool.getMemoryUsed(), pool.getCount(), pool.getTotalCapacity())); ++ } ++ } ++ ++ // gc ++ private static void gcCollector(List garbageCollectors) { ++ for (GarbageCollectorMXBean gc : garbageCollectors) { ++ writeMetricRecords(String.format("|jvm_gc|%s|%s|%d|%d|\n", ++ pid, gc.getName(), gc.getCollectionCount(), gc.getCollectionTime())); // ms ++ } ++ } ++ ++ ++ public static void agentmain(String agentArgs) { ++ String[] argStr = agentArgs.split("[,]"); ++ pid = argStr[0]; ++ nspid = argStr[1]; ++ try { ++ getJmxInfo(); ++ } catch (IOException e) { ++ System.out.println(e.getMessage()); ++ } ++ } ++} +diff --git a/src/probes/extends/java.probe/jvm.probe/src/agent/config/META-INF/MANIFEST.MF b/src/probes/extends/java.probe/jvm.probe/src/agent/config/META-INF/MANIFEST.MF +new file mode 100644 +index 0000000..2d6f14f +--- /dev/null ++++ b/src/probes/extends/java.probe/jvm.probe/src/agent/config/META-INF/MANIFEST.MF +@@ -0,0 +1,6 @@ ++Manifest-Version: 1.0 ++Created-By: 1.8.0_272 (Oracle Corporation) ++Agent-Class: agent.JvmProbeAgent ++Can-Retransform-Classes: true ++Can-Redefine-Classes: true ++ +-- +2.33.0 + diff --git a/stackprobe-fix-inaccurate-call-stack-count.-add-samp.patch b/stackprobe-fix-inaccurate-call-stack-count.-add-samp.patch new file mode 100644 index 0000000..fd607f9 --- /dev/null +++ b/stackprobe-fix-inaccurate-call-stack-count.-add-samp.patch @@ -0,0 +1,668 @@ +From f084483fae4e051b872a4bc812ffa3dc73039c76 Mon Sep 17 00:00:00 2001 +From: wo_cow +Date: Fri, 31 Mar 2023 19:07:09 +0800 +Subject: [PATCH 29/30] stackprobe: fix inaccurate call stack count. add + sample_perioud param + +--- + .../src/stackprobe/conf/stackprobe.conf | 1 + + .../src/stackprobe/conf/stackprobe_conf.h | 3 + + .../src/stackprobe/conf/stackprobe_config.c | 11 ++ + .../ebpf.probe/src/stackprobe/flame_graph.c | 77 +------- + .../ebpf.probe/src/stackprobe/flame_graph.h | 5 +- + .../ebpf.probe/src/stackprobe/java_support.c | 2 +- + .../src/stackprobe/jvmti/jvm_agent.c | 2 +- + .../extends/ebpf.probe/src/stackprobe/stack.h | 3 +- + .../src/stackprobe/stack_bpf/stackprobe_bpf.h | 4 +- + .../ebpf.probe/src/stackprobe/stackprobe.c | 177 +++++++++++++----- + .../ebpf.probe/src/stackprobe/stackprobe.h | 2 + + .../extends/ebpf.probe/src/stackprobe/svg.h | 9 + + .../ebpf.probe/src/stackprobe/symbol.c | 1 - + 13 files changed, 175 insertions(+), 122 deletions(-) + +diff --git a/src/probes/extends/ebpf.probe/src/stackprobe/conf/stackprobe.conf b/src/probes/extends/ebpf.probe/src/stackprobe/conf/stackprobe.conf +index 0b3d0ac..4d50eb2 100644 +--- a/src/probes/extends/ebpf.probe/src/stackprobe/conf/stackprobe.conf ++++ b/src/probes/extends/ebpf.probe/src/stackprobe/conf/stackprobe.conf +@@ -2,6 +2,7 @@ general = + { + whitelist_enable = false; + period = 180; # unit is second ++ sample_period = 10; # unit is ms + log_dir = "/var/log/gala-gopher/stacktrace/logs"; + svg_dir = "/var/log/gala-gopher/stacktrace"; + flame_dir = "/var/log/gala-gopher/flamegraph"; +diff --git a/src/probes/extends/ebpf.probe/src/stackprobe/conf/stackprobe_conf.h b/src/probes/extends/ebpf.probe/src/stackprobe/conf/stackprobe_conf.h +index d872b4d..a1b9913 100644 +--- a/src/probes/extends/ebpf.probe/src/stackprobe/conf/stackprobe_conf.h ++++ b/src/probes/extends/ebpf.probe/src/stackprobe/conf/stackprobe_conf.h +@@ -23,6 +23,8 @@ + #define PROC_MAX_RANGE 64 + #define PERIOD_MAX 600 + #define PERIOD_MIN 30 ++#define SAMPLE_PERIOD_MAX 1000 ++#define SAMPLE_PERIOD_MIN 10 + + typedef enum { + SWITCH_ON = 0, +@@ -31,6 +33,7 @@ typedef enum { + + typedef struct { + int period; ++ int samplePeriod; + char logDir[PATH_LEN]; + char svgDir[PATH_LEN]; + char flameDir[PATH_LEN]; +diff --git a/src/probes/extends/ebpf.probe/src/stackprobe/conf/stackprobe_config.c b/src/probes/extends/ebpf.probe/src/stackprobe/conf/stackprobe_config.c +index 282cbbd..ed6ae19 100644 +--- a/src/probes/extends/ebpf.probe/src/stackprobe/conf/stackprobe_config.c ++++ b/src/probes/extends/ebpf.probe/src/stackprobe/conf/stackprobe_config.c +@@ -184,6 +184,17 @@ static int configLoadGeneral(void *config, config_setting_t *settings) + } + generalConfig->period = intVal; + ++ ret = config_setting_lookup_int(settings, "sample_period", &intVal); ++ if (ret == 0) { ++ ERROR("[STACKPROBE]: load config for general sample_period failed.\n"); ++ return -1; ++ } ++ if (intVal < SAMPLE_PERIOD_MIN || intVal > SAMPLE_PERIOD_MAX) { ++ ERROR("[STACKPROBE]: Please check config for general sample_period, val shold inside 10~1000.\n"); ++ return -1; ++ } ++ generalConfig->samplePeriod = intVal; ++ + ret = config_setting_lookup_string(settings, "log_dir", &strVal); + if (ret == 0) { + ERROR("[STACKPROBE]: load config for general log_dir failed.\n"); +diff --git a/src/probes/extends/ebpf.probe/src/stackprobe/flame_graph.c b/src/probes/extends/ebpf.probe/src/stackprobe/flame_graph.c +index fd03699..cb70ec0 100644 +--- a/src/probes/extends/ebpf.probe/src/stackprobe/flame_graph.c ++++ b/src/probes/extends/ebpf.probe/src/stackprobe/flame_graph.c +@@ -25,7 +25,6 @@ + #include + #include + #include +-#include + + #ifdef BPF_PROG_KERN + #undef BPF_PROG_KERN +@@ -38,16 +37,7 @@ + #include "bpf.h" + #include "flame_graph.h" + +-#define POST_MAX_STEP_SIZE 1048576 // 1M +-static int g_post_max = POST_MAX_STEP_SIZE; +- +-struct post_info_s { +- int post_flag; +- int remain_size; +- char *buf_start; +- char *buf; +- CURL *curl; +-}; ++extern int g_post_max; + + struct MemoryStruct { + char *memory; +@@ -108,13 +98,6 @@ static FILE *__open_flame_graph_fp(struct stack_svg_mng_s *svg_mng) + return sfg->fp; + } + +-static FILE *__get_flame_graph_fp(struct stack_svg_mng_s *svg_mng) +-{ +- struct stack_flamegraph_s *sfg; +- +- sfg = &(svg_mng->flame_graph); +- return sfg->fp; +-} + + static void __mkdir_flame_graph_path(struct stack_svg_mng_s *svg_mng) + { +@@ -192,51 +175,7 @@ static void __reopen_flame_graph_file(struct stack_svg_mng_s *svg_mng) + __set_flame_graph_flags(svg_mng, FLAME_GRAPH_NEW); + } + +-#define HISTO_TMP_LEN (2 * STACK_SYMBS_LEN) +-static char __histo_tmp_str[HISTO_TMP_LEN]; +- +-static int __do_wr_stack_histo(struct stack_svg_mng_s *svg_mng, +- struct stack_trace_histo_s *stack_trace_histo, int first, struct post_info_s *post_info) +-{ +- FILE *fp = __get_flame_graph_fp(svg_mng); +- if (!fp) { +- ERROR("[FLAMEGRAPH]: Invalid fp.\n"); +- return -1; +- } + +- __histo_tmp_str[0] = 0; +- +- if (first) { +- (void)snprintf(__histo_tmp_str, HISTO_TMP_LEN, "%s %llu", +- stack_trace_histo->stack_symbs_str, stack_trace_histo->count); +- } else { +- (void)snprintf(__histo_tmp_str, HISTO_TMP_LEN, "\n%s %llu", +- stack_trace_histo->stack_symbs_str, stack_trace_histo->count); +- } +- +- if (post_info->post_flag) { +- int written = post_info->buf - post_info->buf_start; +- int ret = __snprintf(&post_info->buf, post_info->remain_size, &post_info->remain_size, "%s", __histo_tmp_str); +- if (ret < 0) { +- int new_post_max = g_post_max + POST_MAX_STEP_SIZE; +- char *temp = (char *)realloc(post_info->buf_start, new_post_max); +- if(temp == NULL) { +- ERROR("[FLAMEGRAPH]: Not enough post memory (realloc failed), current capacity is %d.\n", +- g_post_max); +- } else { +- post_info->buf_start = temp; +- post_info->buf = post_info->buf_start + written; +- post_info->remain_size += POST_MAX_STEP_SIZE; +- g_post_max = new_post_max; +- INFO("[FLAMEGRAPH]: post memory realloc to %d\n", g_post_max); +- (void)__snprintf(&post_info->buf, post_info->remain_size, &post_info->remain_size, "%s", __histo_tmp_str); +- } +- } +- } +- +- (void)fputs(__histo_tmp_str, fp); +- return 0; +-} + + static size_t __write_memory_cb(void *contents, size_t size, size_t nmemb, void *userp) + { +@@ -362,8 +301,7 @@ static void __init_curl_handle(struct post_server_s *post_server, struct post_in + } + } + +-static void __do_wr_flamegraph(struct stack_svg_mng_s *svg_mng, struct stack_trace_histo_s *head, +- struct post_server_s *post_server, int en_type) ++static void __do_wr_flamegraph(struct stack_svg_mng_s *svg_mng, struct post_server_s *post_server, int en_type) + { + int first_flag = 0; + struct post_info_s post_info = {.remain_size = g_post_max, .post_flag = 0}; +@@ -374,11 +312,8 @@ static void __do_wr_flamegraph(struct stack_svg_mng_s *svg_mng, struct stack_tra + + __init_curl_handle(post_server, &post_info); + +- struct stack_trace_histo_s *item, *tmp; +- H_ITER(head, item, tmp) { +- (void)__do_wr_stack_histo(svg_mng, item, first_flag, &post_info); +- first_flag = 0; +- } ++ iter_histo_tbl(svg_mng, en_type, &first_flag, &post_info); ++ + if (post_info.post_flag) { + __curl_post(post_server, &post_info, en_type); + } +@@ -389,10 +324,10 @@ static void __do_wr_flamegraph(struct stack_svg_mng_s *svg_mng, struct stack_tra + + #endif + +-void wr_flamegraph(struct stack_svg_mng_s *svg_mng, struct stack_trace_histo_s *head, int en_type, ++void wr_flamegraph(struct stack_svg_mng_s *svg_mng, int en_type, + struct post_server_s *post_server) + { +- __do_wr_flamegraph(svg_mng, head, post_server, en_type); ++ __do_wr_flamegraph(svg_mng, post_server, en_type); + + if (is_svg_tmout(svg_mng)) { + (void)create_svg_file(svg_mng, +diff --git a/src/probes/extends/ebpf.probe/src/stackprobe/flame_graph.h b/src/probes/extends/ebpf.probe/src/stackprobe/flame_graph.h +index ea29107..d596328 100644 +--- a/src/probes/extends/ebpf.probe/src/stackprobe/flame_graph.h ++++ b/src/probes/extends/ebpf.probe/src/stackprobe/flame_graph.h +@@ -20,8 +20,9 @@ + #include "svg.h" + #include "stackprobe.h" + +-void wr_flamegraph(struct stack_svg_mng_s *svg_mng, struct stack_trace_histo_s *head, int en_type, +- struct post_server_s *post_server); ++int do_wr_stack_histo(struct stack_svg_mng_s *svg_mng, ++ struct stack_trace_histo_s *stack_trace_histo, int first, struct post_info_s *post_info); ++void wr_flamegraph(struct stack_svg_mng_s *svg_mng, int en_type, struct post_server_s *post_server); + int set_flame_graph_path(struct stack_svg_mng_s *svg_mng, const char* path, const char *flame_name); + int set_post_server(struct post_server_s *post_server, const char *pyroscopeServer); + void clean_post_server(); +diff --git a/src/probes/extends/ebpf.probe/src/stackprobe/java_support.c b/src/probes/extends/ebpf.probe/src/stackprobe/java_support.c +index 48b4386..e7088fb 100644 +--- a/src/probes/extends/ebpf.probe/src/stackprobe/java_support.c ++++ b/src/probes/extends/ebpf.probe/src/stackprobe/java_support.c +@@ -63,7 +63,7 @@ static struct jvm_agent_hash_t *jvm_agent_head = NULL; + #define FIND_JAVA_PROC_COMM "ps -e -o pid,comm | grep java | awk '{print $1}'" + #define PROC_COMM "/usr/bin/cat /proc/%u/comm 2> /dev/null" + #define ATTACH_BIN_PATH "/opt/gala-gopher/extend_probes/jvm_attach" +-#define ATTACH_CMD "%s %u %u load %s true %s" // jvm_attach load /tmp/jvm_agent.so true /tmp/java-symbolization-123 ++#define ATTACH_CMD "%s %u %u load %s true %s" // jvm_attach load /tmp/jvm_agent.so true /tmp/java-sym-123 + #define HOST_SO_DIR "/opt/gala-gopher/extend_probes" + #define AGENT_SO_FILE "jvm_agent.so" + #define HOST_JAVA_SYM_PATH "/proc/%u/root/tmp/java-sym-%u/%s" // /proc//root/tmp/java-sym-/java-symbols.bin +diff --git a/src/probes/extends/ebpf.probe/src/stackprobe/jvmti/jvm_agent.c b/src/probes/extends/ebpf.probe/src/stackprobe/jvmti/jvm_agent.c +index 21b1780..f8450ac 100644 +--- a/src/probes/extends/ebpf.probe/src/stackprobe/jvmti/jvm_agent.c ++++ b/src/probes/extends/ebpf.probe/src/stackprobe/jvmti/jvm_agent.c +@@ -103,7 +103,7 @@ void get_class_name_from_csig(char *dest, size_t dest_size, const char *sig) { + for(i = 0; i < (dest_size - 1) && src[i]; i++) { + char c = src[i]; + if (c == '/') c = '.'; +- if (c == ';') break; ++ if (c == ';' || c == '$') break; + dest[i] = c; + } + dest[i] = 0; +diff --git a/src/probes/extends/ebpf.probe/src/stackprobe/stack.h b/src/probes/extends/ebpf.probe/src/stackprobe/stack.h +index 82fda3f..5b6f7e3 100644 +--- a/src/probes/extends/ebpf.probe/src/stackprobe/stack.h ++++ b/src/probes/extends/ebpf.probe/src/stackprobe/stack.h +@@ -20,12 +20,11 @@ + #include "common.h" + + #define AGGRE_PERIOD (1 * 30 * 1000) // 30s +-#define SAMPLE_PERIOD (10) // 10ms + #define TMOUT_PERIOD (AGGRE_PERIOD / 1000) // Second as unit + #define PROC_CACHE_MAX_COUNT 100 // Cache 100 proc symbols + #define DIV_ROUND_UP(NUM, DEN) ((NUM + DEN - 1) / DEN) + +-#define PERCPU_SAMPLE_COUNT (2 * DIV_ROUND_UP(AGGRE_PERIOD, SAMPLE_PERIOD)) ++#define MAX_PERCPU_SAMPLE_COUNT (2 * DIV_ROUND_UP(AGGRE_PERIOD, 10)) // samplePeriod as 10ms + + struct convert_data_t { + u32 whitelist_enable; +diff --git a/src/probes/extends/ebpf.probe/src/stackprobe/stack_bpf/stackprobe_bpf.h b/src/probes/extends/ebpf.probe/src/stackprobe/stack_bpf/stackprobe_bpf.h +index 5626bd5..1ab3b13 100644 +--- a/src/probes/extends/ebpf.probe/src/stackprobe/stack_bpf/stackprobe_bpf.h ++++ b/src/probes/extends/ebpf.probe/src/stackprobe/stack_bpf/stackprobe_bpf.h +@@ -54,7 +54,7 @@ struct { + __uint(type, BPF_MAP_TYPE_STACK_TRACE); + __uint(key_size, sizeof(u32)); + __uint(value_size, PERF_MAX_STACK_DEPTH * sizeof(u64)); +- __uint(max_entries, PERCPU_SAMPLE_COUNT); ++ __uint(max_entries, MAX_PERCPU_SAMPLE_COUNT); + } stackmap_a SEC(".maps"); + + +@@ -63,7 +63,7 @@ struct { + __uint(type, BPF_MAP_TYPE_STACK_TRACE); + __uint(key_size, sizeof(u32)); + __uint(value_size, PERF_MAX_STACK_DEPTH * sizeof(u64)); +- __uint(max_entries, PERCPU_SAMPLE_COUNT); ++ __uint(max_entries, MAX_PERCPU_SAMPLE_COUNT); + } stackmap_b SEC(".maps"); + + +diff --git a/src/probes/extends/ebpf.probe/src/stackprobe/stackprobe.c b/src/probes/extends/ebpf.probe/src/stackprobe/stackprobe.c +index eafe5ad..dcc26c7 100644 +--- a/src/probes/extends/ebpf.probe/src/stackprobe/stackprobe.c ++++ b/src/probes/extends/ebpf.probe/src/stackprobe/stackprobe.c +@@ -64,6 +64,8 @@ + #define IS_IEG_ADDR(addr) ((addr) != 0xcccccccccccccccc && (addr) != 0xffffffffffffffff) + + #define MEMLEAK_SEC_NUM 4 ++#define HISTO_TMP_LEN (2 * STACK_SYMBS_LEN) ++#define POST_MAX_STEP_SIZE 1048576 // 1M + + #define BPF_GET_MAP_FD(obj, map_name) \ + ({ \ +@@ -85,7 +87,7 @@ + __ret; \ + }) + +-typedef int (*AttachFunc)(struct svg_stack_trace_s *svg_st); ++typedef int (*AttachFunc)(struct svg_stack_trace_s *svg_st, StackprobeConfig *conf); + typedef int (*PerfProcessFunc)(void *ctx, int cpu, void *data, u32 size); + + enum pid_state_t { +@@ -116,6 +118,9 @@ struct bpf_link_hash_t { + struct bpf_link_hash_value v; // value + }; + ++ ++static char __histo_tmp_str[HISTO_TMP_LEN]; ++int g_post_max = POST_MAX_STEP_SIZE; + static struct probe_params params = {.period = DEFAULT_PERIOD}; + static volatile sig_atomic_t g_stop; + static struct stack_trace_s *g_st = NULL; +@@ -198,12 +203,10 @@ static void destroy_proc_cache_tbl(struct stack_trace_s *st) + return; + } + +- struct proc_cache_s *proc_hash_tbl = st->proc_cache; + struct proc_cache_s *item, *tmp; +- +- H_ITER(proc_hash_tbl, item, tmp) { ++ H_ITER(st->proc_cache, item, tmp) { + __destroy_proc_cache(item); +- H_DEL(proc_hash_tbl, item); ++ H_DEL(st->proc_cache, item); + (void)free(item); + } + st->proc_cache = NULL; +@@ -322,7 +325,7 @@ static struct raw_stack_trace_s *create_raw_stack_trace(struct stack_trace_s *st + { + struct raw_stack_trace_s *raw_stack_trace; + +- size_t stack_size = st->cpus_num * PERCPU_SAMPLE_COUNT; ++ size_t stack_size = st->cpus_num * MAX_PERCPU_SAMPLE_COUNT; + size_t mem_size = sizeof(struct raw_stack_trace_s); + mem_size += (stack_size * sizeof(struct raw_trace_s)); + +@@ -353,9 +356,19 @@ static int add_raw_stack_id(struct raw_stack_trace_s *raw_st, struct raw_trace_s + + #endif + ++#define STACK_LAYER_ELSE 0 ++#define STACK_LAYER_1ST 1 ++#define STACK_LAYER_2ND 2 // only for Java ++#define STACK_LAYER_3RD 3 // only for Java ++ ++// For deep call stacks (especially prone to Java programs), it is easy to sample incomplete call stacks. ++// If the function name at the first layer of the call stack contains ".", ++// it means that this is must be an incomplete call stack. ++// We query whether the first two layers of this call stack are contained in other call stacks (eg. A), ++// and then count this call on the A call stack. + #if 1 + static int __stack_addrsymbs2string(struct proc_symbs_s *proc_symbs, struct addr_symb_s *addr_symb, +- int first, char *p, int size) ++ int *layer, char *p, int size) + { + int ret; + char *symb; +@@ -366,21 +379,33 @@ static int __stack_addrsymbs2string(struct proc_symbs_s *proc_symbs, struct addr + char *cur_p = p; + int len = size; + +-#if 1 +- symb = addr_symb->sym ?: addr_symb->mod; +- if (first) { +- if (proc_symbs->pod[0] != 0) { +- ret = __snprintf(&cur_p, len, &len, "[Pod]%s; ", proc_symbs->pod); +- } +- if (proc_symbs->container_name[0] != 0) { +- ret = __snprintf(&cur_p, len, &len, "[Con]%s; ", proc_symbs->container_name); ++ if (addr_symb->sym == NULL) { ++ return 0; ++ } ++ symb = addr_symb->sym; ++ ++ if (*layer == STACK_LAYER_1ST) { ++ if (strstr(symb, ".") != NULL) { ++ ret = __snprintf(&cur_p, len, &len, "; %s", symb); ++ *layer = STACK_LAYER_2ND; ++ } else { ++ if (proc_symbs->pod[0] != 0) { ++ ret = __snprintf(&cur_p, len, &len, "[Pod]%s; ", proc_symbs->pod); ++ } ++ if (proc_symbs->container_name[0] != 0) { ++ ret = __snprintf(&cur_p, len, &len, "[Con]%s; ", proc_symbs->container_name); ++ } ++ ret = __snprintf(&cur_p, len, &len, "[%d]%s; %s", proc_symbs->proc_id, proc_symbs->comm, symb); ++ *layer = STACK_LAYER_ELSE; + } +- ret = __snprintf(&cur_p, len, &len, "[%d]%s; %s", proc_symbs->proc_id, proc_symbs->comm, symb); ++ } else if (*layer == STACK_LAYER_2ND) { ++ ret = __snprintf(&cur_p, len, &len, "; %s", symb); ++ *layer = STACK_LAYER_3RD; + } else { + ret = __snprintf(&cur_p, len, &len, "; %s", symb); ++ *layer = STACK_LAYER_ELSE; + } + +-#endif + if (ret < 0) { + return -1; + } +@@ -391,7 +416,7 @@ static int __stack_symbs2string(struct stack_symbs_s *stack_symbs, struct proc_s + char symbos_str[], size_t size) + { + int len; +- int first_flag = 1; ++ int layer = STACK_LAYER_1ST; + int remain_len = size; + char *pos = symbos_str; + struct addr_symb_s *addr_symb; +@@ -399,28 +424,19 @@ static int __stack_symbs2string(struct stack_symbs_s *stack_symbs, struct proc_s + for (int i = 0; i < PERF_MAX_STACK_DEPTH; i++) { + addr_symb = &(stack_symbs->user_stack_symbs[i]); + if (addr_symb->orign_addr != 0) { +- len = __stack_addrsymbs2string(proc_symbs, addr_symb, first_flag, pos, remain_len); +- if (len < 0) { ++ len = __stack_addrsymbs2string(proc_symbs, addr_symb, &layer, pos, remain_len); ++ if (layer == STACK_LAYER_3RD) { + return -1; + } +- remain_len -= len; +- pos += len; +- first_flag = 0; +- } +- } +- +- for (int i = 0; i < PERF_MAX_STACK_DEPTH; i++) { +- addr_symb = &(stack_symbs->kern_stack_symbs[i]); +- if (addr_symb->orign_addr != 0) { +- len = __stack_addrsymbs2string(proc_symbs, addr_symb, first_flag, pos, remain_len); + if (len < 0) { + return -1; + } + remain_len -= len; + pos += len; +- first_flag = 0; + } + } ++ ++ symbos_str[size - 1] = 0; + return 0; + } + +@@ -428,7 +444,8 @@ static int add_stack_histo(struct stack_trace_s *st, struct stack_symbs_s *stack + struct proc_symbs_s *proc_symbs, enum stack_svg_type_e en_type, s64 count) + { + char str[STACK_SYMBS_LEN]; +- struct stack_trace_histo_s *item = NULL, *new_item; ++ struct stack_trace_histo_s *item = NULL, *new_item = NULL; ++ struct stack_trace_histo_s *tmp; + + str[0] = 0; + if (__stack_symbs2string(stack_symbs, proc_symbs, str, STACK_SYMBS_LEN)) { +@@ -448,6 +465,20 @@ static int add_stack_histo(struct stack_trace_s *st, struct stack_symbs_s *stack + return 0; + } + ++ // Java incomplete call stack merge ++ if (str[0] == ';') { ++ char tmp_str[__FUNC_NAME_LEN] = {0}; ++ (void)snprintf(tmp_str, __FUNC_NAME_LEN, "[%d]", proc_symbs->proc_id); ++ H_ITER(st->svg_stack_traces[en_type]->histo_tbl, item, tmp) { ++ if (strstr(item->stack_symbs_str, tmp_str) && strstr(item->stack_symbs_str, str)) { ++ st->stats.count[STACK_STATS_HISTO_FOLDED]++; ++ item->count = item->count + count; ++ return 0; ++ } ++ } ++ return -1; ++ } ++ + H_FIND_S(st->svg_stack_traces[en_type]->histo_tbl, str, item); + if (item) { + st->stats.count[STACK_STATS_HISTO_FOLDED]++; +@@ -461,6 +492,7 @@ static int add_stack_histo(struct stack_trace_s *st, struct stack_symbs_s *stack + } + new_item->stack_symbs_str[0] = 0; + (void)strncpy(new_item->stack_symbs_str, str, STACK_SYMBS_LEN - 1); ++ new_item->stack_symbs_str[STACK_SYMBS_LEN - 1] = 0; + new_item->count = count < 0 ? 0 : count; + H_ADD_S(st->svg_stack_traces[en_type]->histo_tbl, stack_symbs_str, new_item); + +@@ -473,11 +505,9 @@ static void clear_stack_histo(struct svg_stack_trace_s *svg_st) + return; + } + +- struct stack_trace_histo_s *stack_trace_histo_tbl = svg_st->histo_tbl; + struct stack_trace_histo_s *item, *tmp; +- +- H_ITER(stack_trace_histo_tbl, item, tmp) { +- H_DEL(stack_trace_histo_tbl, item); ++ H_ITER(svg_st->histo_tbl, item, tmp) { ++ H_DEL(svg_st->histo_tbl, item); + (void)free(item); + } + svg_st->histo_tbl = NULL; +@@ -1035,12 +1065,13 @@ err: + return -1; + } + +-static int attach_oncpu_bpf_prog(struct svg_stack_trace_s *svg_st) ++static int attach_oncpu_bpf_prog(struct svg_stack_trace_s *svg_st, StackprobeConfig *conf) + { + int ret; ++ int samplePeriod = conf->generalConfig->samplePeriod; + + struct perf_event_attr attr_type_sw = { +- .sample_freq = SAMPLE_PERIOD, ++ .sample_freq = samplePeriod, // default 10ms + .freq = 1, + .type = PERF_TYPE_SOFTWARE, + .config = PERF_COUNT_SW_CPU_CLOCK, +@@ -1270,7 +1301,7 @@ static void *__uprobe_attach_check(void *arg) + + } + +-static int attach_memleak_bpf_prog(struct svg_stack_trace_s *svg_st) ++static int attach_memleak_bpf_prog(struct svg_stack_trace_s *svg_st, StackprobeConfig *conf) + { + int err; + #if 0 +@@ -1393,6 +1424,66 @@ static void *__running(void *arg) + return NULL; + } + ++static FILE *__get_flame_graph_fp(struct stack_svg_mng_s *svg_mng) ++{ ++ struct stack_flamegraph_s *sfg; ++ ++ sfg = &(svg_mng->flame_graph); ++ return sfg->fp; ++} ++ ++int __do_wr_stack_histo(struct stack_svg_mng_s *svg_mng, ++ struct stack_trace_histo_s *stack_trace_histo, int first, struct post_info_s *post_info) ++{ ++ FILE *fp = __get_flame_graph_fp(svg_mng); ++ if (!fp) { ++ ERROR("[STACKPROBE]: Invalid fp.\n"); ++ return -1; ++ } ++ ++ __histo_tmp_str[0] = 0; ++ ++ if (first) { ++ (void)snprintf(__histo_tmp_str, HISTO_TMP_LEN, "%s %llu", ++ stack_trace_histo->stack_symbs_str, stack_trace_histo->count); ++ } else { ++ (void)snprintf(__histo_tmp_str, HISTO_TMP_LEN, "\n%s %llu", ++ stack_trace_histo->stack_symbs_str, stack_trace_histo->count); ++ } ++ if (post_info->post_flag) { ++ int written = post_info->buf - post_info->buf_start; ++ int ret = __snprintf(&post_info->buf, post_info->remain_size, &post_info->remain_size, "%s", __histo_tmp_str); ++ if (ret < 0) { ++ int new_post_max = g_post_max + POST_MAX_STEP_SIZE; ++ char *temp = (char *)realloc(post_info->buf_start, new_post_max); ++ if(temp == NULL) { ++ ERROR("[STACKPROBE]: Not enough post memory (realloc failed), current capacity is %d.\n", ++ g_post_max); ++ } else { ++ post_info->buf_start = temp; ++ post_info->buf = post_info->buf_start + written; ++ post_info->remain_size += POST_MAX_STEP_SIZE; ++ g_post_max = new_post_max; ++ INFO("[STACKPROBE]: post memory realloc to %d\n", g_post_max); ++ (void)__snprintf(&post_info->buf, post_info->remain_size, &post_info->remain_size, "%s", __histo_tmp_str); ++ } ++ } ++ } ++ ++ (void)fputs(__histo_tmp_str, fp); ++ return 0; ++} ++ ++void iter_histo_tbl(struct stack_svg_mng_s *svg_mng, int en_type, int *first_flag, struct post_info_s *post_info) ++{ ++ struct stack_trace_histo_s *item, *tmp; ++ H_ITER(g_st->svg_stack_traces[en_type]->histo_tbl, item, tmp) { ++ (void)__do_wr_stack_histo(svg_mng, item, *first_flag, post_info); ++ *first_flag = 0; ++ } ++ return; ++} ++ + static void switch_stackmap() + { + struct stack_trace_s *st = g_st; +@@ -1410,8 +1501,10 @@ static void switch_stackmap() + if (st->svg_stack_traces[i] == NULL) { + continue; + } +- (void)stack_id2histogram(st, i, st->is_stackmap_a); +- wr_flamegraph(st->svg_stack_traces[i]->svg_mng, st->svg_stack_traces[i]->histo_tbl, i, &st->post_server); ++ if (stack_id2histogram(st, i, st->is_stackmap_a) != 0) { ++ continue; ++ } ++ wr_flamegraph(st->svg_stack_traces[i]->svg_mng , i, &st->post_server); + clear_raw_stack_trace(st->svg_stack_traces[i], st->is_stackmap_a); + } + record_running_ctx(st); +@@ -1468,7 +1561,7 @@ static int init_enabled_svg_stack_traces(StackprobeConfig *conf) + } + + if (flameProcs[i].func) { +- if (flameProcs[i].func(svg_st)) { ++ if (flameProcs[i].func(svg_st, conf)) { + goto err; + } + } +diff --git a/src/probes/extends/ebpf.probe/src/stackprobe/stackprobe.h b/src/probes/extends/ebpf.probe/src/stackprobe/stackprobe.h +index 2e3cfcc..b09cdba 100644 +--- a/src/probes/extends/ebpf.probe/src/stackprobe/stackprobe.h ++++ b/src/probes/extends/ebpf.probe/src/stackprobe/stackprobe.h +@@ -141,4 +141,6 @@ struct stack_trace_s { + int pmu_fd[]; // It must be put to the last. + }; + ++void iter_histo_tbl(struct stack_svg_mng_s *svg_mng, int en_type, int *first_flag, struct post_info_s *post_info); ++ + #endif +diff --git a/src/probes/extends/ebpf.probe/src/stackprobe/svg.h b/src/probes/extends/ebpf.probe/src/stackprobe/svg.h +index d763e7b..a707342 100644 +--- a/src/probes/extends/ebpf.probe/src/stackprobe/svg.h ++++ b/src/probes/extends/ebpf.probe/src/stackprobe/svg.h +@@ -19,6 +19,15 @@ + + #include + #include "stack.h" ++#include ++ ++struct post_info_s { ++ int post_flag; ++ int remain_size; ++ char *buf_start; ++ char *buf; ++ CURL *curl; ++}; + + #define DAYS_TIME (24 * 60 *60) // 1 DAY + #define WEEKS_TIME (DAYS_TIME * 7) // 1 WEEK +diff --git a/src/probes/extends/ebpf.probe/src/stackprobe/symbol.c b/src/probes/extends/ebpf.probe/src/stackprobe/symbol.c +index 2f7e06b..0c4ffaf 100644 +--- a/src/probes/extends/ebpf.probe/src/stackprobe/symbol.c ++++ b/src/probes/extends/ebpf.probe/src/stackprobe/symbol.c +@@ -1049,7 +1049,6 @@ int proc_search_addr_symb(struct proc_symbs_s *proc_symbs, + } + continue; + } +- + // search debug symbs + ret = search_elf_symb(proc_symbs->mods[i]->debug_symbs, + addr, addr, comm, addr_symb); +-- +2.33.0 + -- Gitee