Skip to content

Commit f4fd4de

Browse files
committed
feat: add eBPF map configuration with unified CompileOptions
1 parent 6d54283 commit f4fd4de

12 files changed

Lines changed: 436 additions & 102 deletions

File tree

config.toml

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,3 +96,26 @@ output_dir = "."
9696
# Default filename prefix for auto-generated realtime log files
9797
# Default: "ghostscope_session"
9898
filename_prefix = "ghostscope_session"
99+
100+
[ebpf]
101+
# RingBuf map size in bytes (must be power of 2)
102+
# This controls the size of the ring buffer used to transfer trace events from kernel to userspace.
103+
# Larger sizes allow more events to be buffered but consume more kernel memory.
104+
# Valid range: 4096 (4KB) to 16777216 (16MB)
105+
# Recommended values:
106+
# - Low-frequency tracing: 131072 (128KB)
107+
# - Medium-frequency tracing: 262144 (256KB)
108+
# - High-frequency tracing: 524288 (512KB) or 1048576 (1MB)
109+
# Default: 262144 (256KB)
110+
ringbuf_size = 262144
111+
112+
# Maximum number of (pid, module) offset entries for ASLR translation
113+
# This map stores the runtime address offsets for each loaded module in each process.
114+
# Each entry stores offsets for text/rodata/data/bss sections.
115+
# Valid range: 64 to 65536
116+
# Recommended values:
117+
# - Single process: 1024
118+
# - Multi-process: 4096
119+
# - System-wide tracing: 8192 or 16384
120+
# Default: 4096
121+
proc_module_offsets_max_entries = 4096

docs/configuration.md

Lines changed: 67 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,27 @@ enabled = true
206206

207207
# Maximum history entries
208208
max_entries = 5000
209+
210+
[ebpf]
211+
# RingBuf map size in bytes (must be power of 2)
212+
# Controls the size of the ring buffer for transferring trace events from kernel to userspace
213+
# Valid range: 4096 (4KB) to 16777216 (16MB)
214+
ringbuf_size = 262144 # 256KB (default)
215+
216+
# Recommended values:
217+
# - Low-frequency tracing: 131072 (128KB)
218+
# - Medium-frequency tracing: 262144 (256KB)
219+
# - High-frequency tracing: 524288 (512KB) or 1048576 (1MB)
220+
221+
# Maximum number of (pid, module) offset entries for ASLR translation
222+
# Stores runtime address offsets for each loaded module in each process
223+
# Valid range: 64 to 65536
224+
proc_module_offsets_max_entries = 4096 # Default
225+
226+
# Recommended values:
227+
# - Single process: 1024
228+
# - Multi-process: 4096
229+
# - System-wide tracing: 8192 or 16384
209230
```
210231

211232
### Configuration Examples
@@ -261,6 +282,40 @@ enabled = true
261282
max_entries = 10000
262283
```
263284

285+
#### High-Frequency Tracing Configuration
286+
287+
```toml
288+
# Optimized for high-frequency event tracing
289+
[ebpf]
290+
ringbuf_size = 1048576 # 1MB buffer for high event rates
291+
proc_module_offsets_max_entries = 8192 # Support many modules
292+
293+
[general]
294+
log_level = "info" # Reduce logging overhead
295+
enable_console_logging = false
296+
```
297+
298+
#### Low-Overhead Configuration
299+
300+
```toml
301+
# Minimal resource usage for production
302+
[ebpf]
303+
ringbuf_size = 131072 # 128KB minimal buffer
304+
proc_module_offsets_max_entries = 1024 # Single process only
305+
306+
[general]
307+
log_level = "error"
308+
enable_logging = false
309+
310+
[files]
311+
[files.save_llvm_ir]
312+
debug = false
313+
release = false
314+
[files.save_ebpf]
315+
debug = false
316+
release = false
317+
```
318+
264319
## Environment Variables
265320

266321
### RUST_LOG
@@ -337,6 +392,9 @@ GhostScope validates configuration at startup:
337392
4. **Panel Ratios**: Ensures all 3 values are positive (non-zero) integers
338393
5. **Log Level**: Validates against allowed values (error, warn, info, debug, trace)
339394
6. **Layout Mode**: Validates against allowed values (Horizontal, Vertical - capitalized)
395+
7. **eBPF Configuration**:
396+
- **ringbuf_size**: Must be power of 2, range 4096-16777216 bytes
397+
- **proc_module_offsets_max_entries**: Must be in range 64-65536
340398

