Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions agent/src/config/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1153,6 +1153,7 @@ pub struct EbpfProfileLanguages {
pub python_disabled: bool,
pub php_disabled: bool,
pub nodejs_disabled: bool,
pub lua_disabled: bool,
}

impl Default for EbpfProfileLanguages {
Expand All @@ -1161,6 +1162,7 @@ impl Default for EbpfProfileLanguages {
python_disabled: false,
php_disabled: false,
nodejs_disabled: false,
lua_disabled: false,
}
}
}
Expand Down
12 changes: 7 additions & 5 deletions agent/src/ebpf/kernel/perf_profiler.bpf.c
Original file line number Diff line number Diff line change
Expand Up @@ -99,15 +99,17 @@ typedef struct {
} stack_t;

/*
* Stack map for interpreter stacks (Python, PHP, V8).
* Stack map for interpreter stacks (Python, PHP, V8, Lua).
* Now uses stack_t to store frame_types and extra_data.
* Due to the limitation of the number of eBPF instruction in kernel, this
* feature is suitable for Linux5.2+
*
* Map sizes are configured in user space program
*/
MAP_HASH(custom_stack_map_a, __u32, stack_t, 1, FEATURE_FLAG_DWARF_UNWINDING)
MAP_HASH(custom_stack_map_b, __u32, stack_t, 1, FEATURE_FLAG_DWARF_UNWINDING)
MAP_HASH(custom_stack_map_a, __u32, stack_t, 1,
FEATURE_FLAG_DWARF_UNWINDING | FEATURE_FLAG_PROFILE_LUA)
MAP_HASH(custom_stack_map_b, __u32, stack_t, 1,
FEATURE_FLAG_DWARF_UNWINDING | FEATURE_FLAG_PROFILE_LUA)

/*
* The following maps are used for DWARF based unwinding
Expand Down Expand Up @@ -312,7 +314,7 @@ MAP_HASH(lua_tstate_map, __u32, struct lua_state_cache_t, LUA_TSTATE_ENTRIES, FE
/* Records which Lua runtime a process uses (key: tgid, value: LANG_* bitmask).
* Memory: LUA_TSTATE_ENTRIES(65536) * (key 4B + value 4B + hash header) -> roughly sub‑MB.
*/
MAP_HASH(lang_flags_map, __u32, __u32, LUA_TSTATE_ENTRIES, FEATURE_FLAG_PROFILE_ONCPU)
MAP_HASH(lua_lang_flags_map, __u32, __u32, LUA_TSTATE_ENTRIES, FEATURE_FLAG_PROFILE_ONCPU)
/* Per-process Lua unwinding metadata (key: tgid, value: lua_unwind_info_t).
* Memory: LUA_TSTATE_ENTRIES(65536) * (key 4B + value 16B + hash header) -> roughly low MB.
*/
Expand Down Expand Up @@ -909,7 +911,7 @@ PERF_EVENT_PROG(oncpu_profile) (struct bpf_perf_event_data * ctx) {
pre_python_unwind(ctx, state, &oncpu_maps, PROG_PYTHON_UNWIND_PE_IDX);
}

