今天希望同一個程式可以有兩種觀察方式:平常只取得統計,需要追查時才開啟少量事件輸出。
如果每個排程與 syscall 都立即印字,工具本身就會大幅改變我們想看的行為。
所以整合的第一步不是增加更多 log,而是能夠關閉它。
保留前面新增的計數欄位及初始化,但移除以下臨時列印與其呼叫:
obs_created() 與呼叫scheduled++
syscalls++
修改後先重新編譯,避免留下未使用的 static 函式或誤刪必要宣告。
我們不是移除觀察能力,而是把即時輸出從預設路徑拿開。
本次只追蹤 getpid,避免提供一個看似通用卻沒有控制輸出量的追蹤系統。
在 struct proc 新增 int trace_getpid;,並在 allocproc() 初始化為 0。
這個旗標由行程自己透過 syscall 設定,fork 子行程不繼承,exec 則保留,讓 wrapper 能追蹤它接著執行的程式。
在 kernel/syscall.h 新增 #define SYS_trace 25,其餘接線如下:
| 檔案 | 新增內容 |
|---|---|
kernel/syscall.c 宣告區 |
extern uint64 sys_trace(void); |
syscalls[] |
[SYS_trace] = sys_trace, |
user/user.h |
int trace(int); |
user/usys.pl |
entry("trace"); |
在 kernel/sysproc.c 加入:
uint64
sys_trace(void)
{
int enabled;
argint(0, &enabled);
if (enabled != 0 && enabled != 1)
return -1;
myproc()->trace_getpid = enabled;
return 0;
}
在 kernel/syscall.c 原本 handler 呼叫的下一行加入:
if (num == SYS_getpid && p->trace_getpid)
printk("trace pid=%d syscall=getpid result=%lu\n",
p->pid, p->trapframe->a0);
這是 handler 返回後的紀錄,不涵蓋不返回的 exit,也不是全系統 syscall trace。
目前沒有印出任意指標內容或核心位址,避免把觀察工具變成不必要的資料洩漏介面。
新增 user/trace.c,並在 Makefile 的 UPROGS 加入 $U/_trace\:
#include "kernel/types.h"
#include "user/user.h"
int
main(int argc, char **argv)
{
if (argc < 2) {
fprintf(2, "usage: trace command [args...]\n");
exit(1);
}
if (trace(1) < 0)
exit(1);
exec(argv[1], &argv[1]);
trace(0);
fprintf(2, "trace: exec failed\n");
exit(1);
}
在 xv6 checkout 執行 make TOOLPREFIX=riscv64-linux-gnu- CPUS=1 qemu,於 xv6 Shell 依序執行:
pidprobe
trace pidprobe
pstat
第一個只印出返回值,第二個多出 getpid trace,第三個則提供結構化的自身統計。
若普通 pidprobe 仍有 Day 26 的大量階段紀錄,表示臨時 instrumentation 尚未清乾淨。
| 欄位 | 實際意義 | 不能直接解讀成 |
|---|---|---|
scheduled |
scheduler 交給行程的次數 | CPU 使用時間 |
syscalls |
有效 syscall 被分派的次數 | 成功完成的呼叫數 |
sleeps |
實際進入 SLEEPING | sleep 函式呼叫次數 |
wakes |
wakeup 使 SLEEPING 轉成 RUNNABLE | 所有原因的喚醒總數 |
yields |
核心 yield 次數 | 使用者主動讓出 CPU 次數 |
size_bytes |
行程的 sz | RSS 或實體 RAM 用量 |
計數器在行程表格重用時歸零,exec 則保留,因為 exec 替換程式映像,不是建立新的 PID。
若要比較單一工作片段,應對同一 PID 做前後差值,不直接拿生命週期累計值比較。
pstat 需要進入核心,trace 需要輸出,計數更新也會增加指令與鎖的成本。
所以測試時要記錄 trace 是否開啟,不把不同觀察設定下的數字當成等價條件。
這個版本沒有事件 ring buffer、時間戳排序或跨 CPU 原子快照,這些是可以延伸的方向,不是已經完成的功能。
本日新增 trace.c,修改旗標、handler 與 syscall 接線,並清除前面各篇的臨時列印。
day29: integrate process statistics and opt-in syscall tracing
最後一天會把 CPU、等待、記憶體與 syscall 四種行為放進同一個測試程式,用差值檢查 Observer 是否說得出一致的故事。