341399
Invalid configuration will produce clear error messages with suggestions for fixes.
342400

@@ -346,11 +404,19 @@ Invalid configuration will produce clear error messages with suggestions for fix
346404
- **"Target file does not exist"**: Specified target path not found. Check the file path.
347405
- **"Script file does not exist"**: Specified script file not found.
348406
- **"Invalid log level"**: Use one of: error, warn, info, debug, trace.
407+
- **"ringbuf_size must be a power of 2"**: Use values like 131072, 262144, 524288, etc.
408+
- **"ringbuf_size X is out of reasonable range"**: Must be between 4KB and 16MB.
409+
- **"proc_module_offsets_max_entries X is out of reasonable range"**: Must be between 64 and 65536.
349410

350411
## Best Practices
351412

352413
1. **Use Configuration Files**: Store common settings in `~/.ghostscope/config.toml`
353414
2. **Environment-Specific Configs**: Keep separate configs for development and production
354415
3. **Log Rotation**: Configure external log rotation for long-running sessions
355416
4. **Debug Output**: Disable debug file saving in production for performance
356-
5. **Panel Layout**: Use horizontal layout for wide screens, vertical for narrow displays
417+
5. **Panel Layout**: Use horizontal layout for wide screens, vertical for narrow displays
418+
6. **eBPF Tuning**:
419+
- Start with default `ringbuf_size` (256KB) and increase if events are dropped
420+
- Monitor kernel memory usage when using large ringbuf sizes
421+
- Use smaller `proc_module_offsets_max_entries` for single-process debugging
422+
- Increase buffer size for high-frequency tracing scenarios

docs/zh/configuration.md

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,27 @@ enabled = true
206206

207207
# 最大历史条目数
208208
max_entries = 5000
209+
210+
[ebpf]
211+
# RingBuf map 大小(字节,必须是 2 的幂)
212+
# 控制从内核向用户空间传输跟踪事件的环形缓冲区大小
213+
# 有效范围:4096 (4KB) 到 16777216 (16MB)
214+
ringbuf_size = 262144 # 256KB(默认)
215+
216+
# 推荐值:
217+
# - 低频跟踪:131072 (128KB)
218+
# - 中频跟踪:262144 (256KB)
219+
# - 高频跟踪:524288 (512KB) 或 1048576 (1MB)
220+
221+
# ASLR 地址转换的 (pid, module) 偏移条目最大数量
222+
# 存储每个进程中每个加载模块的运行时地址偏移
223+
# 有效范围:64 到 65536
224+
proc_module_offsets_max_entries = 4096 # 默认
225+
226+
# 推荐值:
227+
# - 单进程:1024
228+
# - 多进程:4096
229+
# - 系统级跟踪:8192 或 16384
209230
```
210231

211232
### 配置示例
@@ -261,6 +282,40 @@ enabled = true
261282
max_entries = 10000
262283
```
263284

285+
#### 高频跟踪配置
286+
287+
```toml
288+
# 针对高频事件跟踪优化
289+
[ebpf]
290+
ringbuf_size = 1048576 # 1MB 缓冲区用于高事件率
291+
proc_module_offsets_max_entries = 8192 # 支持更多模块
292+
293+
[general]
294+
log_level = "info" # 降低日志开销
295+
enable_console_logging = false
296+
```
297+
298+
#### 低开销配置
299+
300+
```toml
301+
# 生产环境最小资源占用
302+
[ebpf]
303+
ringbuf_size = 131072 # 128KB 最小缓冲区
304+
proc_module_offsets_max_entries = 1024 # 仅单进程
305+
306+
[general]
307+
log_level = "error"
308+
enable_logging = false
309+
310+
[files]
311+
[files.save_llvm_ir]
312+
debug = false
313+
release = false
314+
[files.save_ebpf]
315+
debug = false
316+
release = false
317+
```
318+
264319
## 环境变量
265320

