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
45 changes: 45 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

124 changes: 124 additions & 0 deletions docs/harness-os-knowledge-graph.md

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

不要只放一个 .md 文档在 docs 根目录下,根目录下的文档实际没有接入 文档系统,需要在docs/docs下的对应目录中,且确保本地 yarn start 后启动网站后可以正常流量,

Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
# Harness OS 知识图谱功能说明

`tools/starry-syscall-harness` 的 GUI 新增了一个独立的 `Knowledge` 页,用于在处理 StarryOS / ArceOS OS 相关 coding 任务时,自动扫描当前仓库并生成结构化知识图谱。

## 目标

该功能解决两个问题:

1. 新接手任务时,需要快速知道当前代码改动落在 OS 哪个子系统。
2. 写代码或做性能分析时,需要把仓库实践和 OS 课本知识关联起来,便于讲解、复盘和教学报告。

## 启动

```bash
python3 tools/starry-syscall-harness/harness.py ui --host 127.0.0.1 --port 8765
```

浏览器打开:

```text
http://127.0.0.1:8765/
```

进入左侧 `Knowledge` tab。

## 页面能力

`Knowledge` 页面包含:

* 当前开发任务输入框。
* 粗粒度 / 细粒度讲解切换。
* OS 子系统知识图谱 SVG。
* 当前任务焦点节点高亮。
* 节点详情面板。

点击图谱节点后,右侧会显示:

* 子系统职责。
* 相关目录。
* 扫描到的代表文件。
* 扫描到的 Rust 符号。
* OS 课本知识。
* 当前仓库实践关联。

## API

GUI 使用以下本地 API:

```text
GET /api/knowledge-graph?task=<当前任务>&granularity=coarse|fine&refresh=0|1
```

也可以让当前 GUI 扫描相邻的本地教学仓库:

```text
GET /api/knowledge-graph?repo_root=../tg-arceos-tutorial&task=分析教程实验&granularity=fine&refresh=1
```

`repo_root` 为空时扫描当前仓库;非空时必须位于当前仓库或当前仓库的父目录下,且只用于静态扫描,不会通过 artifact API 暴露外部文件。

返回结构包含:

* `graph.nodes`:OS 子系统节点。
* `graph.edges`:子系统依赖边。
* `task.focus_node_ids`:当前任务命中的焦点节点。
* `focus.code_explanation`:代码讲解。
* `focus.os_explanation`:OS 课本知识与实践关联。
* `focus.coding_guidance`:编码建议。

## 扫描方式

当前实现是轻量本地静态扫描,不依赖外部服务:

* 扫描 `os/`、`components/`、`drivers/`、`scripts/`、`tools/`、`test-suit/`、`docs/`。
* 对教学仓库额外扫描 `app-*`、`exercise-*`、根 `README.md`、`report.md`、`Cargo.toml`。
* 跳过 `.git`、`target`、`node_modules`、`__pycache__` 等目录。
* 提取 `.rs`、`.toml`、`.py`、`.md`、`.c`、`.h`、`.json` 文件。
* 根据预定义 OS 子系统目录、关键词、当前任务文本、未提交文件或最近提交文件进行匹配。

当前预置的主要节点包括:

* Linux syscall compatibility
* Task / process lifecycle
* Scheduler / wait / synchronization
* Virtual memory / address space
* Allocator / object lifetime
* VFS / file I/O
* rsext4 / block cache
* Block layer / request queue
* virtio-blk driver
* Network stack / socket path
* virtio-net driver
* virtio-vsock / vhost-vsock
* PCI / interrupt / transport
* procfs / debug observability
* qperf / harness / GUI
* Build / rootfs / qemu tests

## 粗/细粒度

`coarse`:

* 面向任务入门和 PPT 总结。
* 每个焦点节点只给职责、关键目录和 OS 概念关联。

`fine`:

* 面向写代码和 code review。
* 展示代表文件、符号、命中文件、实践风险和编码建议。

