一、calltrace介紹
Calltrace是Linux內核中實現函數調用跟蹤的一種方法。作為Linux內核調試的一項重要工具之一,其主要功能是自動記錄Linux內核中每個函數調用路徑,便於初步定位內核崩潰和性能問題等。
實現原理:當函數A調用函數B時,內核會自動將函數A的地址和函數B的地址記錄在一個緩衝區中,並將緩衝區的指針(虛擬地址)存儲在一個特殊寄存器中。當函數B返回時,這個緩衝區的指針就會被取出,記錄當前函數調用路徑的數據就會被寫入trace內核日誌文件中。
二、調用流程探究
調用流程可以分為三個主要部分:trace日誌輸出驅動、trace日誌記錄與寫入、trace日誌分析工具。
1、trace日誌輸出驅動
trace日誌輸出驅動是負責將trace日誌輸出到用戶空間的核心代碼,該代碼位於drivers/trace目錄下。在啟用CONFIG_TRACEPOINTS和CONFIG_EVENT_TRACING支持的情況下,內核將會編譯該模塊,並在內核啟動時自動載入。
void trace_printk_init(struct trace_array *tr) { tr->trace_printk = __trace_printk; } void trace_printk(void *ignore, const char *fmt, ...) { struct trace_array *tr = get_trace_kern(current); va_list args; if (!tr || !tr->trace_printk) return; va_start(args, fmt); vprintk(fmt, args); va_end(args); }
2、trace日誌記錄與寫入
當trace日誌輸出驅動輸出trace日誌到用戶空間後,trace日誌記錄與寫入模塊將負責將trace日誌記錄到緩衝區並將緩衝區中的數據寫入trace內核日誌文件中。該模塊位於kernel/trace目錄下。
static inline void trace_call_function_enqueue(struct trace_array *tr, unsigned long ip, int depth, int idx) { struct trace_event_call_template *call; unsigned long flags; unsigned long long parent, current, local_ts; parent = local_irq_save(flags); current = tr->trace_buffer.buffer->data[tr->trace_buffer.buffer->data_size - 1]; if (depth >= CALLCHAIN_MAX_DEPTH || current == TRACE_SYSTEM_EVENT) goto out; local_ts = tr->timestamp_fn(tr); call = trace_event_buffer_reserve(&tr->trace_buffer, sizeof(*call), 0, local_ts); if (!call) goto out; call->parent_ip = current; call->ip = ip; call->depth = depth; call->call_idx = idx; trace_event_buffer_commit(&tr->trace_buffer); out: local_irq_restore(flags); }
3、trace日誌分析工具
最後一部分是trace日誌分析工具,在Linux中提供了多種分析trace日誌的工具,包括trace-cmd、perf、ftrace等。其中,trace-cmd是一個比較實用的工具,包含了trace日誌收集、解析和分析等功能,可以較方便地定位系統問題。
三、calltrace使用技巧
1、配置內核選項
首先需要在內核編譯配置中選擇CONFIG_TRACEPOINTS和CONFIG_EVENT_TRACING選項,以及選擇具體的tracepoints模塊。
CONFIG_TRACEPOINTS=y CONFIG_EVENT_TRACING=y # Select a tracepoints module # CONFIG_FTRACE_SYSCALLS is not set # CONFIG_FTRACE_MCOUNT_RECORD is not set CONFIG_FTRACE_LATENCY_TRACKING=y CONFIG_HAVE_DYNAMIC_FTRACE=y CONFIG_DYNAMIC_FTRACE=y
2、開啟calltrace
可以通過sysfs介面來開啟或關閉calltrace。將tracer設置為function_graph,即可開啟calltrace。
echo function_graph > /sys/kernel/debug/tracing/current_tracer
3、查看calltrace日誌
使用trace-cmd工具可以查看calltrace日誌。下面是一個簡單的例子:
# 啟動trace-cmd trace-cmd start # 運行測試程序 ./test_program # 結束跟蹤 trace-cmd stop # 查看trace日誌 trace-cmd report
四、總結
通過對calltrace的介紹和調用流程探究,我們可以了解到calltrace的重要性和使用方法。在Linux內核調試和性能優化中,這是一個不可缺少的工具。同時,我們也需要注意合理使用calltrace以及其他trace日誌工具,以保證系統性能。
原創文章,作者:小藍,如若轉載,請註明出處:https://www.506064.com/zh-tw/n/200752.html