266321
### RUST_LOG
@@ -337,6 +392,9 @@ GhostScope 在启动时验证配置:
337392
4. **面板比例**:确保所有 3 个值都是正(非零)整数
338393
5. **日志级别**:验证是否为允许的值(error, warn, info, debug, trace)
339394
6. **布局模式**:验证是否为允许的值(Horizontal, Vertical - 首字母大写)
395+
7. **eBPF 配置**
396+
- **ringbuf_size**:必须是 2 的幂,范围 4096-16777216 字节
397+
- **proc_module_offsets_max_entries**:必须在 64-65536 范围内
340398

341399
无效配置将产生清晰的错误消息和修复建议。
342400

@@ -346,6 +404,9 @@ GhostScope 在启动时验证配置:
346404
- **"Target file does not exist"**:未找到指定的目标路径。检查文件路径。
347405
- **"Script file does not exist"**:未找到指定的脚本文件。
348406
- **"Invalid log level"**:使用以下之一:error, warn, info, debug, trace。
407+
- **"ringbuf_size must be a power of 2"**:使用 2 的幂值,如 131072、262144、524288 等。
408+
- **"ringbuf_size X is out of reasonable range"**:必须在 4KB 到 16MB 之间。
409+
- **"proc_module_offsets_max_entries X is out of reasonable range"**:必须在 64 到 65536 之间。
349410

350411
## 最佳实践
351412

@@ -354,3 +415,8 @@ GhostScope 在启动时验证配置:
354415
3. **日志轮转**:为长时间运行的会话配置外部日志轮转
355416
4. **调试输出**:在生产环境中禁用调试文件保存以提高性能
356417
5. **面板布局**:宽屏使用水平布局,窄屏使用垂直布局
418+
6. **eBPF 调优**
419+
- 从默认 `ringbuf_size`(256KB)开始,如果事件丢失则增加
420+
- 使用大缓冲区时监控内核内存使用情况
421+
- 单进程调试时使用较小的 `proc_module_offsets_max_entries`
422+
- 高频跟踪场景下增加缓冲区大小

ghostscope-compiler/src/ebpf/context.rs

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -90,14 +90,22 @@ pub struct EbpfContext<'ctx> {
9090

9191
// Per-invocation stack key for proc_module_offsets lookups (allocated in entry block)
9292
pub pm_key_alloca: Option<inkwell::values::PointerValue<'ctx>>, // [3 x i32] alloca
93+
94+
// Compilation options (includes eBPF map configuration)
95+
pub compile_options: crate::CompileOptions,
9396
}
9497

9598
// Temporary alias for backward compatibility during refactoring
9699
pub type NewCodeGen<'ctx> = EbpfContext<'ctx>;
97100