__u32 *flags = lang_flags_map__lookup(&key->tgid);
__u32 *flags = lua_lang_flags_map__lookup(&key->tgid);
if (flags && (*flags & (LANG_LUA | LANG_LUAJIT))) {
state->lua_is_jit = (*flags & LANG_LUAJIT) ? 1 : 0;

Expand Down
2 changes: 2 additions & 0 deletions agent/src/ebpf/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,8 @@ pub const FEATURE_PROFILE_PYTHON: c_int = 9;
pub const FEATURE_PROFILE_PHP: c_int = 10;
#[allow(dead_code)]
pub const FEATURE_PROFILE_V8: c_int = 11;
#[allow(dead_code)]
pub const FEATURE_PROFILE_LUA: c_int = 12;

//追踪器当前状态
#[allow(dead_code)]
Expand Down
4 changes: 3 additions & 1 deletion agent/src/ebpf/user/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@
#define PROG_ONCPU_OUTPUT_FOR_PE "df_PE_oncpu_output"

// lua related maps
#define MAP_LUA_LANG_FLAGS_NAME "__lang_flags_map"
#define MAP_LUA_LANG_FLAGS_NAME "__lua_lang_flags_map"
#define MAP_LUA_UNWIND_INFO_NAME "__lua_unwind_info_map"
#define MAP_LUA_OFFSETS_NAME "__lua_offsets_map"
#define MAP_LUAJIT_OFFSETS_NAME "__luajit_offsets_map"
Expand Down Expand Up @@ -170,6 +170,7 @@ enum cfg_feature_idx {
FEATURE_PROFILE_PYTHON,
FEATURE_PROFILE_PHP,
FEATURE_PROFILE_V8,
FEATURE_PROFILE_LUA,
FEATURE_MAX,
};

Expand All @@ -184,6 +185,7 @@ enum cfg_feature_idx {
#define FEATURE_FLAG_PROFILE_PYTHON (1 << FEATURE_PROFILE_PYTHON)
#define FEATURE_FLAG_PROFILE_PHP (1 << FEATURE_PROFILE_PHP)
#define FEATURE_FLAG_PROFILE_V8 (1 << FEATURE_PROFILE_V8)
#define FEATURE_FLAG_PROFILE_LUA (1 << FEATURE_PROFILE_LUA)

#define FEATURE_FLAG_PROFILE (FEATURE_FLAG_PROFILE_ONCPU | FEATURE_FLAG_PROFILE_OFFCPU | FEATURE_FLAG_PROFILE_MEMORY)

Expand Down
6 changes: 5 additions & 1 deletion agent/src/ebpf/user/load.c
Original file line number Diff line number Diff line change
Expand Up @@ -970,6 +970,9 @@ int ebpf_obj_load(struct ebpf_object *obj)
if (!python_profiler_enabled()) {
enabled_feats &= ~FEATURE_FLAG_PROFILE_PYTHON;
}
if (!lua_profiler_enabled()) {
enabled_feats &= ~FEATURE_FLAG_PROFILE_LUA;
}
enabled_feats &= ~extended_feature_flags(map);
if (enabled_feats == 0 &&
map->def.type != BPF_MAP_TYPE_PROG_ARRAY &&
Expand All @@ -991,7 +994,8 @@ int ebpf_obj_load(struct ebpf_object *obj)
}
// Log language profiler map creation with max_entries for verification
if (strstr(map->name, "php_") || strstr(map->name, "v8_") ||
strstr(map->name, "python_")) {
strstr(map->name, "python_") || strstr(map->name, "lua_") ||
strstr(map->name, "luajit_")) {
ebpf_info
("Language profiler map created: name=%s, max_entries=%d (1 means disabled)\n",
map->name, map->def.max_entries);
Expand Down
8 changes: 7 additions & 1 deletion agent/src/ebpf/user/profile/perf_profiler.c
Original file line number Diff line number Diff line change
Expand Up @@ -327,15 +327,21 @@ static int create_profiler(struct bpf_tracer *tracer)
if ((ret = maps_config(tracer, MAP_STACK_B_NAME, cap)))
return ret;

if (get_dwarf_enabled() && (major > 5 || (major == 5 && minor >= 2))) {
bool kernel_supports_custom_stack_maps =
(major > 5 || (major == 5 && minor >= 2));
bool need_custom_stack_maps =
get_dwarf_enabled() || lua_profiler_enabled();
if (kernel_supports_custom_stack_maps && need_custom_stack_maps) {
if ((ret = maps_config(tracer, MAP_CUSTOM_STACK_A_NAME, cap))) {
return ret;
}

if ((ret = maps_config(tracer, MAP_CUSTOM_STACK_B_NAME, cap))) {
return ret;
}
}

if (get_dwarf_enabled() && kernel_supports_custom_stack_maps) {
if ((ret =
maps_config(tracer, MAP_PROCESS_SHARD_LIST_NAME,
get_dwarf_process_map_size()))) {
Expand Down
5 changes: 5 additions & 0 deletions agent/src/ebpf/user/tracer.c
Original file line number Diff line number Diff line change
Expand Up @@ -2018,6 +2018,11 @@ bool python_profiler_enabled(void)
return is_feature_regex_set(FEATURE_PROFILE_PYTHON);
}

bool lua_profiler_enabled(void)
{
return is_feature_regex_set(FEATURE_PROFILE_LUA);
}

static void init_thread_ids(void)
{
thread_ids.entries = NULL;
Expand Down
1 change: 1 addition & 0 deletions agent/src/ebpf/user/tracer.h
Original file line number Diff line number Diff line change
Expand Up @@ -627,6 +627,7 @@ bool is_feature_regex_set(int feature);
bool php_profiler_enabled(void);
bool v8_profiler_enabled(void);
bool python_profiler_enabled(void);
bool lua_profiler_enabled(void);
int bpf_tracer_init(const char *log_file, bool is_stdout);
int tracer_bpf_load(struct bpf_tracer *tracer);
int tracer_probes_init(struct bpf_tracer *tracer);
Expand Down
76 changes: 45 additions & 31 deletions agent/src/ebpf/user/unwind_tracer.c
Original file line number Diff line number Diff line change
Expand Up @@ -307,32 +307,34 @@ int unwind_tracer_init(struct bpf_tracer *tracer) {
pthread_mutex_unlock(&g_v8_unwind_table_lock);
}

int lua_lang_fd = bpf_table_get_fd(tracer, MAP_LUA_LANG_FLAGS_NAME);
int lua_unwind_info_fd = bpf_table_get_fd(tracer, MAP_LUA_UNWIND_INFO_NAME);
int lua_offsets_fd = bpf_table_get_fd(tracer, MAP_LUA_OFFSETS_NAME);
int luajit_offsets_fd = bpf_table_get_fd(tracer, MAP_LUAJIT_OFFSETS_NAME);

if (lua_lang_fd < 0 || lua_unwind_info_fd < 0 || lua_offsets_fd < 0 || luajit_offsets_fd < 0) {
ebpf_warning("Failed to get lua profiling map fds (lang:%d unwind:%d lua_ofs:%d lj_ofs:%d)\n",
lua_lang_fd, lua_unwind_info_fd, lua_offsets_fd, luajit_offsets_fd);
return -1;
}
if (lua_profiler_enabled()) {
int lua_lang_fd = bpf_table_get_fd(tracer, MAP_LUA_LANG_FLAGS_NAME);
int lua_unwind_info_fd = bpf_table_get_fd(tracer, MAP_LUA_UNWIND_INFO_NAME);
int lua_offsets_fd = bpf_table_get_fd(tracer, MAP_LUA_OFFSETS_NAME);
int luajit_offsets_fd = bpf_table_get_fd(tracer, MAP_LUAJIT_OFFSETS_NAME);

if (lua_lang_fd < 0 || lua_unwind_info_fd < 0 || lua_offsets_fd < 0 || luajit_offsets_fd < 0) {
ebpf_warning("Failed to get lua profiling map fds (lang:%d unwind:%d lua_ofs:%d lj_ofs:%d)\n",
lua_lang_fd, lua_unwind_info_fd, lua_offsets_fd, luajit_offsets_fd);
return -1;
}

lua_unwind_table_t *lua_table =
lua_unwind_table_create(lua_lang_fd, lua_unwind_info_fd, lua_offsets_fd, luajit_offsets_fd);
if (lua_table == NULL) {
ebpf_warning("Failed to create lua unwind table\n");
return -1;
}
lua_set_map_fds(lua_lang_fd, lua_unwind_info_fd, lua_offsets_fd, luajit_offsets_fd);
lua_unwind_table_t *lua_table =
lua_unwind_table_create(lua_lang_fd, lua_unwind_info_fd, lua_offsets_fd, luajit_offsets_fd);
if (lua_table == NULL) {
ebpf_warning("Failed to create lua unwind table\n");
return -1;
}
lua_set_map_fds(lua_lang_fd, lua_unwind_info_fd, lua_offsets_fd, luajit_offsets_fd);

pthread_mutex_lock(&g_lua_unwind_table_lock);
g_lua_unwind_table = lua_table;
pthread_mutex_unlock(&g_lua_unwind_table_lock);
pthread_mutex_lock(&g_lua_unwind_table_lock);
g_lua_unwind_table = lua_table;
pthread_mutex_unlock(&g_lua_unwind_table_lock);

if (dwarf_available() && get_dwarf_enabled() && tracer) {
lua_queue_existing_processes(tracer);
}
if (dwarf_available() && tracer) {
lua_queue_existing_processes(tracer);
}
}

return 0;
}
Expand Down Expand Up @@ -422,7 +424,7 @@ static void lua_queue_existing_processes(struct bpf_tracer *tracer)
{
DIR *dir = NULL;
struct dirent *entry = NULL;
if (tracer == NULL || tracer->state != TRACER_RUNNING) {
if (tracer == NULL) {
return;
}

Expand Down Expand Up @@ -529,7 +531,11 @@ void unwind_tracer_drop() {
}

void unwind_process_exec(int pid) {
if (!dwarf_available() || !get_dwarf_enabled()) {
if (!dwarf_available()) {
return;
}

if (!get_dwarf_enabled() && !lua_profiler_enabled()) {
return;
}

Expand All @@ -543,7 +549,11 @@ void unwind_process_exec(int pid) {

// Process events in the queue
void unwind_events_handle(void) {
if (!dwarf_available() || !get_dwarf_enabled()) {
if (!dwarf_available()) {
return;
}

if (!get_dwarf_enabled() && !lua_profiler_enabled()) {
return;
}

Expand All @@ -565,7 +575,7 @@ void unwind_events_handle(void) {
}

tracer = event->tracer;
if (tracer && python_profiler_enabled() && is_python_process(event->pid)) {
if (tracer && get_dwarf_enabled() && python_profiler_enabled() && is_python_process(event->pid)) {
python_unwind_table_load(g_python_unwind_table, event->pid);
pthread_mutex_lock(&tracer->mutex_probes_lock);
python_parse_and_register(event->pid, tracer->tps);
Expand All @@ -574,17 +584,17 @@ void unwind_events_handle(void) {
pthread_mutex_unlock(&tracer->mutex_probes_lock);
}

if (tracer && php_profiler_enabled() && is_php_process(event->pid)) {
if (tracer && get_dwarf_enabled() && php_profiler_enabled() && is_php_process(event->pid)) {
php_unwind_table_load(g_php_unwind_table, event->pid);
// Note: PHP profiling doesn't require uprobe registration like Python
}

if (tracer && v8_profiler_enabled() && is_v8_process(event->pid)) {
if (tracer && get_dwarf_enabled() && v8_profiler_enabled() && is_v8_process(event->pid)) {
v8_unwind_table_load(g_v8_unwind_table, event->pid);
// Note: V8 profiling doesn't require uprobe registration like Python
}

if (tracer && is_lua_process(event->pid)) {
if (tracer && lua_profiler_enabled() && is_lua_process(event->pid)) {
if (g_lua_unwind_table) {
lua_unwind_table_load(g_lua_unwind_table, event->pid);
}
Expand Down Expand Up @@ -612,7 +622,11 @@ void unwind_events_handle(void) {

// Process exit, reclaim resources
void unwind_process_exit(int pid) {
if (!dwarf_available() || !get_dwarf_enabled()) {
if (!dwarf_available()) {
return;
}

if (!get_dwarf_enabled() && !lua_profiler_enabled()) {
return;
}

Expand Down
6 changes: 6 additions & 0 deletions agent/src/ebpf_dispatcher.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1071,6 +1071,12 @@ impl EbpfCollector {
CString::new(".*").unwrap().as_c_str().as_ptr(),
);
}
if !languages.lua_disabled {
ebpf::set_feature_regex(
ebpf::FEATURE_PROFILE_LUA,
CString::new(".*").unwrap().as_c_str().as_ptr(),
);
}

#[cfg(feature = "extended_observability")]
{
Expand Down
72 changes: 70 additions & 2 deletions server/agent_config/README-CH.md
Original file line number Diff line number Diff line change
Expand Up @@ -5026,8 +5026,76 @@ inputs:

**详细描述**:

禁用 Node.js(V8)解释器剖析。禁用后将不采集 Node.js 进程的函数调用栈,
可节省约 6.4 MB 内核内存(v8_unwind_info_map)。
禁用 Node.js (V8 引擎) 剖析功能。禁用后将不会采集 Node.js 进程的函数调用栈,可节省约 6.4 MB 的内核内存。

此配置项控制以下 eBPF map 的创建:
- `v8_unwind_info_map`:存储进程级 unwinding 信息,包括 V8 内部结构偏移量 (~6.4 MB)

适用场景:
- 环境中确定不运行 Node.js 应用
- 仅关注其他语言的性能分析
- 内存受限的环境需要优化资源使用

**重要提示**:修改此配置将自动触发 deepflow-agent 重启,因为 eBPF maps 无法在运行时动态创建或销毁。

##### 禁用 Lua 剖析 {#inputs.ebpf.profile.languages.lua_disabled}

**标签**:

<mark>agent_restart</mark>

**FQCN**:

`inputs.ebpf.profile.languages.lua_disabled`

**默认值**:
```yaml
inputs:
ebpf:
profile:
languages:
lua_disabled: false
```

**模式**:
| Key | Value |
| ---- | ---------------------------- |
| Type | bool |

**详细描述**:

禁用 Lua 解释器剖析功能。禁用后将不会采集 Lua 进程的函数调用栈,可节省约 13 MB 的内核内存。

此配置项控制以下 eBPF maps 的创建:
- `lua_tstate_map`:缓存每线程 lua_State 栈(按线程,容量较大,约 7 MB)
- `lua_lang_flags_map`:记录进程 Lua/LuaJIT 类型标记(约 2.5 MB)
- `lua_unwind_info_map`:存储进程级 unwinding 元信息(约 3 MB)
- `lua_offsets_map`、`luajit_offsets_map`:存储 Lua/LuaJIT 结构偏移表(总计 < 2 KB)

适用场景:
- 环境中确定不运行 Lua/LuaJIT 应用(如 OpenResty/nginx-lua)
- 仅关注其他语言的性能分析
- 内存受限的环境需要优化资源使用

**重要提示**:修改此配置将自动触发 deepflow-agent 重启,因为 eBPF maps 无法在运行时动态创建或销毁。

**内存节省效果总结**:

| 配置方式 | Python | PHP | Node.js | Lua | 总计内存占用 | 节省内存 |
| -------- | ------ | --- | ------- | --- | ----------- | -------- |
| 全部启用(默认) | 6.1 MB | 5.2 MB | 6.4 MB | ~13 MB | ~30-33 MB | 0 MB |
| 仅 Python | 6.1 MB | 0 MB | 0 MB | 0 MB | ~6.1 MB | ~24-27 MB |
| 仅 PHP | 0 MB | 5.2 MB | 0 MB | 0 MB | ~5.2 MB | ~25-28 MB |
| 仅 Node.js | 0 MB | 0 MB | 6.4 MB | 0 MB | ~6.4 MB | ~23-26 MB |
| 仅 Lua | 0 MB | 0 MB | 0 MB | ~13 MB | ~13 MB | ~17-20 MB |
| 全部禁用 | 0 MB | 0 MB | 0 MB | 0 MB | ~0 MB | ~30-33 MB |

**注意事项**:
- 修改语言开关需要重启 deepflow-agent 才能生效
- eBPF maps 使用预分配机制,空载和满载占用相同的内核内存
- 禁用时,对应语言的 eBPF maps 会被创建但 max_entries 设为 1(最小化内存占用)
- 禁用时,不会创建对应语言的 unwind table,也不会加载进程的 unwinding 信息
- 禁用不需要的语言除了节省内存,还能减少 CPU 开销

### 调优 {#inputs.ebpf.tunning}

Expand Down
Loading
Loading