## 局限

* 当前是启发式静态扫描,不做完整 Rust 语义解析,也不构建精确调用图。
* 任务焦点依赖目录、关键词、git diff 和最近提交文件,不能替代人工读代码。
* 图谱节点是 OS 教学/工程视角下的子系统归类,不等价于 crate 依赖图。
* 该功能不调用 LLM,因此讲解模板是确定性的;后续可接入更细的符号索引或 rustdoc JSON。

## 后续扩展建议

1. 读取 `Cargo.toml` workspace 和 crate dependency,补充 crate 依赖边。
2. 用 `rustdoc --output-format json` 或 `cargo metadata` 生成更精确的符号图。
3. 将 qperf report 的 hotspot category 自动映射到知识图谱节点。
4. 在 GUI 的 qperf report 页点击 hotspot 时,跳转到对应知识图谱节点。
5. 为每个节点补充课程章节、推荐阅读和典型 bug 模式。
129 changes: 129 additions & 0 deletions docs/qperf-callchain-flamegraph-design.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
# qperf 深调用栈火焰图设计说明

## 1. 问题背景

旧版 qperf 生成的 `qperf/stack.folded` 大多只有一层函数名,因此 `flamegraph.svg` 只能横向展示 leaf hotspot,几乎没有纵向调用链。典型检查命令如下:

```bash
awk -F';' '{print NF}' target/qperf-host-rerun/blk-harness/perf/riscv64/latest/qperf/stack.folded | sort -n | uniq -c
```

旧 blk 产物的结果为 `623 1`,说明 623 条 folded stack 全部只有一帧。结合 `resolve.stats.json` 中 `format_version=2`、`raw_records=1292`、`total_frames=1292`,可以判断当时 raw sample 本身只有 PC/TB leaf 地址,不是 analyzer 把多帧调用栈压扁了。

## 2. 根因诊断

本轮诊断结论如下:

| 类别 | 结论 |
| --- | --- |
| raw sample 是否有 callchain | 旧格式没有,只有 elapsed timestamp 与 PC leaf。 |
| analyzer 是否压扁多帧 | 未发现多帧被压扁的问题;问题主要在采样侧没有多帧数据。 |
| QEMU plugin 是否读寄存器 | 旧执行回调使用 `QEMU_PLUGIN_CB_NO_REGS`,无法稳定读取 guest SP/FP。 |
| RISC-V FP 寄存器别名 | QEMU 暴露 `sp`、`fp`,同时也可能有 `x2`、`s0`、`x8` 别名;旧实现没有完整候选别名。 |
| 构建参数 | 旧 `--full-stack` 没有把 `-Cforce-frame-pointers=yes` 稳定传入实际 StarryOS kernel 构建。 |
| debug info | 只保留 leaf symbol 时还能解析函数名,但深栈与 inline 展开需要 `debuginfo=2` 与不剥离符号。 |

因此,火焰图浅的核心原因不是 SVG 展示参数、采样频率或 `--max-depth`,而是 qperf 采样链路没有拿到可 unwind 的 guest callchain。

## 3. 实现方案

本轮采用真实 frame-pointer callchain 方案,默认仍保留 leaf 模式:

| 模式 | 说明 |
| --- | --- |
| `leaf` | 默认模式,只记录 PC leaf,开销低、兼容旧命令。 |
| `fp` | 通过 QEMU TCG plugin 读取 guest `pc/sp/fp`,按 RISC-V frame pointer 链恢复调用栈。 |
| `logical` | 预留 CLI 值,但当前不实现;如果后续真实 unwind 不够稳定,再做人工插桩逻辑栈。 |

`cargo starry perf --full-stack` 等价于:

* 启用 qperf `callchain=fp`。
* 为 StarryOS kernel 构建加入 `-Cdebuginfo=2`、`-Cstrip=none`、`-Cforce-frame-pointers=yes`。
* 启用 `DWARF=y`、`BACKTRACE=y`,方便符号和 debug 信息保留。