98101
impl<'ctx> EbpfContext<'ctx> {
99102
/// Create a new eBPF code generation context
100-
pub fn new(context: &'ctx Context, module_name: &str, trace_id: Option<u32>) -> Result<Self> {
103+
pub fn new(
104+
context: &'ctx Context,
105+
module_name: &str,
106+
trace_id: Option<u32>,
107+
compile_options: &crate::CompileOptions,
108+
) -> Result<Self> {
101109
let module = context.create_module(module_name);
102110
let builder = context.create_builder();
103111

@@ -177,6 +185,7 @@ impl<'ctx> EbpfContext<'ctx> {
177185
trace_context: ghostscope_protocol::TraceContext::new(),
178186
current_resolved_var_module_path: None,
179187
pm_key_alloca: None,
188+
compile_options: compile_options.clone(),
180189
})
181190
}
182191

@@ -186,8 +195,9 @@ impl<'ctx> EbpfContext<'ctx> {
186195
module_name: &str,
187196
process_analyzer: Option<&mut DwarfAnalyzer>,
188197
trace_id: Option<u32>,
198+
compile_options: &crate::CompileOptions,
189199
) -> Result<Self> {
190-
let mut codegen = Self::new(context, module_name, trace_id)?;
200+
let mut codegen = Self::new(context, module_name, trace_id, compile_options)?;
191201
codegen.process_analyzer = process_analyzer.map(|pa| pa as *const _ as *mut _);
192202
Ok(codegen)
193203
}
@@ -302,13 +312,14 @@ impl<'ctx> EbpfContext<'ctx> {
302312
};
303313

304314
// Create required maps - critical for eBPF loader
315+
// Use configured ringbuf size directly (in bytes)
305316
self.map_manager
306317
.create_ringbuf_map(
307318
&self.module,
308319
&self.di_builder,
309320
&self.compile_unit,
310321
"ringbuf",
311-
8,
322+
self.compile_options.ringbuf_size,
312323
)
313324
.map_err(|e| CodeGenError::LLVMError(format!("Failed to create ringbuf map: {e}")))?;
314325

@@ -319,7 +330,7 @@ impl<'ctx> EbpfContext<'ctx> {
319330
&self.di_builder,
320331
&self.compile_unit,
321332
"proc_module_offsets",
322-
4096,
333+
self.compile_options.proc_module_offsets_max_entries,
323334
)
324335
.map_err(|e| {
325336
CodeGenError::LLVMError(format!("Failed to create proc_module_offsets map: {e}"))

ghostscope-compiler/src/ebpf/maps.rs

Lines changed: 41 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -124,21 +124,42 @@ impl<'ctx> MapManager<'ctx> {
124124
};
125125
let max_entries_u32 = max_entries.min(u32::MAX as u64) as u32;
126126

127-
// Create a simple struct with basic map definition layout
128-
// Use the standard 4-field layout that most eBPF maps use
129-
let elements = vec![
130-
i32_type.into(), // type (map type)
131-
i32_type.into(), // key_size
132-
i32_type.into(), // value_size
133-
i32_type.into(), // max_entries
134-
];
127+
// Create struct with appropriate fields based on map type
128+
// Ringbuf only needs type and max_entries, others need all 4 fields
129+
let (elements, initializer_values): (Vec<_>, Vec<_>) = match map_type {
130+
BpfMapType::Ringbuf => {
131+
// Ringbuf: only type and max_entries
132+
(
133+
vec![
134+
i32_type.into(), // type
135+
i32_type.into(), // max_entries
136+
],
137+
vec![
138+
i32_type.const_int(map_type_id as u64, false).into(),
139+
i32_type.const_int(max_entries_u32 as u64, false).into(),
140+
],
141+
)
142+
}
143+
_ => {
144+
// Other maps: type, key_size, value_size, max_entries
145+
(
146+
vec![
147+
i32_type.into(), // type
148+
i32_type.into(), // key_size
149+
i32_type.into(), // value_size
150+
i32_type.into(), // max_entries
151+
],
152+
vec![
153+
i32_type.const_int(map_type_id as u64, false).into(),
154+
i32_type.const_int(key_size as u64, false).into(),
155+
i32_type.const_int(value_size as u64, false).into(),
156+
i32_type.const_int(max_entries_u32 as u64, false).into(),
157+
],
158+
)
159+
}
160+
};
135161
let struct_type = self.context.struct_type(&elements, false);
136-
let initializer = struct_type.const_named_struct(&[
137-
i32_type.const_int(map_type_id as u64, false).into(),
138-
i32_type.const_int(key_size as u64, false).into(),
139-
i32_type.const_int(value_size as u64, false).into(),
140-
i32_type.const_int(max_entries_u32 as u64, false).into(),
141-
]);
162+
let initializer = struct_type.const_named_struct(&initializer_values);
142163

143164
// Create BTF type information for the map
144165
// This is critical for aya to understand the map structure
@@ -215,15 +236,13 @@ impl<'ctx> MapManager<'ctx> {
215236
di_builder: &DebugInfoBuilder<'ctx>,
216237
compile_unit: &inkwell::debug_info::DICompileUnit<'ctx>,
217238
name: &str,
218-
perf_rb_pages: u64,
239+
ringbuf_size: u64,
219240
) -> Result<()> {
220-
// For ringbuf, max_entries should be power of 2 and reasonable size
221-
// Use 256KB (262144 bytes) which is a common size for eBPF ringbuf
222-
let max_entries = 256 * 1024; // 262144
223-
info!(
224-
"Creating ringbuf map: {} with {} max entries ({} pages)",
225-
name, max_entries, perf_rb_pages
226-
);
241+
// For ringbuf, max_entries is the buffer size in bytes (must be power of 2)
242+
// The parameter name is kept as perf_rb_pages for backward compatibility,
243+
// but we now interpret it directly as the ringbuf size in bytes
244+
let max_entries = ringbuf_size;
245+
info!("Creating ringbuf map: {} with {} bytes", name, max_entries);
227246
self.create_map_definition(
228247
module,
229248
di_builder,

0 commit comments

Comments
 (0)