## 4. raw sample v3

qperf plugin 新增 v3 sample 格式:

```text
elapsed_ns
pc
sp
fp
cpu
callchain
trace[]
```

其中:

* `pc` 是采样点 leaf PC。
* `sp` 是 guest stack pointer。
* `fp` 是 RISC-V `s0/fp`。
* `trace[]` 是 plugin 通过 frame pointer unwind 得到的地址链。
* `callchain=leaf|fp` 标记该样本来源。

analyzer 继续兼容旧 v1/v2 raw 格式;旧数据会自动退化为 leaf-only 栈。

## 5. RISC-V frame pointer unwind

RISC-V ABI 下,开启 frame pointer 后通常可从当前 `fp` 附近读取上一个 frame pointer 与 return address。本轮实现按如下策略恢复:

1. QEMU execute callback 使用 `QEMU_PLUGIN_CB_R_REGS`。
2. 采样时读取 guest `sp` 与 `fp`,寄存器候选包括 `sp/x2` 与 `fp/s0/x8`。
3. 只对 kernel text 或其物理映射别名范围内的 PC 做 unwind,避免在 OpenSBI 或用户态地址上误读。
4. 按 `fp - 16` 读取 `{prev_fp, ra}`。
5. 遇到非法地址、非单调 frame pointer、距离过大、循环 frame、不可读内存或非 kernel text return address 时停止。
6. 单个样本 unwind 失败时回退到 leaf,不中断整个 profile。

输出新增:

* `qperf/stack-depth-summary.csv`
* `report.json.callchain`
* `report.json.resolve_stats.depth_histogram`
* `qperf/summary.txt` 中的 sample format 与 callchain 字段

## 6. analyzer 与 folded stack

analyzer 的变化:

* 保留 raw sample 中的多帧地址,不再只按 leaf 聚合。
* folded stack 按 caller-to-leaf 顺序输出。
* `stack.folded` 默认保留完整 demangled Rust 路径。
* `hotspots.csv` 继续提供函数热点聚合,但函数百分比按函数帧总量计算,避免深栈下出现超过 100% 的函数占比。
* `hotspot_categories.csv` 是 inclusive stack 分类,表示某类别在多少条样本调用栈中出现,不是互斥 CPU 时间分摊。

## 7. cargo starry 集成

新增或完善的参数:

```text
cargo starry perf --full-stack
cargo starry perf --perf-callchain leaf|fp|logical
cargo starry perf --perf-debuginfo
cargo starry perf --perf-force-frame-pointers
cargo starry perf --symbol-style full|module|short
cargo starry perf --max-depth 128
```

推荐深栈用法:

```bash
cargo starry perf \
--case blk-full-stack \
--full-stack \
--start-marker QPERF_BEGIN \
--stop-marker QPERF_END \
--workload 'echo QPERF_BEGIN:blk; dd if=/usr/bin/lto-dump of=/dev/null bs=64k; echo QPERF_END:blk'
```

默认 `cargo starry perf` 仍使用 `leaf`,避免对普通 profile 强制引入 frame pointer 与 debug info 的构建开销。

## 8. 局限性

* `fp` 模式依赖 kernel 编译时保留 frame pointer;没有 `--full-stack` 时不能期待深栈。
* 目前只解析 kernel ELF,用户态符号和用户栈不是本轮目标。
* trap/syscall/task 切换附近的栈可能截断,不能保证穿透所有上下文切换。
* inline 展开会让 `stack.folded` 的符号层数大于 raw FP frame 数;原始地址深度以 `stack-depth-summary.csv` 为准。
* QEMU 退出如果被 SIGKILL 截断,plugin shutdown summary 可能缺失;analyzer 仍可处理已落盘 raw sample。
* `logical` 模式尚未实现,当前不会把人工 instrumentation 路径伪装成真实 CPU callchain。
Loading
Loading