diff --git a/.claude/skills/starry-syscall-harness/SKILL.md b/.claude/skills/starry-syscall-harness/SKILL.md new file mode 100644 index 0000000000..083266e153 --- /dev/null +++ b/.claude/skills/starry-syscall-harness/SKILL.md @@ -0,0 +1,68 @@ +--- +name: starry-syscall-harness +description: Audit and fix StarryOS syscall Linux-compatibility and qperf performance issues using the project harness. Use when comparing StarryOS syscall behavior with Linux, profiling StarryOS with qperf, running or extending tools/starry-syscall-harness, invoking its MCP tools, or validating syscall/performance fixes before opening a PR. +--- + +# Starry Syscall Harness + +Use this skill for StarryOS syscall semantic audits, qperf hotspot analysis, and fixes. + +## Core Rules + +- Run all StarryOS build, rootfs, QEMU, syscall probe, and qperf profile execution through Docker. +- Use the configured image by default: `ghcr.io/rcore-os/tgoskits-container:latest`. +- Prefer the harness entrypoint over hand-built commands: + `python3 tools/starry-syscall-harness/harness.py discover --arch riscv64` +- Prefer the qperf harness entrypoint for performance work: + `python3 tools/starry-syscall-harness/harness.py perf-profile --arch riscv64 --timeout 20` +- Treat host Linux probe output as the reference unless a case is explicitly documented as architecture-specific. +- Treat qperf top functions, folded stacks, and generated fix candidates as triage inputs; confirm suspected bottlenecks in code before patching. +- Keep fixes in the relevant syscall implementation; do not weaken probes to hide mismatches. +- After changing StarryOS logic, run `cargo fmt` and targeted clippy in Docker: + `docker run --rm -v "$PWD":/work -w /work ghcr.io/rcore-os/tgoskits-container:latest bash -lc 'cargo xtask clippy --package starry-kernel'` + +## Workflow + +1. Run `python3 tools/starry-syscall-harness/harness.py doctor` to verify Docker and required tools. +2. Run `python3 tools/starry-syscall-harness/harness.py discover --arch riscv64`. +3. Read the JSON report under `target/starry-syscall-harness//latest/report.json`. +4. Fix only mismatches with clear Linux semantics. +5. Rerun the harness for the affected arch, then run Docker clippy for changed crates. +6. Before PR work, fetch upstream and create a clean branch from the target upstream branch. + +## Performance Workflow + +1. Run `python3 tools/starry-syscall-harness/harness.py perf-profile --arch riscv64 --timeout 20`. +2. Read `target/starry-syscall-harness/perf//latest/report.json` and `report.md`. +3. Inspect `hotspots.top_functions`, `fix_candidates`, and `qperf/stack.folded`. +4. If comparing optimization attempts, run `perf-diff --baseline --compare `. +5. Use the default release profile for performance comparisons; pass `--debug` only when symbol detail is more important than optimized runtime behavior. +6. Keep the default broad qperf sampling unless the report is dominated by non-kernel addresses; use `--kernel-filter` only after confirming the detected `.text` range matches QEMU callback addresses. +7. Fix only bottlenecks supported by samples and code inspection. +8. Rerun `perf-profile`, then run Docker clippy for changed crates. + +## MCP + +The MCP server is `tools/starry-syscall-harness/mcp_server.py`. + +Register it locally with: + +```bash +codex mcp add starry-syscall-harness -- python3 /path/to/tgoskits/tools/starry-syscall-harness/mcp_server.py --repo /path/to/tgoskits +``` + +Available tools: + +- `starry_syscall_doctor`: checks Docker, image, and required toolchain availability. +- `starry_syscall_discover`: runs Linux-vs-StarryOS syscall probes and returns the report. +- `starry_perf_profile`: runs qperf in Docker, emits JSON/Markdown/CSV hotspot reports, and lists fix candidates. +- `starry_perf_diff`: compares two qperf folded-stack outputs or profile directories. + +## Probe Changes + +When adding a probe: + +- Put deterministic C cases in `tools/starry-syscall-harness/probes/syscall_probe.c`. +- Print one `CASE key=value ...` line per syscall behavior. +- Avoid fd numbers, timestamps, paths, pointer values, and scheduler-sensitive output in comparisons. +- Prefer small syscall-focused probes that can run under BusyBox init without extra packages. diff --git a/AGENTS.md b/AGENTS.md index e3412dc9f3..c8fd4d4451 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -18,6 +18,8 @@ - Use `board-uboot-fsck-repair` when a physical board Linux rootfs needs ext4 recovery through U-Boot, initramfs fsck reports unrepaired corruption, OrangePi-5-Plus needs `extraboardargs=fsckfix`, or Starry board write tests must be bracketed by Linux fsck/boot checks. - `crates-io-owner`: project-local skill at `.claude/skills/crates-io-owner/SKILL.md` - Use `crates-io-owner` when the user wants to add or verify `github:rcore-os:crates-io` for branch-added crates, asks which new crates still need the crates.io team owner, or explicitly wants `cargo owner` used instead of `Cargo.toml` metadata. +- `starry-syscall-harness`: project-local skill at `.claude/skills/starry-syscall-harness/SKILL.md` +- Use `starry-syscall-harness` when auditing StarryOS syscall Linux-compatibility semantics, running syscall differential tests, running qperf-based StarryOS performance profiling, using its MCP tools, or preparing fixes from harness output. ## Other Requirements diff --git a/Cargo.lock b/Cargo.lock index 3b4b99b53d..f71e1905f9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4667,6 +4667,22 @@ dependencies = [ "rustversion", ] +[[package]] +name = "inferno" +version = "0.12.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90807d610575744524d9bdc69f3885d96f0e6c3354565b0828354a7ff2a262b8" +dependencies = [ + "ahash 0.8.12", + "itoa", + "log", + "num-format", + "once_cell", + "quick-xml", + "rgb", + "str_stack", +] + [[package]] name = "inherit-methods-macro" version = "0.1.0" @@ -5619,6 +5635,16 @@ dependencies = [ "syn 2.0.117", ] +[[package]] +name = "num-format" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a652d9771a63711fd3c3deb670acfbe5c30a4072e664d7a3bf5a9e1056ac72c3" +dependencies = [ + "arrayvec", + "itoa", +] + [[package]] name = "num-integer" version = "0.1.46" @@ -6290,6 +6316,19 @@ dependencies = [ "anyhow", "bincode", "clap", + "inferno", + "object 0.37.3", + "regex", + "rustc-demangle", +] + +[[package]] +name = "quick-xml" +version = "0.39.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdcc8dd4e2f670d309a5f0e83fe36dfdc05af317008fea29144da1a2ac858e5e" +dependencies = [ + "memchr", ] [[package]] @@ -8181,6 +8220,12 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" +[[package]] +name = "str_stack" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f446288b699d66d0fd2e30d1cfe7869194312524b3b9252594868ed26ef056a" + [[package]] name = "strsim" version = "0.10.0" diff --git a/ai-harness-ppt/ai-harness-defense.pptx b/ai-harness-ppt/ai-harness-defense.pptx new file mode 100644 index 0000000000..d528b48a0d Binary files /dev/null and b/ai-harness-ppt/ai-harness-defense.pptx differ diff --git a/ai-harness-ppt/assets/ai-harness-cover-16x9.png b/ai-harness-ppt/assets/ai-harness-cover-16x9.png new file mode 100644 index 0000000000..af877751e3 Binary files /dev/null and b/ai-harness-ppt/assets/ai-harness-cover-16x9.png differ diff --git a/ai-harness-ppt/assets/ai-harness-cover.png b/ai-harness-ppt/assets/ai-harness-cover.png new file mode 100644 index 0000000000..cc5927face Binary files /dev/null and b/ai-harness-ppt/assets/ai-harness-cover.png differ diff --git a/ai-harness-ppt/assets/flamegraph-panel.png b/ai-harness-ppt/assets/flamegraph-panel.png new file mode 100644 index 0000000000..140851fcab Binary files /dev/null and b/ai-harness-ppt/assets/flamegraph-panel.png differ diff --git a/ai-harness-ppt/assets/flamegraph.png b/ai-harness-ppt/assets/flamegraph.png new file mode 100644 index 0000000000..1ecf0c8e82 Binary files /dev/null and b/ai-harness-ppt/assets/flamegraph.png differ diff --git a/ai-harness-ppt/build_ai_harness_ppt.py b/ai-harness-ppt/build_ai_harness_ppt.py new file mode 100644 index 0000000000..7633d3c3b7 --- /dev/null +++ b/ai-harness-ppt/build_ai_harness_ppt.py @@ -0,0 +1,1198 @@ +#!/usr/bin/env python3 +from __future__ import annotations + +import json +from datetime import date +from pathlib import Path + +from PIL import Image, ImageDraw, ImageFilter, ImageOps +from pptx import Presentation +from pptx.dml.color import RGBColor +from pptx.enum.dml import MSO_THEME_COLOR +from pptx.enum.shapes import MSO_AUTO_SHAPE_TYPE, MSO_CONNECTOR +from pptx.enum.text import MSO_ANCHOR, PP_ALIGN +from pptx.oxml.ns import qn +from pptx.oxml.xmlchemy import OxmlElement +from pptx.util import Inches, Pt + + +ROOT = Path(__file__).resolve().parents[1] +OUT_DIR = ROOT / "ai-harness-ppt" +ASSET_DIR = OUT_DIR / "assets" +OUT = OUT_DIR / "ai-harness-defense.pptx" + +SLIDE_W = Inches(13.333333) +SLIDE_H = Inches(7.5) + +FONT = "Noto Sans CJK SC" +FONT_FALLBACK = "Microsoft YaHei" + +C = { + "dark": RGBColor(18, 24, 32), + "dark2": RGBColor(27, 35, 45), + "ink": RGBColor(33, 41, 54), + "muted": RGBColor(96, 111, 128), + "line": RGBColor(209, 216, 224), + "paper": RGBColor(248, 250, 252), + "white": RGBColor(255, 255, 255), + "cyan": RGBColor(0, 166, 181), + "cyan2": RGBColor(213, 245, 247), + "amber": RGBColor(239, 159, 62), + "amber2": RGBColor(255, 239, 213), + "green": RGBColor(34, 163, 104), + "green2": RGBColor(222, 247, 235), + "red": RGBColor(211, 68, 79), + "blue": RGBColor(68, 103, 201), + "blue2": RGBColor(229, 234, 255), + "violet": RGBColor(127, 83, 172), + "violet2": RGBColor(239, 232, 247), +} + + +def read_json(path: Path) -> dict: + if path.exists(): + return json.loads(path.read_text(encoding="utf-8", errors="replace")) + return {} + + +def load_data() -> dict: + syscall_rv = read_json(ROOT / "target/starry-syscall-harness/riscv64/latest/report.json") + syscall_x86 = read_json(ROOT / "target/starry-syscall-harness/x86_64/latest/report.json") + perf = read_json(ROOT / "target/starry-syscall-harness/perf/riscv64/latest/report.json") + diff = read_json(ROOT / "target/starry-syscall-harness/perf-diff/report.json") + return {"syscall_rv": syscall_rv, "syscall_x86": syscall_x86, "perf": perf, "diff": diff} + + +def ensure_assets() -> None: + ASSET_DIR.mkdir(parents=True, exist_ok=True) + cover = ASSET_DIR / "ai-harness-cover.png" + cover_16x9 = ASSET_DIR / "ai-harness-cover-16x9.png" + if cover.exists() and not cover_16x9.exists(): + with Image.open(cover) as im: + im = im.convert("RGB") + ImageOps.fit(im, (1920, 1080), method=Image.Resampling.LANCZOS, centering=(0.7, 0.5)).save(cover_16x9) + + flame = ASSET_DIR / "flamegraph.png" + flame_panel = ASSET_DIR / "flamegraph-panel.png" + if flame.exists(): + with Image.open(flame) as im: + im = im.convert("RGBA") + canvas = Image.new("RGBA", (1920, 360), (255, 255, 255, 255)) + resized = im.resize((1780, max(68, int(im.height * 1780 / im.width))), Image.Resampling.LANCZOS) + y = 186 + shadow = Image.new("RGBA", resized.size, (0, 0, 0, 0)) + ImageDraw.Draw(shadow).rounded_rectangle((0, 0, resized.width - 1, resized.height - 1), radius=10, fill=(0, 0, 0, 60)) + canvas.alpha_composite(shadow.filter(ImageFilter.GaussianBlur(8)), (74, y - 2)) + canvas.alpha_composite(resized, (70, y)) + draw = ImageDraw.Draw(canvas) + draw.rounded_rectangle((70, 42, 1850, 132), radius=24, fill=(18, 24, 32, 255)) + draw.text((104, 68), "qperf flamegraph artifact", fill=(255, 255, 255, 255)) + draw.text((490, 68), "实际 SVG 产物已转换为证据截图;热点解释以 JSON/CSV 为准", fill=(205, 213, 224, 255)) + canvas.save(flame_panel) + + +def set_font(run, size: int | float | None = None, color: RGBColor | None = None, bold: bool = False): + font = run.font + font.name = FONT + if size is not None: + font.size = Pt(size) + if color is not None: + font.color.rgb = color + font.bold = bold + r_pr = run._r.get_or_add_rPr() + for tag, typeface in (("a:latin", FONT), ("a:ea", FONT), ("a:cs", FONT_FALLBACK)): + element = r_pr.find(qn(tag)) + if element is None: + element = OxmlElement(tag) + r_pr.append(element) + element.set("typeface", typeface) + + +def fill_solid(shape, color: RGBColor, transparency: int | None = None): + shape.fill.solid() + shape.fill.fore_color.rgb = color + if transparency is not None: + shape.fill.transparency = transparency + + +def line_solid(shape, color: RGBColor, width: float = 1.0, transparency: int | None = None): + shape.line.color.rgb = color + shape.line.width = Pt(width) + if transparency is not None: + shape.line.transparency = transparency + + +def set_bg(slide, color: RGBColor = C["paper"]): + slide.background.fill.solid() + slide.background.fill.fore_color.rgb = color + + +def add_text(slide, x, y, w, h, text, size=18, color=C["ink"], bold=False, align=PP_ALIGN.LEFT, valign=MSO_ANCHOR.TOP): + box = slide.shapes.add_textbox(x, y, w, h) + tf = box.text_frame + tf.clear() + tf.word_wrap = True + tf.margin_left = Inches(0.04) + tf.margin_right = Inches(0.04) + tf.margin_top = Inches(0.02) + tf.margin_bottom = Inches(0.02) + tf.vertical_anchor = valign + p = tf.paragraphs[0] + p.alignment = align + run = p.add_run() + run.text = text + set_font(run, size, color, bold) + return box + + +def add_multiline(slide, x, y, w, h, lines, size=16, color=C["ink"], bullet=False, gap=0.85): + box = slide.shapes.add_textbox(x, y, w, h) + tf = box.text_frame + tf.clear() + tf.word_wrap = True + tf.margin_left = Inches(0.08) + tf.margin_right = Inches(0.06) + tf.margin_top = Inches(0.02) + tf.margin_bottom = Inches(0.02) + for i, line in enumerate(lines): + p = tf.paragraphs[0] if i == 0 else tf.add_paragraph() + p.space_after = Pt(5 * gap) + p.line_spacing = 1.05 + run = p.add_run() + run.text = ("• " if bullet else "") + line + set_font(run, size, color) + return box + + +def add_title(slide, title: str, subtitle: str | None = None, section: str | None = None): + if section: + add_text(slide, Inches(0.62), Inches(0.36), Inches(2.3), Inches(0.28), section.upper(), 8.5, C["cyan"], True) + add_text(slide, Inches(0.62), Inches(0.58), Inches(8.8), Inches(0.62), title, 26, C["dark"], True) + if subtitle: + add_text(slide, Inches(0.64), Inches(1.15), Inches(8.8), Inches(0.36), subtitle, 12.5, C["muted"]) + line = slide.shapes.add_shape(MSO_AUTO_SHAPE_TYPE.RECTANGLE, Inches(0.62), Inches(1.46), Inches(1.15), Inches(0.045)) + fill_solid(line, C["amber"]) + line.line.fill.background() + + +def add_footer(slide, idx: int, total: int): + add_text(slide, Inches(0.62), Inches(7.12), Inches(2.8), Inches(0.18), "AI-Harness 答辩", 8.5, C["muted"]) + add_text(slide, Inches(12.03), Inches(7.12), Inches(0.76), Inches(0.18), f"{idx:02d}/{total:02d}", 8.5, C["muted"], align=PP_ALIGN.RIGHT) + + +def add_card(slide, x, y, w, h, title, body_lines, accent=C["cyan"], fill=C["white"], title_size=16, body_size=12.5): + card = slide.shapes.add_shape(MSO_AUTO_SHAPE_TYPE.ROUNDED_RECTANGLE, x, y, w, h) + fill_solid(card, fill) + line_solid(card, RGBColor(224, 229, 235), 0.75) + stripe = slide.shapes.add_shape(MSO_AUTO_SHAPE_TYPE.RECTANGLE, x, y, Inches(0.08), h) + fill_solid(stripe, accent) + stripe.line.fill.background() + add_text(slide, x + Inches(0.26), y + Inches(0.18), w - Inches(0.42), Inches(0.34), title, title_size, C["dark"], True) + add_multiline(slide, x + Inches(0.23), y + Inches(0.63), w - Inches(0.42), h - Inches(0.76), body_lines, body_size, C["ink"], bullet=False) + return card + + +def add_metric(slide, x, y, w, h, value, label, accent=C["cyan"], note=None): + card = slide.shapes.add_shape(MSO_AUTO_SHAPE_TYPE.ROUNDED_RECTANGLE, x, y, w, h) + fill_solid(card, C["white"]) + line_solid(card, RGBColor(222, 228, 235), 0.75) + marker = slide.shapes.add_shape(MSO_AUTO_SHAPE_TYPE.OVAL, x + Inches(0.22), y + Inches(0.24), Inches(0.18), Inches(0.18)) + fill_solid(marker, accent) + marker.line.fill.background() + add_text(slide, x + Inches(0.22), y + Inches(0.54), w - Inches(0.44), Inches(0.54), value, 28, C["dark"], True) + add_text(slide, x + Inches(0.24), y + Inches(1.12), w - Inches(0.48), Inches(0.32), label, 12.5, C["ink"], True) + if note: + add_text(slide, x + Inches(0.24), y + Inches(1.48), w - Inches(0.48), Inches(0.36), note, 9.5, C["muted"]) + return card + + +def add_arrow(slide, x1, y1, x2, y2, color=C["muted"], width=1.4): + conn = slide.shapes.add_connector( + MSO_CONNECTOR.STRAIGHT, + int(round(x1)), + int(round(y1)), + int(round(x2)), + int(round(y2)), + ) + line_solid(conn, color, width) + conn.line.end_arrowhead = 3 + return conn + + +def add_node(slide, x, y, w, h, title, subtitle=None, fill=C["white"], accent=C["cyan"], title_size=14): + shape = slide.shapes.add_shape(MSO_AUTO_SHAPE_TYPE.ROUNDED_RECTANGLE, x, y, w, h) + fill_solid(shape, fill) + line_solid(shape, accent, 1.1) + add_text(slide, x + Inches(0.13), y + Inches(0.16), w - Inches(0.26), Inches(0.28), title, title_size, C["dark"], True, align=PP_ALIGN.CENTER) + if subtitle: + add_text(slide, x + Inches(0.16), y + Inches(0.50), w - Inches(0.32), h - Inches(0.56), subtitle, 9.8, C["muted"], align=PP_ALIGN.CENTER) + return shape + + +def shorten_func(name: str) -> str: + rules = [ + ("add_notify_wait_pop", "VirtQueue::add_notify_wait_pop"), + ("compiler_builtins3mem6memcpy", "memcpy"), + ("yield_current", "yield_current"), + ("current_check_preempt_pending", "check_preempt_pending"), + ("pseudofs4proc", "procfs builders"), + ("run_idle", "run_idle"), + ] + for needle, label in rules: + if needle in name: + return label + if len(name) > 26: + return name[:25] + "..." + return name + + +def table_cell(cell, text, size=10.5, color=C["ink"], bold=False, fill=None, align=PP_ALIGN.LEFT): + if fill is not None: + cell.fill.solid() + cell.fill.fore_color.rgb = fill + cell.vertical_anchor = MSO_ANCHOR.MIDDLE + tf = cell.text_frame + tf.clear() + tf.margin_left = Inches(0.06) + tf.margin_right = Inches(0.04) + p = tf.paragraphs[0] + p.alignment = align + run = p.add_run() + run.text = str(text) + set_font(run, size, color, bold) + + +def add_header_bar(slide, text, color=C["dark"]): + rect = slide.shapes.add_shape(MSO_AUTO_SHAPE_TYPE.RECTANGLE, Inches(0), Inches(0), SLIDE_W, Inches(0.18)) + fill_solid(rect, color) + rect.line.fill.background() + if text: + add_text(slide, Inches(10.2), Inches(0.26), Inches(2.5), Inches(0.2), text, 8.5, C["muted"], align=PP_ALIGN.RIGHT) + + +def slide_cover(prs, data): + slide = prs.slides.add_slide(prs.slide_layouts[6]) + set_bg(slide, C["dark"]) + cover = ASSET_DIR / "ai-harness-cover-16x9.png" + if cover.exists(): + slide.shapes.add_picture(str(cover), 0, 0, width=SLIDE_W, height=SLIDE_H) + overlay = slide.shapes.add_shape(MSO_AUTO_SHAPE_TYPE.RECTANGLE, 0, 0, SLIDE_W, SLIDE_H) + fill_solid(overlay, RGBColor(7, 11, 17), 28) + overlay.line.fill.background() + add_text(slide, Inches(0.78), Inches(0.62), Inches(3.6), Inches(0.24), "TGOSKits / StarryOS", 11, RGBColor(210, 222, 235), True) + add_text(slide, Inches(0.74), Inches(1.28), Inches(6.8), Inches(1.05), "ArceOS 实验与 AI-Harness", 38, C["white"], True) + add_text(slide, Inches(0.78), Inches(2.25), Inches(6.7), Inches(0.92), "任务一:工程化课程实验\n任务二:StarryOS 自治开发框架", 21, RGBColor(223, 232, 240), True) + add_text(slide, Inches(0.80), Inches(3.54), Inches(5.9), Inches(0.58), "从真实 ArceOS crate 生态到 syscall/qperf 自动化闭环", 15, RGBColor(190, 204, 218)) + add_text(slide, Inches(0.80), Inches(6.62), Inches(3.8), Inches(0.26), f"答辩汇报 | {date.today().isoformat()}", 11, RGBColor(190, 204, 218)) + return slide + + +def slide_answer_structure(prs): + slide = prs.slides.add_slide(prs.slide_layouts[6]) + set_bg(slide, RGBColor(247, 249, 252)) + add_header_bar(slide, "00") + add_title(slide, "答辩结构:两个任务,一条工程能力主线", "任务一训练真实 ArceOS 工程实践;任务二把这种实践进一步自动化、证据化。", "Overview") + add_card( + slide, + Inches(0.82), + Inches(1.88), + Inches(5.54), + Inches(4.34), + "任务一:tg-arceos-tutorial 五个实验", + [ + "printcolor:从应用输出触达 axstd/axhal 层次", + "hashmap:把 Rust 集合生态接入 no_std axstd", + "altalloc:实现同时服务 byte/page 的 bump allocator", + "ramfs-rename:补齐 VFS 到 ramfs 的 rename 语义链路", + "sysmap:运行 musl 用户态程序并实现文件 mmap", + ], + C["cyan"], + C["white"], + title_size=18, + body_size=12.9, + ) + add_card( + slide, + Inches(6.98), + Inches(1.88), + Inches(5.54), + Inches(4.34), + "任务二:AI-Harness 自治开发框架", + [ + "syscall Linux-vs-StarryOS 对拍", + "qperf profile / flamegraph / perf-diff", + "CLI + MCP + Local UI + Codex skill", + "Docker 隔离执行与结构化报告", + "面向 PR 的证据链和回归验证流程", + ], + C["amber"], + C["white"], + title_size=18, + body_size=12.9, + ) + add_text(slide, Inches(0.96), Inches(6.54), Inches(11.36), Inches(0.34), "贯穿主线:不是只理解 OS 原理,而是在真实工程约束下把功能做成可构建、可运行、可验证、可协作的系统能力。", 14.2, C["dark"], True, align=PP_ALIGN.CENTER) + return slide + + +def slide_task1_overview(prs): + slide = prs.slides.add_slide(prs.slide_layouts[6]) + set_bg(slide) + add_header_bar(slide, "T1") + add_title(slide, "任务一概览:五个实验覆盖 ArceOS 的关键工程边界", "每个 exercise 都是独立 unikernel 项目,支持多架构 build/run,并用脚本检查串口输出。", "Task 1") + rows = [ + ("printcolor", "ANSI 彩色输出", "应用输出 / axstd / axhal", "Hello + SGR 序列"), + ("hashmap", "collections::HashMap", "axstd + hashbrown + alloc", "5 万键值插入与校验"), + ("altalloc", "bump_allocator", "axalloc / global allocator", "300 万 Vec push + sort"), + ("ramfs-rename", "std::fs::rename", "axfs + axfs_ramfs + VFS", "ramfs 文件重命名并读回"), + ("sysmap", "SYS_MMAP", "用户态 ELF / syscall / AddrSpace", "mmap 文件并读回 hello"), + ] + table = slide.shapes.add_table(len(rows) + 1, 4, Inches(0.58), Inches(1.72), Inches(12.18), Inches(3.18)).table + widths = [2.0, 2.45, 3.75, 3.98] + for i, width in enumerate(widths): + table.columns[i].width = Inches(width) + for j, h in enumerate(("实验", "核心任务", "触达模块", "验收信号")): + table_cell(table.cell(0, j), h, 10.4, C["white"], True, C["dark"], PP_ALIGN.CENTER) + for i, row in enumerate(rows, start=1): + for j, val in enumerate(row): + fill = C["white"] if i % 2 else RGBColor(244, 247, 250) + table_cell(table.cell(i, j), val, 9.7, C["ink"], j == 0, fill, PP_ALIGN.CENTER if j != 2 else PP_ALIGN.LEFT) + add_card( + slide, + Inches(0.82), + Inches(5.22), + Inches(11.62), + Inches(0.94), + "共同工程框架", + [ + "nightly + bare-metal targets + cargo xtask + QEMU;脚本覆盖 riscv64、x86_64、aarch64、loongarch64,并按串口输出做功能判定。", + ], + C["cyan"], + C["white"], + title_size=13.5, + body_size=11.4, + ) + return slide + + +def slide_task1_path(prs): + slide = prs.slides.add_slide(prs.slide_layouts[6]) + set_bg(slide, RGBColor(247, 250, 249)) + add_header_bar(slide, "T1") + add_title(slide, "任务一学习路径:从可见输出走向用户态 syscall 语义", "实验难度不是堆知识点,而是逐步扩大“必须理解的工程上下文”。", "Task 1") + steps = [ + ("printcolor", "应用输出\nANSI / println!"), + ("hashmap", "标准库外观\nno_std collections"), + ("altalloc", "内核资源\n全局分配器"), + ("ramfs rename", "文件系统\nVFS 转发语义"), + ("sysmap", "用户态运行\nELF + mmap syscall"), + ] + colors = [C["blue"], C["cyan"], C["green"], C["amber"], C["violet"]] + x0, y0 = Inches(0.82), Inches(2.1) + for i, (title, sub) in enumerate(steps): + x = x0 + Inches(i * 2.42) + add_node(slide, x, y0, Inches(1.72), Inches(1.06), title, sub, C["white"], colors[i], 12) + if i < len(steps) - 1: + add_arrow(slide, x + Inches(1.72), y0 + Inches(0.53), x + Inches(2.24), y0 + Inches(0.53), C["muted"], 1.0) + add_card( + slide, + Inches(0.82), + Inches(4.16), + Inches(3.52), + Inches(1.72), + "传统 OS 课常见收获", + [ + "理解进程、内存、文件系统、系统调用等概念模型", + "在教学内核中实现相对封闭的模块", + ], + C["blue"], + C["white"], + title_size=14.5, + body_size=11.4, + ) + add_card( + slide, + Inches(4.82), + Inches(4.16), + Inches(7.52), + Inches(1.72), + "这组实验的独特收获", + [ + "要把概念落到真实 crate 依赖、feature、trait、linker、QEMU、串口日志、跨架构 ABI 和测试脚本上;问题不再停在“算法对不对”,而是“能否接入系统并长期维护”。", + ], + C["amber"], + C["white"], + title_size=14.5, + body_size=12, + ) + return slide + + +def slide_task1_no_std(prs): + slide = prs.slides.add_slide(prs.slide_layouts[6]) + set_bg(slide) + add_header_bar(slide, "T1") + add_title(slide, "独特收获一:把 Rust 生态迁移到 no_std OS 环境", "HashMap 不是“会用集合”,而是让 axstd 具备接近 std 的 API 外观。", "Task 1") + add_card( + slide, + Inches(0.72), + Inches(1.74), + Inches(3.52), + Inches(4.72), + "printcolor", + [ + "理解 `println!` 在 axstd 中如何落到串口输出", + "ANSI SGR 序列让输出验证从文本变成字节级行为", + "提示:修改 axstd 与 axhal 会影响不同输出层", + ], + C["blue"], + C["white"], + title_size=17, + body_size=12.2, + ) + add_card( + slide, + Inches(4.88), + Inches(1.74), + Inches(3.52), + Inches(4.72), + "hashmap", + [ + "在 axstd 的 `collections` 中导出 HashMap / HashSet", + "引入 `hashbrown`,并处理 `default-hasher` 与 alloc 依赖", + "通过 50,000 个 key/value 验证分配器、格式化和迭代", + ], + C["cyan"], + C["white"], + title_size=17, + body_size=12.2, + ) + add_card( + slide, + Inches(9.04), + Inches(1.74), + Inches(3.52), + Inches(4.72), + "独特能力", + [ + "理解 `extern crate axstd as std` 背后的兼容层", + "知道 crates.io 版本缺口如何用本地 path / patch 修补", + "学会在 no_std、alloc、随机数和平台 HAL 之间定位问题", + ], + C["green"], + C["white"], + title_size=17, + body_size=12.2, + ) + return slide + + +def slide_task1_allocator_fs(prs): + slide = prs.slides.add_slide(prs.slide_layouts[6]) + set_bg(slide, RGBColor(248, 249, 246)) + add_header_bar(slide, "T1") + add_title(slide, "独特收获二:在真实 trait 边界里替换内核组件", "altalloc 和 ramfs-rename 都要求理解局部实现如何被上层全局机制调用。", "Task 1") + add_card( + slide, + Inches(0.78), + Inches(1.78), + Inches(5.62), + Inches(4.58), + "altalloc:分配器不是一个孤立算法", + [ + "`bump_allocator::EarlyAllocator` 同时承担 byte allocator 与 page allocator", + "实现 `BaseAllocator`、`ByteAllocator`、`PageAllocator` 三组 trait", + "`axalloc` 通过 `[patch.crates-io]` 和 feature 默认选用本地 bump allocator", + "大 Vec + sort 压测暴露容量、对齐、回收计数和页分配边界", + ], + C["green"], + C["white"], + title_size=16, + body_size=12.3, + ) + add_card( + slide, + Inches(6.92), + Inches(1.78), + Inches(5.62), + Inches(4.58), + "ramfs-rename:文件系统语义要走完整链路", + [ + "`std::fs::rename` 经过 axstd/axfs 到 `axfs_ramfs`", + "补齐 `VfsNodeOps::rename`,并让 composite root 正确转发", + "限制同目录 rename,不把 move 语义误当成 rename", + "通过创建、写入、重命名、重新读回确认可见语义", + ], + C["amber"], + C["white"], + title_size=16, + body_size=12.3, + ) + return slide + + +def slide_task1_sysmap(prs): + slide = prs.slides.add_slide(prs.slide_layouts[6]) + set_bg(slide) + add_header_bar(slide, "T1") + add_title(slide, "独特收获三:从内核进入用户态 ABI 与 Linux 语义", "sysmap 把课程里的 mmap 概念落实到 ELF、用户地址空间、trap 和文件 fd。", "Task 1") + nodes = [ + ("musl payload", "mapfile.c\nstatic ELF"), + ("FAT32 disk", "/sbin/mapfile\nvirtio-blk"), + ("ELF loader", "PT_LOAD\nuser stack"), + ("trap loop", "UserContext\nsyscall dispatch"), + ("SYS_MMAP", "file-backed\nAddrSpace map"), + ("verification", "read back\nMapFile ok"), + ] + colors = [C["blue"], C["cyan"], C["green"], C["amber"], C["violet"], C["dark"]] + x0, y0 = Inches(0.62), Inches(1.82) + for i, (title, sub) in enumerate(nodes): + x = x0 + Inches(i * 2.05) + add_node(slide, x, y0, Inches(1.54), Inches(0.98), title, sub, C["white"], colors[i], 11.5) + if i < len(nodes) - 1: + add_arrow(slide, x + Inches(1.54), y0 + Inches(0.49), x + Inches(1.88), y0 + Inches(0.49), C["muted"], 0.95) + add_card( + slide, + Inches(0.84), + Inches(3.62), + Inches(5.62), + Inches(2.32), + "实现重点", + [ + "按架构读取 syscall number 与参数,按 Linux mmap ABI 返回结果", + "处理 PROT / MAP flags、页对齐、匿名映射、文件映射与 errno", + "通过 `USER_ASPACE` 写入映射内容,而不是只在内核缓冲区模拟", + ], + C["violet"], + C["white"], + title_size=15, + body_size=12.2, + ) + add_card( + slide, + Inches(6.86), + Inches(3.62), + Inches(5.62), + Inches(2.32), + "区别于普通课程实验", + [ + "需要处理真实 musl 程序的系统调用序列,而不是手写单个测试函数", + "跨架构 syscall number / register convention 会直接影响正确性", + "文件系统、内存管理和任务切换必须在同一个可运行镜像里闭合", + ], + C["cyan"], + C["white"], + title_size=15, + body_size=12.2, + ) + return slide + + +def slide_task1_validation(prs): + slide = prs.slides.add_slide(prs.slide_layouts[6]) + set_bg(slide, RGBColor(247, 248, 252)) + add_header_bar(slide, "T1") + add_title(slide, "任务一验证方式:面向真实运行,而不是只看单元测试", "每个 exercise 都通过 `cargo xtask run` 构建裸机镜像、启动 QEMU、检查串口输出。", "Task 1") + add_metric(slide, Inches(0.82), Inches(1.86), Inches(2.5), Inches(1.78), "5", "standalone exercises", C["cyan"], "独立 Cargo 项目") + add_metric(slide, Inches(3.58), Inches(1.86), Inches(2.5), Inches(1.78), "4", "target architectures", C["blue"], "rv64 / x86 / arm64 / loongarch") + add_metric(slide, Inches(6.34), Inches(1.86), Inches(2.5), Inches(1.78), "QEMU", "runtime check", C["amber"], "serial-output oracle") + add_metric(slide, Inches(9.10), Inches(1.86), Inches(2.5), Inches(1.78), "OK", "representative run", C["green"], "printcolor/riscv64 in Docker") + add_card( + slide, + Inches(1.02), + Inches(4.22), + Inches(10.96), + Inches(1.36), + "验证信号示例", + [ + "`Hello, Arceos!` + ANSI SGR、`test_hashmap() OK!`、`Bump tests run OK!`、`[Ramfs-Rename]: ok!`、`Read back content: hello, arceos!` + `MapFile ok!`。", + ], + C["green"], + C["white"], + title_size=14, + body_size=12.1, + ) + add_text(slide, Inches(0.94), Inches(6.20), Inches(11.5), Inches(0.42), "这类验证强迫我们同时关心编译目标、链接脚本、镜像格式、QEMU 参数、串口日志和跨架构差异,训练的是 OS 工程交付能力。", 14, C["dark"], True, align=PP_ALIGN.CENTER) + return slide + + +def slide_problem(prs): + slide = prs.slides.add_slide(prs.slide_layouts[6]) + set_bg(slide) + add_header_bar(slide, "01") + add_title(slide, "任务二背景:StarryOS 兼容与性能问题越来越难靠人工闭环", "Linux 兼容目标下,细粒度语义差异和运行时热点都需要可复现证据。", "Task 2") + add_card( + slide, + Inches(0.78), + Inches(1.88), + Inches(5.72), + Inches(4.42), + "Syscall 语义兼容", + [ + "错误返回值、errno、flag 校验顺序会直接影响应用行为", + "边界条件分散在 fd、路径、权限、信号和内存等路径中", + "只看源码难以判断 Linux 真实行为", + "修复后必须重新对拍,不能靠改弱测试通过", + ], + C["cyan"], + C["white"], + title_size=20, + body_size=15, + ) + add_card( + slide, + Inches(6.84), + Inches(1.88), + Inches(5.72), + Inches(4.42), + "qperf 性能定位", + [ + "热点可能分布在 VirtIO、内存映射、调度、锁与 copy 路径", + "优化不能只依赖直觉,需要样本、火焰图和 diff", + "采样结果要能保存、比较、复查,并进入 PR 证据链", + "agent 需要结构化输入,而不是一次性命令输出", + ], + C["amber"], + C["white"], + title_size=20, + body_size=15, + ) + add_text(slide, Inches(0.9), Inches(6.55), Inches(11.55), Inches(0.28), "核心矛盾:要让 AI 自动做开发,必须先把“发现问题 -> 形成证据 -> 定位代码 -> 验证回归”做成稳定接口。", 14, C["dark"], True, align=PP_ALIGN.CENTER) + return slide + + +def slide_goals(prs): + slide = prs.slides.add_slide(prs.slide_layouts[6]) + set_bg(slide) + add_header_bar(slide, "02") + add_title(slide, "任务二设计目标:自动化,但不牺牲可信性", "框架不是脚本集合,而是面向 agent 和人工协作的开发平台。", "Task 2") + goals = [ + ("自动化调用", "CLI/MCP 默认入口;无需人工点击即可批量扫描、采样、生成报告", C["cyan"]), + ("可信基线", "Linux probe 输出作为 syscall 参考;StarryOS 构建和 QEMU 统一在 Docker", C["green"]), + ("证据落盘", "JSON / Markdown / CSV / SVG / logs 全部保留,便于复核和 PR 说明", C["amber"]), + ("可交互观察", "本地 Web UI 可看任务、报告、flamegraph 和 artifact", C["blue"]), + ("真实 PR 流程", "fetch/rebase、验证命令、关键结果与风险点进入 PR 描述", C["violet"]), + ] + x0, y0 = Inches(0.76), Inches(1.88) + for i, (title, body, color) in enumerate(goals): + x = x0 + Inches((i % 3) * 4.1) + y = y0 + Inches((i // 3) * 2.08) + add_card(slide, x, y, Inches(3.64), Inches(1.62), title, [body], color, C["white"], title_size=16, body_size=12.4) + add_text(slide, Inches(7.15), Inches(5.96), Inches(4.7), Inches(0.58), "交付形态:CLI harness + MCP server + Codex skill + Local UI + Docker 执行边界 + 结构化报告。", 15, C["dark"], True, align=PP_ALIGN.CENTER) + return slide + + +def slide_architecture(prs): + slide = prs.slides.add_slide(prs.slide_layouts[6]) + set_bg(slide, RGBColor(245, 247, 250)) + add_header_bar(slide, "03") + add_title(slide, "任务二总体架构:agent 不直接拼复杂构建命令", "harness 负责参数规范化、Docker 重入、输出目录管理、报告生成与 artifact 回收。", "Task 2") + layers = [ + ("Agent / Human Operator", "MCP 自动调用 | CLI 直接调用 | Local Web UI", C["blue2"], C["blue"]), + ("Harness Entry Points", "harness.py | mcp_server.py | ui_server.py", C["cyan2"], C["cyan"]), + ("Docker Execution Boundary", "ghcr.io/rcore-os/tgoskits-container:latest", C["green2"], C["green"]), + ("Syscall Differential Engine", "Linux probe vs StarryOS probe | CASE parser | report.json", C["amber2"], C["amber"]), + ("qperf Performance Engine", "TCG plugin | analyzer | folded stack | flamegraph | diff", C["violet2"], C["violet"]), + ("Reports And Feedback", "JSON | Markdown | CSV | SVG | logs | PR evidence", C["white"], C["dark"]), + ] + x, y, w, h = Inches(1.06), Inches(1.72), Inches(8.9), Inches(0.68) + for i, (title, body, fill, accent) in enumerate(layers): + yy = y + Inches(i * 0.82) + rect = slide.shapes.add_shape(MSO_AUTO_SHAPE_TYPE.ROUNDED_RECTANGLE, x, yy, w, h) + fill_solid(rect, fill) + line_solid(rect, accent, 1) + add_text(slide, x + Inches(0.24), yy + Inches(0.12), Inches(3.4), Inches(0.25), title, 14.5, C["dark"], True) + add_text(slide, x + Inches(3.65), yy + Inches(0.14), Inches(5.0), Inches(0.24), body, 11.2, C["ink"]) + if i < len(layers) - 1: + mid = x + (w // 2) + add_arrow(slide, mid, yy + h, mid, yy + h + Inches(0.14), layers[i][3], 1.0) + add_card( + slide, + Inches(10.34), + Inches(1.86), + Inches(2.18), + Inches(3.46), + "关键抽象", + [ + "稳定入口:harness.py", + "隔离边界:Docker", + "机器可读:report.json", + "人可读:UI + flamegraph", + "协作闭环:PR evidence", + ], + C["cyan"], + C["white"], + title_size=14, + body_size=10.6, + ) + return slide + + +def slide_syscall_loop(prs, data): + slide = prs.slides.add_slide(prs.slide_layouts[6]) + set_bg(slide) + add_header_bar(slide, "04") + add_title(slide, "Syscall 对拍闭环:同一份 probe,Linux 作为语义基线", "输出稳定 CASE key=value 行,避免 fd、地址、时间戳等非确定信息进入比较。", "Syscall") + steps = [ + ("写入 probe", "syscall_probe.c"), + ("Linux 执行", "生成参考输出"), + ("StarryOS 构建", "rootfs + debugfs 注入"), + ("QEMU 运行", "捕获 begin/end marker"), + ("CASE 解析", "ANSI 清理 + key/value"), + ("差异报告", "report.json + artifacts"), + ] + colors = [C["blue"], C["green"], C["cyan"], C["amber"], C["violet"], C["dark"]] + x0, y0 = Inches(0.72), Inches(1.88) + box_w, gap = Inches(1.82), Inches(0.24) + for i, (title, sub) in enumerate(steps): + x = x0 + i * (box_w + gap) + add_node(slide, x, y0, box_w, Inches(1.04), title, sub, C["white"], colors[i], 12.2) + if i < len(steps) - 1: + add_arrow(slide, x + box_w, y0 + Inches(0.52), x + box_w + gap, y0 + Inches(0.52), C["muted"], 1.1) + code = [ + "CASE ftruncate_readonly_fd ret=-1 errno=22", + "CASE pwritev2_writes_data ret=2 errno=0 read_ret=2 data=5859", + "CASE dup3_same_fd ret=-1 errno=22", + ] + rect = slide.shapes.add_shape(MSO_AUTO_SHAPE_TYPE.ROUNDED_RECTANGLE, Inches(0.84), Inches(3.56), Inches(5.82), Inches(1.66)) + fill_solid(rect, C["dark2"]) + line_solid(rect, RGBColor(64, 78, 96), 0.6) + add_text(slide, Inches(1.06), Inches(3.82), Inches(5.4), Inches(0.84), "\n".join(code), 13, RGBColor(218, 227, 237)) + rv = data["syscall_rv"] + case_count = len(rv.get("linux", {})) + diff_count = len(rv.get("differences", [])) + add_metric(slide, Inches(7.08), Inches(3.42), Inches(2.45), Inches(1.82), str(case_count), "riscv64 cases", C["cyan"], "latest report") + add_metric(slide, Inches(9.82), Inches(3.42), Inches(2.45), Inches(1.82), str(diff_count), "semantic diffs", C["green"], "begin/end marker 正常") + add_text(slide, Inches(1.0), Inches(6.14), Inches(11.3), Inches(0.34), "已验证修复示例:ftruncate_readonly_fd 曾暴露 errno 映射差异,修实现后 rerun discover 验证 riscv64 无差异。", 14, C["dark"], True, align=PP_ALIGN.CENTER) + return slide + + +def slide_qperf_loop(prs): + slide = prs.slides.add_slide(prs.slide_layouts[6]) + set_bg(slide, RGBColor(248, 249, 246)) + add_header_bar(slide, "05") + add_title(slide, "qperf 性能闭环:从采样到可执行修复线索", "profile 结果不是结论本身,而是进入代码审查和 perf-diff 的证据。", "Performance") + steps = [ + ("StarryOS build", "release 默认"), + ("QEMU + plugin", "TCG sampling"), + ("raw samples", "qperf.bin"), + ("analyzer", "resolve symbols"), + ("folded stack", "stack.folded"), + ("flamegraph", "SVG visual"), + ("fix candidates", "rule-based triage"), + ("perf-diff", "before/after"), + ] + x0, y0 = Inches(0.55), Inches(2.05) + for i, (title, sub) in enumerate(steps): + x = x0 + Inches((i % 4) * 3.12) + y = y0 + Inches((i // 4) * 1.82) + color = [C["cyan"], C["blue"], C["amber"], C["green"], C["violet"], C["red"], C["dark"], C["cyan"]][i] + add_node(slide, x, y, Inches(2.42), Inches(0.92), title, sub, C["white"], color, 12.8) + if i % 4 != 3: + add_arrow(slide, x + Inches(2.42), y + Inches(0.46), x + Inches(2.88), y + Inches(0.46), C["muted"], 1.05) + elif i == 3: + add_arrow(slide, x + Inches(1.2), y + Inches(0.92), x + Inches(1.2), y + Inches(1.54), C["muted"], 1.05) + add_card( + slide, + Inches(0.88), + Inches(5.72), + Inches(11.58), + Inches(0.78), + "关键工程增强", + [ + "bounded queue + non-blocking send 降低采样扰动;symbol cache / partial record 容错提升 analyzer 稳定性;SVG/JSON/CSV 同时输出,支持机器解析与人工复核。", + ], + C["amber"], + C["white"], + title_size=13.5, + body_size=11.3, + ) + return slide + + +def slide_code_layout(prs): + slide = prs.slides.add_slide(prs.slide_layouts[6]) + set_bg(slide) + add_header_bar(slide, "06") + add_title(slide, "代码与产物布局:入口清晰,证据可追踪", "代码入口、采样工具、报告目录共同构成可扩展的开发平台。", "Implementation") + rows = [ + ("CLI / MCP / UI", "tools/starry-syscall-harness/", "harness.py, mcp_server.py, ui_server.py, web/*"), + ("Syscall Probe", "tools/starry-syscall-harness/probes/", "syscall_probe.c: 输出稳定 CASE 行"), + ("qperf 工具链", "tools/qperf/", "plugin / profiler / analyzer / flamegraph feature"), + ("xtask 集成", "scripts/axbuild/src/starry/perf.rs", "构建 qperf、StarryOS、QEMU config 与 analyzer"), + ("报告产物", "target/starry-syscall-harness/", "report.json, report.md, hotspots.csv, stack.folded, flamegraph.svg"), + ] + table = slide.shapes.add_table(len(rows) + 1, 3, Inches(0.78), Inches(1.78), Inches(11.78), Inches(3.58)).table + table.columns[0].width = Inches(2.3) + table.columns[1].width = Inches(3.95) + table.columns[2].width = Inches(5.53) + headers = ("模块", "路径", "职责") + for j, h in enumerate(headers): + table_cell(table.cell(0, j), h, 11, C["white"], True, C["dark"], PP_ALIGN.CENTER) + for i, row in enumerate(rows, start=1): + for j, text in enumerate(row): + fill = C["white"] if i % 2 else RGBColor(244, 247, 250) + table_cell(table.cell(i, j), text, 10.2, C["ink"], j == 0, fill) + add_text(slide, Inches(0.96), Inches(5.78), Inches(11.2), Inches(0.56), "设计取舍:agent 面对的是稳定的 harness 接口和结构化报告,不直接依赖临时命令、手写 QEMU 参数或不可复现日志。", 15, C["dark"], True, align=PP_ALIGN.CENTER) + return slide + + +def slide_agent_entries(prs): + slide = prs.slides.add_slide(prs.slide_layouts[6]) + set_bg(slide, RGBColor(247, 248, 252)) + add_header_bar(slide, "07") + add_title(slide, "Agent-facing 能力:CLI、MCP、Skill 与 Local UI 同源", "自动化入口和人工观察入口共享同一套 harness 命令与 artifact。", "Agent Interface") + add_card( + slide, + Inches(0.72), + Inches(1.78), + Inches(3.72), + Inches(4.54), + "MCP tools", + [ + "starry_syscall_doctor", + "starry_syscall_discover", + "starry_perf_profile", + "starry_perf_diff", + "starry_harness_ui_command", + ], + C["cyan"], + C["white"], + title_size=16, + body_size=13, + ) + add_card( + slide, + Inches(4.82), + Inches(1.78), + Inches(3.72), + Inches(4.54), + "Codex skill 约束", + [ + "StarryOS 相关流程必须走 Docker", + "Linux probe 是 syscall 参考基线", + "qperf 结果作为 triage 输入", + "修复后 rerun + targeted clippy", + "不削弱 probe 来隐藏差异", + ], + C["green"], + C["white"], + title_size=16, + body_size=12.2, + ) + add_card( + slide, + Inches(8.92), + Inches(1.78), + Inches(3.72), + Inches(4.54), + "Local Web UI", + [ + "Doctor / discover / perf-profile / perf-diff", + "后台 job 与日志 tail", + "report API 和 artifact API", + "flamegraph 横向滚动展示", + "限制同一时间一个重任务", + ], + C["amber"], + C["white"], + title_size=16, + body_size=12.2, + ) + return slide + + +def slide_trust(prs): + slide = prs.slides.add_slide(prs.slide_layouts[6]) + set_bg(slide) + add_header_bar(slide, "08") + add_title(slide, "可信性设计:让自动化结果可以被审计", "关键不是“能跑”,而是跑出的差异、热点和建议能被复核。", "Reliability") + items = [ + ("环境一致", "StarryOS build / rootfs / QEMU / qperf 全部在 Docker 中执行", C["green"]), + ("稳定输入", "probe 只输出语义字段,避免地址、fd 编号、时间戳和调度时序", C["cyan"]), + ("真实基线", "Linux probe 输出作为参考;差异默认修 StarryOS 实现", C["blue"]), + ("证据优先", "报告、stdout/stderr、qemu.toml、rootfs、flamegraph 全部落盘", C["amber"]), + ("性能克制", "fix candidates 是规则线索,必须结合代码审查和 perf-diff", C["violet"]), + ] + for i, (title, body, color) in enumerate(items): + y = Inches(1.72 + i * 0.88) + dot = slide.shapes.add_shape(MSO_AUTO_SHAPE_TYPE.OVAL, Inches(0.92), y + Inches(0.12), Inches(0.28), Inches(0.28)) + fill_solid(dot, color) + dot.line.fill.background() + add_text(slide, Inches(1.36), y, Inches(2.0), Inches(0.32), title, 16, C["dark"], True) + add_text(slide, Inches(3.22), y + Inches(0.02), Inches(8.9), Inches(0.34), body, 14, C["ink"]) + add_text(slide, Inches(1.0), Inches(6.35), Inches(11.3), Inches(0.32), "输出可信的前提:自动化必须保留足够上下文,让人能质疑、复现和修正。", 15, C["dark"], True, align=PP_ALIGN.CENTER) + return slide + + +def slide_experiment(prs, data): + slide = prs.slides.add_slide(prs.slide_layouts[6]) + set_bg(slide, RGBColor(247, 250, 249)) + add_header_bar(slide, "09") + add_title(slide, "实验与验证:本地 harness 入口可用,latest 报告完整", "本轮执行 doctor 与 perf-diff 自比较;展示数据来自 target/starry-syscall-harness/latest 报告。", "Validation") + perf = data["perf"] + rv = data["syscall_rv"] + x86 = data["syscall_x86"] + samples = perf.get("hotspots", {}).get("total_samples", 0) + flame = perf.get("summary", {}).get("flamegraph_generated", "true") + add_metric(slide, Inches(0.74), Inches(1.82), Inches(2.62), Inches(1.82), "3/3", "doctor checks", C["green"], "Docker / image / tools") + add_metric(slide, Inches(3.62), Inches(1.82), Inches(2.62), Inches(1.82), "0", "syscall diffs", C["cyan"], "riscv64 + x86_64") + add_metric(slide, Inches(6.50), Inches(1.82), Inches(2.62), Inches(1.82), str(samples), "qperf samples", C["amber"], "riscv64, release") + add_metric(slide, Inches(9.38), Inches(1.82), Inches(2.62), Inches(1.82), "OK", "perf-diff entry", C["blue"], "self compare delta 0") + rows = [ + ("riscv64 syscall", len(rv.get("linux", {})), len(rv.get("differences", [])), rv.get("markers", {}).get("starry_end", False)), + ("x86_64 syscall", len(x86.get("linux", {})), len(x86.get("differences", [])), x86.get("markers", {}).get("starry_end", False)), + ("riscv64 qperf", samples, perf.get("result", "unknown"), flame), + ] + table = slide.shapes.add_table(4, 4, Inches(1.22), Inches(4.18), Inches(10.86), Inches(1.42)).table + for j, h in enumerate(("项目", "样本 / case", "结果", "完整性")): + table_cell(table.cell(0, j), h, 10.5, C["white"], True, C["dark"], PP_ALIGN.CENTER) + for i, row in enumerate(rows, start=1): + for j, val in enumerate(row): + table_cell(table.cell(i, j), str(val), 10.4, C["ink"], j == 0, C["white"] if i % 2 else RGBColor(244, 247, 250), PP_ALIGN.CENTER if j else PP_ALIGN.LEFT) + add_text(slide, Inches(0.94), Inches(6.12), Inches(11.5), Inches(0.44), "注意:性能 profile 的 plugin shutdown summary 可能因 timeout 不可用,harness 仍保留 qperf.bin、folded stack、flamegraph 和 report.json。", 12.8, C["muted"], align=PP_ALIGN.CENTER) + return slide + + +def slide_hotspots(prs, data): + slide = prs.slides.add_slide(prs.slide_layouts[6]) + set_bg(slide) + add_header_bar(slide, "10") + add_title(slide, "qperf 结果示例:机器可读热点 + 人可读 flamegraph", "条形图来自 report.json top_functions;底部为实际 flamegraph SVG 转换后的证据图。", "Hotspots") + perf = data["perf"] + funcs = perf.get("hotspots", {}).get("top_functions", [])[:6] + max_pct = max([float(f.get("percent", 0)) for f in funcs] or [1]) + x0, y0 = Inches(0.9), Inches(1.84) + bar_w = Inches(6.7) + for i, f in enumerate(funcs): + name = shorten_func(f.get("function", "")) + pct = float(f.get("percent", 0)) + samples = f.get("samples", 0) + y = y0 + Inches(i * 0.48) + add_text(slide, x0, y - Inches(0.02), Inches(2.7), Inches(0.24), name, 9.8, C["ink"]) + bg = slide.shapes.add_shape(MSO_AUTO_SHAPE_TYPE.RECTANGLE, x0 + Inches(2.9), y, bar_w, Inches(0.20)) + fill_solid(bg, RGBColor(232, 237, 243)) + bg.line.fill.background() + fg_width = max(1, int(round(bar_w * (pct / max_pct)))) + fg = slide.shapes.add_shape(MSO_AUTO_SHAPE_TYPE.RECTANGLE, x0 + Inches(2.9), y, fg_width, Inches(0.20)) + fill_solid(fg, C["amber"] if i == 0 else C["cyan"]) + fg.line.fill.background() + add_text(slide, x0 + Inches(9.72), y - Inches(0.04), Inches(1.25), Inches(0.24), f"{pct:.2f}% / {samples}", 9.6, C["muted"], align=PP_ALIGN.RIGHT) + add_card( + slide, + Inches(8.78), + Inches(1.74), + Inches(3.38), + Inches(2.68), + "解读方式", + [ + "top_functions 用于排序和自动规则匹配", + "flamegraph 用于人工观察栈上下文", + "fix candidates 未越过当前阈值时不强行生成修复建议", + ], + C["amber"], + C["white"], + title_size=14, + body_size=11.1, + ) + panel = ASSET_DIR / "flamegraph-panel.png" + if panel.exists(): + slide.shapes.add_picture(str(panel), Inches(0.74), Inches(4.74), width=Inches(11.86), height=Inches(2.22)) + return slide + + +def slide_completed(prs): + slide = prs.slides.add_slide(prs.slide_layouts[6]) + set_bg(slide, RGBColor(248, 250, 252)) + add_header_bar(slide, "11") + add_title(slide, "已完成工作量:从工具到协作路径的端到端建设", "覆盖 syscall harness、qperf、MCP/UI、skill/文档和 PR 工作流。", "Progress") + cols = [ + ("Syscall Harness", ["Docker re-exec", "Linux/Starry probe", "rootfs 注入", "QEMU config", "CASE diff", "JSON report"], C["cyan"]), + ("qperf Harness", ["plugin/analyzer", "xtask starry perf", "folded stack", "flamegraph SVG", "hotspots.csv", "perf diff"], C["amber"]), + ("Agent Interface", ["MCP tools", "Codex skill", "Local UI", "job logs", "artifact API", "report API"], C["green"]), + ("协作与文档", ["README", "framework doc", "验证命令", "PR evidence", "risk control", "future roadmap"], C["blue"]), + ] + for i, (title, items, color) in enumerate(cols): + x = Inches(0.62 + i * 3.16) + card = slide.shapes.add_shape(MSO_AUTO_SHAPE_TYPE.ROUNDED_RECTANGLE, x, Inches(1.78), Inches(2.82), Inches(4.8)) + fill_solid(card, C["white"]) + line_solid(card, RGBColor(224, 230, 238), 0.8) + top = slide.shapes.add_shape(MSO_AUTO_SHAPE_TYPE.RECTANGLE, x, Inches(1.78), Inches(2.82), Inches(0.12)) + fill_solid(top, color) + top.line.fill.background() + add_text(slide, x + Inches(0.20), Inches(2.08), Inches(2.42), Inches(0.32), title, 14.2, C["dark"], True, align=PP_ALIGN.CENTER) + add_multiline(slide, x + Inches(0.26), Inches(2.62), Inches(2.36), Inches(3.26), items, 11.2, C["ink"], bullet=True, gap=0.72) + return slide + + +def slide_boundaries(prs): + slide = prs.slides.add_slide(prs.slide_layouts[6]) + set_bg(slide) + add_header_bar(slide, "12") + add_title(slide, "当前边界与风险控制:明确能力范围,避免误用", "框架已具备闭环,但仍保留人工审查和持续扩展空间。", "Boundary") + add_card( + slide, + Inches(0.76), + Inches(1.82), + Inches(5.56), + Inches(4.54), + "当前能力边界", + [ + "syscall probe 覆盖仍需继续扩充", + "qperf 主要验证 riscv64,loongarch64 需要更多实测", + "pprof 格式预留,尚未完整支持", + "fix candidates 仍是规则驱动", + "Linux 性能 baseline 还需定义可比 workload", + ], + C["red"], + C["white"], + title_size=17, + body_size=13.3, + ) + add_card( + slide, + Inches(7.02), + Inches(1.82), + Inches(5.56), + Inches(4.54), + "风险控制策略", + [ + "语义差异必须回到 Linux 参考和源码实现", + "性能优化必须有 profile 证据和 rerun 验证", + "Docker 统一环境,减少宿主漂移", + "UI artifact 读取限制在仓库报告目录", + "PR 描述同步列明背景、修改、验证和结果", + ], + C["green"], + C["white"], + title_size=17, + body_size=13.3, + ) + return slide + + +def slide_roadmap(prs): + slide = prs.slides.add_slide(prs.slide_layouts[6]) + set_bg(slide, RGBColor(246, 248, 250)) + add_header_bar(slide, "13") + add_title(slide, "后续路线:让 harness 逐步变成自治开发基础设施", "扩覆盖、强基线、做映射、进 PR,形成持续改进机制。", "Roadmap") + phases = [ + ("1. 扩 syscall 覆盖", "fd lifecycle、signal、poll/epoll、mmap、权限与 errno 顺序", C["cyan"]), + ("2. 差异到代码映射", "case -> syscall 实现文件 -> 常见 errno/flag 修复模板", C["green"]), + ("3. 性能基线体系", "标准 workload、baseline 保存、阈值判断与趋势报告", C["amber"]), + ("4. 可视化增强", "diff flamegraph、热点文件跳转、compare 并排查看", C["blue"]), + ("5. PR 自动化", "自动汇总 discover/profile/diff 结果,生成 PR body 证据段", C["violet"]), + ] + y = Inches(1.78) + for i, (title, body, color) in enumerate(phases): + x = Inches(0.86 + i * 2.45) + circ = slide.shapes.add_shape(MSO_AUTO_SHAPE_TYPE.OVAL, x, y, Inches(0.78), Inches(0.78)) + fill_solid(circ, color) + circ.line.fill.background() + add_text(slide, x, y + Inches(0.18), Inches(0.78), Inches(0.24), str(i + 1), 17, C["white"], True, align=PP_ALIGN.CENTER) + if i < len(phases) - 1: + add_arrow(slide, x + Inches(0.82), y + Inches(0.39), x + Inches(2.1), y + Inches(0.39), C["muted"], 1.0) + add_text(slide, x - Inches(0.32), Inches(2.84), Inches(1.42), Inches(0.42), title, 12.2, C["dark"], True, align=PP_ALIGN.CENTER) + add_text(slide, x - Inches(0.58), Inches(3.44), Inches(1.96), Inches(1.12), body, 10.7, C["muted"], align=PP_ALIGN.CENTER) + add_text(slide, Inches(1.28), Inches(5.72), Inches(10.75), Inches(0.64), "目标状态:agent 接收到差异或热点后,能自动收集证据、定位代码、提出补丁、跑回归、生成 PR 说明;人类负责语义判断和风险审查。", 16, C["dark"], True, align=PP_ALIGN.CENTER) + return slide + + +def slide_conclusion(prs): + slide = prs.slides.add_slide(prs.slide_layouts[6]) + set_bg(slide, C["dark"]) + add_header_bar(slide, "") + add_text(slide, Inches(0.84), Inches(0.86), Inches(9.2), Inches(0.54), "结论", 28, C["white"], True) + add_text(slide, Inches(0.86), Inches(1.48), Inches(9.6), Inches(0.62), "AI-Harness 把 StarryOS 兼容性与性能优化中的“经验流程”固化成可复现、可审计、可扩展的工程接口。", 18, RGBColor(220, 230, 240)) + takeaways = [ + ("可复现", "Docker re-exec + 结构化 artifact"), + ("可审计", "Linux 基线 + JSON/CSV/SVG 证据"), + ("可扩展", "CLI/MCP/UI/Skill 同源入口"), + ] + for i, (t, b) in enumerate(takeaways): + x = Inches(1.0 + i * 4.05) + rect = slide.shapes.add_shape(MSO_AUTO_SHAPE_TYPE.ROUNDED_RECTANGLE, x, Inches(3.0), Inches(3.18), Inches(1.72)) + fill_solid(rect, RGBColor(33, 43, 56), 0) + line_solid(rect, RGBColor(77, 92, 112), 0.8) + add_text(slide, x, Inches(3.34), Inches(3.18), Inches(0.40), t, 22, C["white"], True, align=PP_ALIGN.CENTER) + add_text(slide, x + Inches(0.24), Inches(4.04), Inches(2.70), Inches(0.38), b, 12.5, RGBColor(190, 204, 218), align=PP_ALIGN.CENTER) + add_text(slide, Inches(0.88), Inches(6.40), Inches(3.8), Inches(0.26), "谢谢", 18, C["amber"], True) + return slide + + +def slide_appendix(prs): + slide = prs.slides.add_slide(prs.slide_layouts[6]) + set_bg(slide) + add_header_bar(slide, "Appendix") + add_title(slide, "附录:本次 PPT 使用的命令与产物路径", None, "Evidence") + lines = [ + "任务一来源:cg24-THU/tg-arceos-tutorial test 分支", + "exercise-printcolor / exercise-hashmap / exercise-altalloc / exercise-ramfs-rename / exercise-sysmap", + "代表性运行:docker run ... -w /work/exercise-printcolor ... cargo xtask run --arch riscv64", + "python3 tools/starry-syscall-harness/harness.py doctor", + "python3 tools/starry-syscall-harness/harness.py perf-diff --baseline target/starry-syscall-harness/perf/riscv64/latest --compare target/starry-syscall-harness/perf/riscv64/latest --top 8", + "docs/ai-harness-development-framework.md", + "tools/starry-syscall-harness/harness.py", + "tools/starry-syscall-harness/mcp_server.py", + "tools/starry-syscall-harness/ui_server.py", + "scripts/axbuild/src/starry/perf.rs", + "target/starry-syscall-harness/riscv64/latest/report.json", + "target/starry-syscall-harness/x86_64/latest/report.json", + "target/starry-syscall-harness/perf/riscv64/latest/report.json", + "target/starry-syscall-harness/perf/riscv64/latest/qperf/flamegraph.svg", + ] + rect = slide.shapes.add_shape(MSO_AUTO_SHAPE_TYPE.ROUNDED_RECTANGLE, Inches(0.78), Inches(1.72), Inches(11.82), Inches(4.86)) + fill_solid(rect, C["dark2"]) + line_solid(rect, RGBColor(64, 78, 96), 0.7) + add_multiline(slide, Inches(1.02), Inches(1.98), Inches(11.26), Inches(4.22), lines, 10.5, RGBColor(220, 230, 240), bullet=False, gap=0.48) + return slide + + +def build() -> None: + ensure_assets() + data = load_data() + prs = Presentation() + prs.slide_width = SLIDE_W + prs.slide_height = SLIDE_H + prs.core_properties.title = "AI-Harness 答辩汇报" + prs.core_properties.subject = "StarryOS Syscall 与 qperf 自治开发框架" + prs.core_properties.author = "TGOSKits" + + slide_builders = [ + lambda: slide_cover(prs, data), + lambda: slide_answer_structure(prs), + lambda: slide_task1_overview(prs), + lambda: slide_task1_path(prs), + lambda: slide_task1_no_std(prs), + lambda: slide_task1_allocator_fs(prs), + lambda: slide_task1_sysmap(prs), + lambda: slide_task1_validation(prs), + lambda: slide_problem(prs), + lambda: slide_goals(prs), + lambda: slide_architecture(prs), + lambda: slide_syscall_loop(prs, data), + lambda: slide_qperf_loop(prs), + lambda: slide_code_layout(prs), + lambda: slide_agent_entries(prs), + lambda: slide_trust(prs), + lambda: slide_experiment(prs, data), + lambda: slide_hotspots(prs, data), + lambda: slide_completed(prs), + lambda: slide_boundaries(prs), + lambda: slide_roadmap(prs), + lambda: slide_conclusion(prs), + lambda: slide_appendix(prs), + ] + + slides = [builder() for builder in slide_builders] + total = len(slides) + for idx, slide in enumerate(slides[1:-1], start=2): + add_footer(slide, idx, total) + add_footer(slides[-1], total, total) + + OUT_DIR.mkdir(parents=True, exist_ok=True) + prs.save(OUT) + print(OUT) + + +if __name__ == "__main__": + build() diff --git a/components/rsext4/src/cache/data_block.rs b/components/rsext4/src/cache/data_block.rs index c09e83a03d..431a654343 100644 --- a/components/rsext4/src/cache/data_block.rs +++ b/components/rsext4/src/cache/data_block.rs @@ -6,6 +6,8 @@ use crate::{blockdev::*, bmalloc::AbsoluteBN, config::*, error::*}; /// Cache key for one physical data block. pub type BlockCacheKey = AbsoluteBN; +const DATA_BLOCK_READAHEAD: u32 = 8; + /// Cached data block. #[derive(Debug, Clone)] pub struct CachedBlock { @@ -74,6 +76,63 @@ impl DataBlockCache { Ok(buffer.to_vec()) } + fn readahead_count( + &self, + block_dev: &Jbd2Dev, + block_num: AbsoluteBN, + ) -> Ext4Result { + let total_blocks = block_dev.total_blocks(); + if block_num.raw() >= total_blocks { + return Ok(1); + } + + let remaining = total_blocks - block_num.raw(); + let limit = DATA_BLOCK_READAHEAD + .min(u32::try_from(self.max_entries.max(1)).unwrap_or(u32::MAX)) + .min(u32::try_from(remaining).unwrap_or(u32::MAX)); + let mut count = 1; + while count < limit { + let next = block_num.checked_add(count)?; + if self.cache.contains_key(&next) { + break; + } + count += 1; + } + Ok(count) + } + + fn load_readahead( + &mut self, + block_dev: &mut Jbd2Dev, + block_num: AbsoluteBN, + ) -> Ext4Result<()> { + let count = self.readahead_count(block_dev, block_num)?; + if count <= 1 { + let data = self.load_block(block_dev, block_num)?; + self.cache + .insert(block_num, CachedBlock::new(data, block_num)); + return Ok(()); + } + + while self.cache.len() + count as usize > self.max_entries { + self.evict_lru(block_dev)?; + } + + let mut data = alloc::vec![0u8; self.block_size * count as usize]; + block_dev.read_blocks(&mut data, block_num, count)?; + + for idx in 0..count { + let cached_block = block_num.checked_add(idx)?; + let start = idx as usize * self.block_size; + let end = start + self.block_size; + self.cache.insert( + cached_block, + CachedBlock::new(data[start..end].to_vec(), cached_block), + ); + } + Ok(()) + } + /// Returns a cached block, loading it from disk on demand. pub fn get_or_load( &mut self, @@ -86,9 +145,7 @@ impl DataBlockCache { self.evict_lru(block_dev)?; } - let data = self.load_block(block_dev, block_num)?; - let cached = CachedBlock::new(data, block_num); - self.cache.insert(block_num, cached); + self.load_readahead(block_dev, block_num)?; } // Refresh the LRU timestamp on every access. diff --git a/docs/ai-harness-development-framework.md b/docs/ai-harness-development-framework.md new file mode 100644 index 0000000000..b9bcc121fd --- /dev/null +++ b/docs/ai-harness-development-framework.md @@ -0,0 +1,1008 @@ +# 基于 AI 的 StarryOS Syscall 与 qperf 自治开发框架说明 + +## 1. 文档目的 + +本文档说明当前在 TGOSKits 仓库中构建的 StarryOS 自治开发 harness。该框架面向两个长期目标: + +1. 让智能开发代理能够自动发现 StarryOS 与 Linux 标准语义之间的 syscall 行为差异,并生成可复现、可审计的差异报告。 +2. 让智能开发代理能够围绕 qperf 性能画像自动定位 StarryOS 热点路径,形成性能分析、可视化、报告生成、瓶颈修复建议和回归验证的闭环。 + +该框架不是单个测试脚本,而是一套面向代理自动化和人工交互的工作平台。它包含 CLI harness、MCP 工具、Codex skill、本地 Web UI、Docker 隔离执行、结构化报告、qperf flamegraph、热点规则和 PR 工作流约束。 + +本文档重点展示框架设计、已完成工作量、自动化能力边界、可信性保障和后续演进方向,可作为评审、汇报、交接和继续扩展的基础材料。 + +## 2. 背景与问题 + +StarryOS 作为 Linux 兼容目标,需要长期面对两类复杂问题。 + +第一类是 syscall 语义兼容问题。单个 syscall 的错误返回值、errno、边界条件、文件描述符状态或 flag 校验顺序只要与 Linux 标准行为不一致,就可能导致上层应用异常。这类问题通常有以下特点: + +- 问题粒度细,人工 review 难以覆盖全部边界条件。 +- 行为差异往往只在特定参数组合下出现。 +- 单纯看源码不一定能判断 Linux 真实行为。 +- 修复后需要重新对拍验证,避免通过修改测试掩盖问题。 + +第二类是性能问题。StarryOS 性能优化不能只依靠直觉或局部代码审查,需要能够回答以下问题: + +- 当前 StarryOS 运行时热点实际集中在哪里。 +- VirtIO、内存映射、调度、锁、copy 路径是否占据异常比例。 +- 优化前后热点是否真的下降。 +- 是否有可保存、可比较、可视化的证据。 + +因此,开发框架必须将“发现问题、生成证据、定位代码、提出修复、验证回归、形成 PR”串联为可重复执行的闭环,而不是依赖一次性命令。 + +## 3. 设计目标 + +### 3.1 自动化目标 + +框架支持智能代理默认通过 CLI/MCP 自动调用,不依赖人工点击页面即可完成批量扫描、性能采样和报告读取。 + +核心自动化能力包括: + +- 自动检查 Docker 镜像和工具链是否可用。 +- 自动编译 Linux 侧 syscall probe。 +- 自动编译目标架构 StarryOS probe。 +- 自动构建 StarryOS rootfs。 +- 自动将 probe 注入 rootfs。 +- 自动启动 StarryOS QEMU。 +- 自动解析 Linux 与 StarryOS 输出。 +- 自动生成 JSON/Markdown/CSV 报告。 +- 自动运行 qperf TCG plugin 采样。 +- 自动解析 qperf raw samples 为 folded stack。 +- 自动生成 flamegraph SVG。 +- 自动提取 top functions、top stacks 和 fix candidates。 +- 自动比较两次 profile 的热点变化。 +- 自动将结果暴露给 MCP 客户端。 + +### 3.2 可信性目标 + +框架不能为了“自动化”降低结果可信度。设计上遵循以下原则: + +- Linux probe 输出作为 syscall 语义参考基线。 +- StarryOS 构建、rootfs、QEMU、qperf 相关流程必须在 Docker 中执行。 +- probe 输出采用稳定 key-value 格式,避免 fd 编号、时间戳、地址、调度时序等非确定信息进入比较。 +- syscall 修复必须修实现,不通过削弱 probe 或忽略差异来通过测试。 +- qperf 结果作为性能优化证据,而不是直接替代代码审查。 +- 性能 fix candidates 是规则辅助,不是自动套用补丁。 +- 所有报告产物都落盘,便于复核和 PR 说明。 + +### 3.3 交互目标 + +默认路径面向智能代理自动调用;同时提供本地浏览器 UI,便于人工交互式查看和触发任务。 + +UI 支持: + +- Doctor 检查。 +- syscall 扫描与修复上下文查看。 +- qperf 性能分析。 +- flamegraph 查看。 +- perf diff 比较。 +- 后台任务日志跟踪。 +- 已生成报告和 artifact 读取。 + +### 3.4 PR 工作流目标 + +框架服务于真实项目协作,因此 PR 流程必须可审计: + +- 提交 PR 前对齐 upstream 目标分支。 +- 在干净分支上提交修复。 +- PR 描述中列明背景、修改、验证命令和关键结果。 +- 对 StarryOS 相关构建测试坚持 Docker 执行。 +- 对 Rust 逻辑变更运行 targeted clippy。 + +## 4. 总体架构 + +框架由六层组成: + +```text +┌──────────────────────────────────────────────────────────────┐ +│ Agent / Human Operator │ +│ - MCP 自动调用 │ +│ - CLI 直接调用 │ +│ - Local Web UI 交互调用 │ +└───────────────────────────────┬──────────────────────────────┘ + │ +┌───────────────────────────────▼──────────────────────────────┐ +│ Harness Entry Points │ +│ tools/starry-syscall-harness/harness.py │ +│ tools/starry-syscall-harness/mcp_server.py │ +│ tools/starry-syscall-harness/ui_server.py │ +└───────────────────────────────┬──────────────────────────────┘ + │ +┌───────────────────────────────▼──────────────────────────────┐ +│ Docker Execution Boundary │ +│ ghcr.io/rcore-os/tgoskits-container:latest │ +│ StarryOS build / rootfs / QEMU / qperf all run inside Docker │ +└───────────────────────────────┬──────────────────────────────┘ + │ +┌───────────────────────────────▼──────────────────────────────┐ +│ Syscall Differential Engine │ +│ Linux probe vs StarryOS probe │ +│ report.json: cases, differences, markers, artifacts │ +└───────────────────────────────┬──────────────────────────────┘ + │ +┌───────────────────────────────▼──────────────────────────────┐ +│ qperf Performance Engine │ +│ qperf plugin / analyzer / folded stack / flamegraph / diff │ +└───────────────────────────────┬──────────────────────────────┘ + │ +┌───────────────────────────────▼──────────────────────────────┐ +│ Reports And Feedback │ +│ JSON / Markdown / CSV / SVG / logs / PR validation evidence │ +└──────────────────────────────────────────────────────────────┘ +``` + +这种架构的关键点是:agent 不直接拼接复杂 StarryOS 构建命令,也不直接操作 QEMU。agent 通过 harness 的稳定接口发起任务,由 harness 负责参数规范化、Docker 重入、输出目录管理、报告生成和 artifact 回收。 + +## 5. 代码与产物布局 + +### 5.1 Harness 主目录 + +```text +tools/starry-syscall-harness/ + README.md + harness.py + mcp_server.py + ui_server.py + probes/ + syscall_probe.c + web/ + index.html + styles.css + app.js +``` + +各文件职责如下: + +| 文件 | 职责 | +|---|---| +| `harness.py` | CLI 主入口,提供 doctor、discover、perf-profile、perf-diff、ui 子命令 | +| `mcp_server.py` | MCP server,将 harness 能力暴露为智能代理可调用工具 | +| `ui_server.py` | 本地 HTTP server,提供任务 API、报告 API、artifact 文件读取 | +| `probes/syscall_probe.c` | syscall 对拍 probe,输出稳定 `CASE` 行 | +| `web/index.html` | 本地 UI 页面结构 | +| `web/styles.css` | 本地 UI 视觉布局 | +| `web/app.js` | 本地 UI 调用 API、轮询任务、渲染报告和 flamegraph | +| `README.md` | harness 使用说明 | + +### 5.2 qperf 相关目录 + +```text +tools/qperf/ + Cargo.toml + src/ + profiler.rs + reg.rs + analyzer/ + Cargo.toml + src/main.rs +``` + +qperf 集成还涉及: + +```text +scripts/axbuild/src/starry/perf.rs +``` + +该文件将 qperf plugin/analyzer 构建、StarryOS 构建、rootfs 准备、QEMU 运行、raw sample 分析和 flamegraph 输出接入 `cargo xtask starry perf`。 + +### 5.3 报告目录 + +默认报告目录为: + +```text +target/starry-syscall-harness/ +``` + +syscall 扫描产物: + +```text +target/starry-syscall-harness//latest/ + report.json + linux.stdout + linux.stderr + starry.stdout + starry.stderr + qemu.toml + rootfs--probe.img +``` + +qperf 性能产物: + +```text +target/starry-syscall-harness/perf//latest/ + report.json + report.md + hotspots.csv + profile.stdout + profile.stderr + qperf/ + qemu.toml + qperf.bin + stack.folded + flamegraph.svg + summary.txt +``` + +perf diff 产物: + +```text +target/starry-syscall-harness/perf-diff/ + report.json +``` + +UI 任务日志: + +```text +target/starry-syscall-harness/ui/jobs/.log +``` + +## 6. CLI 能力 + +### 6.1 Doctor + +```bash +python3 tools/starry-syscall-harness/harness.py doctor +``` + +Doctor 用于确认当前环境是否具备运行 harness 的基本条件。它检查: + +- Docker 命令是否可用。 +- 默认镜像是否存在。 +- 容器内是否具备 `debugfs`、交叉编译器、QEMU 和 Cargo。 + +输出为 JSON,便于 agent 解析。 + +### 6.2 Syscall Discover + +```bash +python3 tools/starry-syscall-harness/harness.py discover --arch riscv64 +``` + +该命令完成 Linux-vs-StarryOS syscall 对拍。默认情况下,如果命令在宿主机执行,会自动重入 Docker,Docker 内再执行真实 StarryOS 构建、rootfs 和 QEMU 流程。 + +支持架构: + +- `riscv64` +- `aarch64` +- `loongarch64` +- `x86_64` + +关键参数: + +| 参数 | 作用 | +|---|---| +| `--arch` | 目标架构 | +| `--timeout` | QEMU probe 超时 | +| `--fail-on-diff` | 如果发现语义差异则返回失败 | +| `--output-dir` | 报告输出目录 | + +### 6.3 qperf Profile + +```bash +python3 tools/starry-syscall-harness/harness.py perf-profile --arch riscv64 --timeout 20 --format all +``` + +该命令执行 StarryOS qperf profile,并生成结构化性能报告。 + +支持架构: + +- `riscv64` +- `loongarch64` + +关键参数: + +| 参数 | 作用 | +|---|---| +| `--format folded` | 只生成 folded stack | +| `--format svg` | 生成 SVG flamegraph | +| `--format all` | 生成 folded stack、报告和 SVG | +| `--freq` | 采样频率 | +| `--max-depth` | 最大栈深 | +| `--mode tb` | 以 QEMU translation block 维度采样 | +| `--mode insn` | 以指令维度采样 | +| `--top` | 报告中展示的热点数量 | +| `--min-percent` | fix candidate 阈值 | +| `--debug` | 使用 debug build,便于符号分析 | +| `--kernel-filter` | 仅保留检测到的 kernel `.text` 范围样本 | + +### 6.4 perf-diff + +```bash +python3 tools/starry-syscall-harness/harness.py perf-diff \ + --baseline target/starry-syscall-harness/perf/riscv64/baseline \ + --compare target/starry-syscall-harness/perf/riscv64/latest +``` + +该命令用于比较两次 profile 的 folded stack,输出热点函数百分比变化,用于验证优化是否有效。 + +### 6.5 Local UI + +```bash +python3 tools/starry-syscall-harness/harness.py ui --host 127.0.0.1 --port 8765 --open +``` + +UI 是可选入口。默认自动化仍建议 agent 走 CLI/MCP;当需要人工观察报告、查看 flamegraph 或手动触发任务时启动 UI。 + +## 7. Syscall 语义对拍闭环 + +### 7.1 Probe 输出规范 + +syscall probe 使用 C 编写,输出形如: + +```text +CASE ftruncate_readonly_fd ret=-1 errno=22 +CASE pwritev2_writes_data ret=2 errno=0 read_ret=2 read_errno=0 data=5859 +``` + +格式设计要点: + +- 每个 case 单独一行。 +- 使用 `CASE key=value ...`。 +- 不输出随机地址、时间戳、fd 编号等不稳定数据。 +- 只输出与语义判断有关的字段。 +- Linux 与 StarryOS 侧使用同一份 probe 源码。 + +### 7.2 Linux 基线 + +host Linux 执行 probe,产生参考输出: + +```text +linux.stdout +linux.stderr +``` + +除非某个 case 明确记录为架构差异,否则 Linux 输出即为目标语义。 + +### 7.3 StarryOS 执行 + +harness 在 Docker 内完成: + +1. 使用目标架构交叉编译 probe。 +2. 通过 `cargo xtask starry rootfs` 准备 rootfs。 +3. 使用 `debugfs` 将 probe 注入 rootfs。 +4. 写入专用 QEMU config。 +5. 通过 `cargo xtask starry qemu` 启动 StarryOS。 +6. 捕获 StarryOS 输出。 +7. 解析 `CASE` 行并与 Linux 输出比较。 + +### 7.4 差异报告 + +`report.json` 包含: + +```json +{ + "arch": "riscv64", + "linux": {}, + "starry": {}, + "differences": [], + "markers": { + "starry_begin": true, + "starry_end": true + }, + "artifacts": {} +} +``` + +字段含义: + +| 字段 | 含义 | +|---|---| +| `linux` | Linux probe 结果 | +| `starry` | StarryOS probe 结果 | +| `differences` | 两边不一致的 case | +| `markers` | StarryOS probe 是否完整启动和结束 | +| `artifacts` | rootfs、qemu config、报告路径 | + +### 7.5 已验证修复示例 + +框架已经发现并驱动修复了一个实际 syscall 语义差异: + +- case:`ftruncate_readonly_fd` +- 问题:只读普通文件 fd 上执行 `ftruncate` 时 errno 与 Linux 不一致。 +- 修复:调整 `sys_ftruncate` 对只读普通文件 fd 的 errno 映射,同时保留 `O_PATH` fd 的 `EBADF` 行为。 +- 验证:重新运行 syscall discover 后,riscv64 报告无语义差异,StarryOS begin/end marker 均正常。 + +该示例说明 harness 不是只生成测试框架,而是已经完成了“发现问题 -> 定位语义 -> 修复实现 -> 回归验证”的完整闭环。 + +## 8. qperf 性能分析闭环 + +### 8.1 qperf 接入目标 + +qperf 集成目标不是简单生成一个 profile 文件,而是为 agent 提供可解析、可比较、可视化、可转化为修复任务的性能证据。 + +完整路径如下: + +```text +StarryOS build + -> rootfs ready + -> QEMU with qperf plugin + -> qperf.bin raw samples + -> qperf-analyzer resolve + -> stack.folded + -> flamegraph.svg + -> report.json / report.md / hotspots.csv + -> fix candidates + -> code inspection and optimization + -> rerun profile + -> perf-diff +``` + +### 8.2 qperf plugin 改造 + +qperf plugin 侧围绕稳定性和长期自动化做了增强: + +- 使用 bounded queue,避免 writer backlog 无界增长。 +- QEMU 执行路径使用 non-blocking send,降低采样对 guest 执行的扰动。 +- 支持 `max_depth` 限制栈展开深度。 +- frame pointer unwind 增加边界检查。 +- 采样失败不 panic,计入失败统计。 +- 使用 buffered writer 写 raw samples。 +- 支持 TB/insn 两种采样模式。 +- 支持 kernel text range 过滤参数。 +- 支持物理地址 alias 映射,将 QEMU callback 中的物理地址样本映射回 ELF 虚拟地址。 +- timeout 结束时尽量保留已采集样本。 + +### 8.3 qperf analyzer 改造 + +analyzer 侧围绕自动报告和可视化做了增强: + +- 解析 qperf raw sample,输出 folded stack。 +- 支持 symbol cache,减少重复地址解析成本。 +- 支持 symtab fallback,DWARF 信息不足时仍尽量给出符号。 +- 对 trailing partial record 容错,避免 timeout 截断导致整次分析失败。 +- 输出 top hottest functions。 +- 支持 diff 模式,比较两份 folded stack。 +- 支持内置 inferno flamegraph feature,`--format all/svg` 时不依赖容器额外安装外部 flamegraph 命令。 +- flamegraph 生成参数已优化为更宽画布、更高 frame、稳定 hash 配色,提升可读性。 + +### 8.4 Flamegraph 可视化优化 + +当前 flamegraph 生成配置: + +```text +title = "StarryOS qperf Flame Graph" +image_width = 3200 +frame_height = 24 +font_size = 13 +min_width = 0.35 +hash = true +deterministic = true +``` + +这样做的目的: + +- 固定宽画布避免热点块挤压在窄面板中。 +- 更高 frame 让多层栈更容易辨认。 +- 更低 `min_width` 保留更多小热点。 +- hash 配色让相邻函数块更容易区分。 +- deterministic 保证不同运行之间颜色更稳定,便于比较。 + +UI 侧也做了配套优化: + +- flamegraph iframe 不再强行压缩到面板宽度。 +- 外层容器支持横向滚动。 +- 前端读取 SVG `width` / `height`,动态调整 iframe 尺寸。 +- 如果 SVG 没有生成,页面显示具体原因,而不是只显示空白。 + +### 8.5 性能报告结构 + +`perf-profile` 生成的 `report.json` 包含: + +```json +{ + "arch": "riscv64", + "result": "ok", + "parameters": {}, + "hotspots": { + "total_samples": 350, + "top_functions": [], + "top_stacks": [] + }, + "summary": {}, + "plugin_summary": {}, + "fix_candidates": [], + "linux_alignment": {}, + "artifacts": {} +} +``` + +核心字段说明: + +| 字段 | 说明 | +|---|---| +| `result` | `ok` 或 `incomplete` | +| `parameters` | profile 参数,便于复现 | +| `hotspots.total_samples` | 样本数 | +| `hotspots.top_functions` | 函数维度热点 | +| `hotspots.top_stacks` | 栈维度热点 | +| `summary` | qperf summary 信息 | +| `plugin_summary` | plugin 侧统计,timeout 时可能不可用 | +| `fix_candidates` | 规则推导的优化候选 | +| `linux_alignment` | 后续与 Linux baseline 或优化前 baseline 对齐的入口 | +| `artifacts` | folded stack、SVG、Markdown、CSV 等路径 | + +### 8.6 Fix Candidate 规则 + +当前实现了一组规则化的性能修复候选,用于把热点函数映射到可能的代码区域和优化策略。 + +示例规则类型: + +- `virtio_vsock_locking` +- `virtio_net_shared_state` +- `virtio_block_sync_queue` +- `lock_contention` +- `copy_overhead` + +候选输出包含: + +```json +{ + "id": "copy_overhead", + "trigger": "...memcpy...", + "samples": 4, + "percent": 1.14, + "files": [], + "strategy": "Inspect repeated buffer copies..." +} +``` + +该能力对 agent 很重要,因为它把“采样结果”转化成“下一步代码审查方向”,降低从性能数据到修复任务之间的语义鸿沟。 + +## 9. MCP 集成 + +MCP server 位于: + +```text +tools/starry-syscall-harness/mcp_server.py +``` + +注册命令: + +```bash +codex mcp add starry-syscall-harness -- \ + python3 /home/cg24/tgoskits/tools/starry-syscall-harness/mcp_server.py \ + --repo /home/cg24/tgoskits +``` + +当前 MCP tools: + +| Tool | 功能 | +|---|---| +| `starry_syscall_doctor` | 检查 Docker、镜像和容器工具链 | +| `starry_syscall_discover` | 运行 syscall Linux-vs-StarryOS 对拍 | +| `starry_perf_profile` | 运行 qperf profile 并返回报告 | +| `starry_perf_diff` | 比较两次 profile | +| `starry_harness_ui_command` | 返回本地 UI 启动命令 | + +MCP 层的价值在于:agent 不需要知道底层命令细节,只需选择工具并传入结构化参数,即可触发完整流程。 + +## 10. Codex Skill 集成 + +本地 skill 位于: + +```text +/home/cg24/.codex/skills/starry-syscall-harness/SKILL.md +``` + +skill 记录了 agent 在使用 harness 时必须遵守的行为约束: + +- StarryOS 构建、rootfs、QEMU、syscall probe、qperf profile 均通过 Docker 执行。 +- syscall 语义以 Linux probe 输出为参考。 +- qperf 热点和 fix candidates 只作为 triage 输入。 +- 修复必须改实现,不削弱 probe。 +- 性能优化必须 rerun profile,并结合 perf-diff 验证。 +- 本地 UI 只作为可选交互入口,默认自动化路径仍是 CLI/MCP。 + +Skill 的作用不是提供代码,而是把项目经验固化为 agent 的操作准则,降低未来自动化执行时误用命令、绕过 Docker 或错误解释报告的风险。 + +## 11. 本地 Web UI + +### 11.1 启动方式 + +```bash +python3 tools/starry-syscall-harness/harness.py ui --host 127.0.0.1 --port 8765 --open +``` + +默认绑定 `127.0.0.1`,避免把本地任务 API 暴露到网络。 + +### 11.2 API 设计 + +UI server 使用 Python 标准库实现,无 Node runtime 依赖。 + +核心 endpoint: + +| Endpoint | 方法 | 功能 | +|---|---|---| +| `/` | GET | 静态 UI | +| `/api/status` | GET | repo、镜像、报告、任务状态 | +| `/api/jobs` | POST | 启动后台任务 | +| `/api/jobs/` | GET | 查询任务状态和日志 | +| `/api/report?kind=...` | GET | 读取 syscall/perf/perf-diff 报告 | +| `/api/file?path=...` | GET | 读取 harness artifact 文件 | + +### 11.3 后台任务模型 + +UI 后台任务支持: + +- `doctor` +- `discover` +- `perf-profile` +- `perf-diff` + +每次任务会生成: + +- job id +- command +- status +- returncode +- duration +- output tail +- log file +- report path + +为了避免多个重型 StarryOS/QEMU 任务并发抢占资源,UI 当前限制同一时间只运行一个 active job。 + +### 11.4 Artifact 安全边界 + +UI 文件读取做了路径限制: + +- 只允许读取仓库内路径。 +- 只允许读取 harness artifact 根目录下的文件。 +- Docker 内报告常见的 `/work/...` 路径会映射回宿主机 repo root。 +- 非文件或越界路径会拒绝。 + +这保证 UI 能读取 Docker 生成的报告,同时不会成为任意文件读取接口。 + +## 12. Docker 执行模型 + +所有 StarryOS 相关测试都必须在 Docker 中完成。harness 的 Docker re-exec 模型如下: + +1. 用户或 agent 在宿主机运行 harness。 +2. harness 检查当前是否在 Docker 内。 +3. 如果不在 Docker 内,自动执行: + +```bash +docker run --rm \ + -v "$repo_root:/work" \ + -w /work \ + -e STARRY_SYSCALL_HARNESS_IN_DOCKER=1 \ + ghcr.io/rcore-os/tgoskits-container:latest \ + bash -lc 'python3 tools/starry-syscall-harness/harness.py "$@" ...' +``` + +4. Docker 内执行真实 StarryOS 构建、rootfs、QEMU 或 qperf。 +5. 任务结束后 chown artifact,避免宿主机留下 root-owned 文件。 + +这种设计同时满足: + +- 环境一致性。 +- StarryOS 运行隔离。 +- agent 命令简洁。 +- artifact 可在宿主机读取。 +- 不在本地裸跑 StarryOS 测试。 + +## 13. 自动修复工作流 + +### 13.1 Syscall 修复闭环 + +推荐 agent 工作流: + +```text +doctor + -> discover + -> read report.json + -> inspect differences + -> locate syscall implementation + -> patch implementation + -> cargo fmt + -> Docker clippy for changed crate + -> discover rerun + -> commit + -> rebase upstream/dev + -> push PR branch +``` + +关键约束: + +- `differences` 必须有明确 Linux 参考。 +- 修复应限制在对应 syscall 或参数校验路径。 +- 不应把 probe 改成 StarryOS 当前行为。 +- rerun discover 后才能认为修复完成。 + +### 13.2 性能优化闭环 + +推荐 agent 工作流: + +```text +perf-profile baseline + -> read report.json/report.md/flamegraph.svg + -> inspect top functions/top stacks/fix candidates + -> inspect code path + -> patch suspected bottleneck + -> cargo fmt + -> Docker clippy for changed crate + -> perf-profile compare + -> perf-diff baseline compare + -> decide whether improvement is real + -> commit + -> update PR evidence +``` + +关键约束: + +- 性能修复必须由样本支持。 +- fix candidate 只是线索,不能替代代码审查。 +- 优化前后必须保留 folded stack 或 report 作为比较依据。 +- Flamegraph 用于视觉定位,JSON/CSV 用于机器解析。 + +## 14. PR 自动化与仓库协作 + +框架已按真实 PR 流程验证: + +- 目标仓库:`rcore-os/tgoskits` +- 目标分支:`dev` +- 工作分支:`fix/starry-syscall-harness` +- PR:`feat(starry): add syscall and qperf harness` + +PR 准则: + +- 提交前 fetch upstream。 +- 在本地分支 rebase 到 `upstream/dev`。 +- 使用 `--force-with-lease` 更新已存在 PR 分支。 +- PR 描述包含背景、修改、验证命令和关键结果。 +- 对 GitHub CLI GraphQL 兼容问题,改用 REST issue API 更新 PR body。 + +这种流程说明框架不是停留在本地实验,而是已经接入真实开源协作路径。 + +## 15. 已完成工作清单 + +### 15.1 Syscall Harness + +- 建立 `tools/starry-syscall-harness/harness.py`。 +- 实现 Docker re-exec。 +- 实现 Doctor 检查。 +- 实现 Linux probe 编译与运行。 +- 实现 StarryOS probe 交叉编译。 +- 实现 rootfs 准备。 +- 实现 debugfs probe 注入。 +- 实现 QEMU config 生成。 +- 实现 StarryOS QEMU 运行与输出捕获。 +- 实现 ANSI 清理、CASE 解析和差异比较。 +- 实现 syscall report JSON。 +- 实现 `--fail-on-diff`。 +- 实现多架构入口。 +- 使用 harness 发现并修复 `ftruncate_readonly_fd` 差异。 + +### 15.2 qperf Performance Harness + +- 将 qperf plugin/analyzer 纳入仓库工具链。 +- 接入 `cargo xtask starry perf`。 +- 支持 TB/insn 采样模式。 +- 支持 `--freq`。 +- 支持 `--max-depth`。 +- 支持 `--timeout`。 +- 支持 release/debug build。 +- 支持 kernel text range 检测。 +- 支持物理地址 alias 映射。 +- 支持 broad sampling 默认策略。 +- 支持 optional kernel filter。 +- 支持 folded stack 输出。 +- 支持 flamegraph SVG 输出。 +- 修复 analyzer flamegraph feature 构建问题。 +- 优化 flamegraph 可读性。 +- 生成 `report.json`。 +- 生成 `report.md`。 +- 生成 `hotspots.csv`。 +- 生成 fix candidates。 +- 实现 perf diff。 + +### 15.3 MCP + +- 实现 MCP initialize。 +- 实现 tools/list。 +- 实现 tools/call。 +- 暴露 syscall doctor。 +- 暴露 syscall discover。 +- 暴露 qperf profile。 +- 暴露 perf diff。 +- 暴露 UI launch command。 +- 完成本地 MCP 注册验证。 + +### 15.4 Local UI + +- 实现 `harness.py ui` 子命令。 +- 实现 Python 标准库 HTTP server。 +- 实现任务 API。 +- 实现报告 API。 +- 实现 artifact 文件 API。 +- 实现后台 job 线程。 +- 实现 job 日志落盘。 +- 实现 active job 防并发。 +- 实现 `/work/...` Docker artifact 路径映射。 +- 实现 syscall 页面。 +- 实现 qperf 页面。 +- 实现 perf diff 页面。 +- 实现 job log 页面。 +- 实现 flamegraph iframe 展示。 +- 实现 flamegraph 空状态诊断。 +- 实现 flamegraph 动态宽高和横向滚动。 + +### 15.5 Skill 与文档 + +- 创建本地 `starry-syscall-harness` skill。 +- 记录 Docker 约束。 +- 记录 syscall 工作流。 +- 记录 performance 工作流。 +- 记录 MCP 注册方法。 +- 记录 UI 使用方法。 +- 增加 harness README。 +- 增加项目 docs 中 syscall/performance harness 说明。 +- 增加本文档,用于描述整体 AI 开发框架。 + +## 16. 验证记录 + +已执行过的关键验证包括: + +```bash +python3 -m py_compile \ + tools/starry-syscall-harness/harness.py \ + tools/starry-syscall-harness/mcp_server.py \ + tools/starry-syscall-harness/ui_server.py +``` + +```bash +node --check tools/starry-syscall-harness/web/app.js +``` + +```bash +docker run --rm -v "$PWD":/work -w /work \ + ghcr.io/rcore-os/tgoskits-container:latest \ + bash -lc 'cargo xtask clippy --package axbuild' +``` + +```bash +docker run --rm -v "$PWD":/work -w /work \ + ghcr.io/rcore-os/tgoskits-container:latest \ + bash -lc 'cargo clippy --manifest-path tools/qperf/analyzer/Cargo.toml --features flamegraph --all-targets -- -D warnings' +``` + +qperf profile 验证: + +```bash +python3 tools/starry-syscall-harness/harness.py perf-profile \ + --repo-root /home/cg24/tgoskits \ + --arch riscv64 \ + --timeout 10 \ + --format all \ + --freq 49 \ + --max-depth 32 \ + --mode tb \ + --top 8 \ + --min-percent 1 \ + --output-dir target/starry-syscall-harness +``` + +验证结果示例: + +```text +result: ok +samples: 350 +flamegraph_generated = true +flamegraph.svg width = 3200 +``` + +UI API 验证: + +```bash +curl http://127.0.0.1:8765/api/status +curl 'http://127.0.0.1:8765/api/report?kind=perf&arch=riscv64' +curl 'http://127.0.0.1:8765/api/file?path=/home/cg24/tgoskits/target/starry-syscall-harness/perf/riscv64/latest/qperf/flamegraph.svg' +``` + +## 17. 可信性与风险控制 + +### 17.1 避免环境漂移 + +StarryOS 相关流程统一在 Docker 镜像中执行,避免宿主机工具链、QEMU 版本、交叉编译器差异影响结果。 + +### 17.2 避免测试变弱 + +syscall probe 作为 Linux 对拍依据,不应为适配 StarryOS 当前错误行为而削弱。若 Linux 与 StarryOS 不一致,默认应修 StarryOS 实现。 + +### 17.3 避免性能误判 + +qperf profile 默认使用 release build。`--debug` 仅用于符号细节调查,不作为默认性能比较基准。 + +### 17.4 避免 UI 越权 + +UI 默认绑定本地地址,并限制 artifact 文件读取范围,避免开放任意文件读取。 + +### 17.5 避免 PR 噪声 + +Docker 命令可能重写 `Cargo.lock` 或生成 root-owned target 文件。工作流中明确恢复非预期 `Cargo.lock` 改动,并在 Docker re-exec 结束后 chown artifact。 + +## 18. 当前能力边界 + +框架已经具备完整闭环,但仍有明确边界: + +- syscall probe 覆盖范围仍需持续扩充。 +- qperf 当前主要验证 riscv64,loongarch64 路径具备入口但仍需更多实测。 +- `pprof` 格式保留为未来能力,目前未完整支持。 +- fix candidates 仍是规则驱动,后续可加入更丰富的代码索引和历史修复模式。 +- Linux 性能 baseline 尚未完全自动化纳入,需要后续定义可比 workload。 +- 自动“修复”仍应由 agent 基于报告和代码审查生成补丁,而不是盲目模板化修改。 + +## 19. 后续扩展路线 + +建议后续按以下方向演进。 + +### 19.1 扩展 syscall 语义覆盖 + +- 增加文件系统 syscall 边界 case。 +- 增加 fd lifecycle case。 +- 增加 signal、poll、epoll、eventfd、timerfd 等常见 Linux app 依赖路径。 +- 增加 mmap/mprotect/munmap 边界 case。 +- 增加权限、flag 和 errno 顺序 case。 + +### 19.2 强化自动修复 + +- 将 difference case 映射到 syscall 实现文件。 +- 为常见 errno/flag 差异建立修复模板。 +- 自动生成最小补丁候选。 +- 自动 rerun discover 并保留 before/after report。 +- 自动生成 PR 描述中的语义证据。 + +### 19.3 强化性能基线 + +- 引入标准 workload 集合。 +- 保存 baseline profile。 +- 自动比较 Linux baseline、StarryOS baseline 和优化后 StarryOS。 +- 增加性能阈值判断。 +- 增加趋势报告。 + +### 19.4 强化可视化 + +- 在 UI 中加入 flamegraph zoom 状态提示。 +- 加入 top function 到 flamegraph 搜索的快捷跳转。 +- 加入 baseline/compare flamegraph 并排查看。 +- 加入 diff flamegraph。 +- 加入热点文件和候选修复区域的跳转。 + +### 19.5 强化 PR 自动化 + +- 自动汇总本轮 discover/perf-profile/perf-diff 结果。 +- 自动生成 PR body。 +- 自动附加关键 artifact 路径。 +- 自动检查目标分支是否最新。 +- 自动标记需要人工 review 的风险点。 + +## 20. 结论 + +当前 harness 已经形成一套面向 StarryOS 的 AI 开发工作框架。它将传统上分散的任务串联成可执行闭环: + +```text +发现 syscall 差异 + -> 生成 Linux 对拍证据 + -> 定位和修复 StarryOS 实现 + -> Docker 内回归验证 + -> 提交 PR + +发现性能热点 + -> qperf 采样 + -> folded stack / flamegraph / JSON 报告 + -> 生成修复候选 + -> 优化代码 + -> perf diff 验证 + -> 提交 PR +``` + +框架同时覆盖自动化和交互式使用: + +- agent 默认使用 CLI/MCP。 +- 人工需要观察时启动本地 UI。 +- 所有 StarryOS 执行留在 Docker 内。 +- 所有关键结果以结构化 artifact 保存。 +- PR 流程对齐真实 upstream 目标分支。 + +这套工作说明了一个可持续扩展的方向:让智能开发代理不只是“写代码”,而是围绕可复现证据执行系统化工程任务,包括发现问题、验证语义、定位热点、生成报告、提出修复、回归确认和推动 PR。 diff --git a/docs/cg24-thu-pr-analysis-report.md b/docs/cg24-thu-pr-analysis-report.md new file mode 100644 index 0000000000..a78d6a1a6f --- /dev/null +++ b/docs/cg24-thu-pr-analysis-report.md @@ -0,0 +1,429 @@ +# cg24-THU 在 rcore-os/tgoskits 中的 PR 分析报告 + +## 1. 分析范围与方法 + +* 仓库: +* 作者:`cg24-THU` +* 分析时间:2026-05-29,Asia/Shanghai;GitHub 元数据时间按 UTC 记录。 +* PR 查询方式:`gh pr list --repo rcore-os/tgoskits --author cg24-THU --state all --limit 200`。 +* 单 PR 数据获取:`gh pr view --repo rcore-os/tgoskits --json ...`、`gh pr diff --repo rcore-os/tgoskits`、`gh pr checks --repo rcore-os/tgoskits`、`gh api repos/rcore-os/tgoskits/pulls//comments --paginate`。 +* 本地代码上下文:`git fetch upstream dev pull//head:refs/remotes/upstream/pr-`,并用 `git show` / `git diff` 阅读关键文件。 +* 数据来源:PR 描述、commit 列表、文件列表、review summary、inline comments、CI/check rollup、PR head diff、本地代码上下文。 +* 局限性:本报告没有重新运行每个 PR 的完整 QEMU、clippy 或 CI;CI 结论来自 GitHub checks 和 review 记录。部分 closed PR 的分支包含旧基线或后续 merge commit,本文会区分 PR 总 diff 与核心 commit。 + +## 2. PR 总览表 + +| PR 编号 | 标题 | 状态 | 创建时间 | 是否合入 | 主要改动领域 | 简要结论 | +|---:|---|---|---|---|---|---| +| [#268](https://github.com/rcore-os/tgoskits/pull/268) | starryos: reject invalid pipe2 flags and add a userspace regression test | MERGED | 2026-04-18T14:01:20Z | 是 | StarryOS syscall | 最终合入 `pipe2` 无效 flags 严格校验;测试基础设施改动在 rebase 后移除。 | +| [#476](https://github.com/rcore-os/tgoskits/pull/476) | feat(starryos): integrate qperf profiling | CLOSED | 2026-05-09T09:21:41Z | 否 | syscall、qperf、BusyBox | 技术点有价值,但范围混杂且 syscall 测试未接入 CI,最终因长期未更新关闭。 | +| [#663](https://github.com/rcore-os/tgoskits/pull/663) | Integrate qperf profiling for StarryOS | CLOSED | 2026-05-16T04:47:42Z | 否 | 非项目代码/文档 | PR 描述声称 qperf 集成,实际 diff 是 `BigLabA-task4/` 和 `.DS_Store`,关闭合理。 | +| [#665](https://github.com/rcore-os/tgoskits/pull/665) | feat(starryos): integrate qperf and expand busybox tests | MERGED | 2026-05-16T05:23:09Z | 是 | syscall、qperf、测试、文档 | 将 #476 中成熟部分合入:vectored I/O 兼容性、qperf 初版、BusyBox 测试增强。 | +| [#783](https://github.com/rcore-os/tgoskits/pull/783) | perf(starryos): 优化 virtio-blk 队列大小与内存屏障 | CLOSED | 2026-05-19T16:35:14Z | 否 | VirtIO block 性能 | 优化方向明确,但 vendoring 整个 `virtio-drivers` 不适合本仓库,维护者建议投上游。 | +| [#940](https://github.com/rcore-os/tgoskits/pull/940) | feat(qperf): TCG hotspot profiling tool for StarryOS | OPEN | 2026-05-25T19:22:38Z | 否 | qperf 性能工具 | 增强 qperf 的地址过滤、TB 采样、symtab fallback、diff、flamegraph;已获 approve。 | +| [#990](https://github.com/rcore-os/tgoskits/pull/990) | feat(starry): add syscall and qperf harness | OPEN | 2026-05-27T10:42:20Z | 否 | syscall harness、qperf、MCP/UI | 建立 Linux/Starry 对拍和 qperf harness;review 已 approve,但与 #940 重叠且最新 checks 有失败项。 | + +## 3. 单个 PR 详细分析 + +### PR #268:starryos: reject invalid pipe2 flags and add a userspace regression test + +#### 基本信息 + +* 链接: +* 状态:MERGED +* 创建 / 更新时间:2026-04-18T14:01:20Z / 2026-05-07T11:59:55Z +* merge 情况:2026-05-07T11:59:55Z 由 `ZR233` 合入,merge commit `2c850f7863907560f1d1fc5b6021634d1812c68b` +* commit 数量:1 +* 修改文件数量:1 + +#### 背景与目标 + +PR 描述指出 `sys_pipe2()` 使用 `PipeFlags::from_bits_truncate(flags)`,会静默丢弃未知 bit。Linux `pipe2(2)` 对未知 flags 应返回 `EINVAL`,因此旧行为会让 `pipe2(..., O_CREAT)` 一类错误调用错误地成功创建 pipe。 + +#### 核心改动 + +最终合入只修改 `os/StarryOS/kernel/src/syscall/fs/pipe.rs`。核心 diff 是把 `PipeFlags::from_bits_truncate(flags)` 改为 `PipeFlags::from_bits(flags).ok_or_else(...) ?`。未知 flags 现在返回 `AxError::InvalidInput`,合法的 `O_CLOEXEC` / `O_NONBLOCK` 路径保持不变。 + +#### 设计分析 + +这是典型的 ABI 兼容性修复:用 bitflags 的严格解析替代容错截断,不引入新抽象,不改变合法 flags 行为。`AxError::InvalidInput` 对应 Linux `EINVAL`,与 PR 目标一致。 + +#### 影响范围 + +影响面集中在 StarryOS pipe syscall。非法 flags 从“成功并创建 pipe”变为“失败返回 `EINVAL`”;合法 flags 行为不变。PR 描述中提到的 userspace regression test 和 per-case rootfs 注入,最终没有出现在合入 diff 中。 + +#### 评审与讨论 + +早期 review 指出测试基础设施问题:`build.sh` 硬编码 `riscv64-unknown-elf-gcc`,success gating 可能在程序打印 `FAIL` 后仍把 case 记为 ok,且旧 rootfs asset 流程与当时 `dev` 冲突。rebase 后只保留核心 `pipe.rs` 修复,review 转为 approve。 + +#### 风险与不足 + +主要不足是合入版缺少回归测试,后续仍应按当前 Starry test-suit C pipeline 补一个 `pipe2` invalid flags case。代码本身风险较低,行为变化是向 Linux 语义收敛。 + +#### 结论 + +#268 是一个小而清晰的 syscall 修复。它提升了 `pipe2` Linux 兼容性,但测试部分未随最终版本合入。该 PR 也暴露出当时 Starry test-suit 对新 C 用例接入方式的演进问题。 + +### PR #476:feat(starryos): integrate qperf profiling + +#### 基本信息 + +* 链接: +* 状态:CLOSED +* 创建 / 更新时间:2026-05-09T09:21:41Z / 2026-05-25T01:24:58Z +* merge 情况:未合入 +* commit 数量:4 +* 修改文件数量:21 +* diff 规模:`+2609/-23` + +#### 背景与目标 + +PR 描述包含三个方向:修复 `preadv2` / `pwritev2` Linux 兼容性,引入 `cargo starry perf` qperf profiling,扩展 BusyBox 兼容性测试。每个方向本身都有价值,但放在一个 PR 中导致 review 面过大。 + +#### 核心改动 + +* `os/StarryOS/kernel/src/syscall/mod.rs`:调整 `preadv` / `pwritev` / `preadv2` / `pwritev2` dispatcher 参数传递。 +* `os/StarryOS/kernel/src/syscall/fs/io.rs`:新增 `offset_from_hilo()`、RWF flags 校验,支持 `preadv2` / `pwritev2` 的 `offset == -1` 当前文件偏移语义。 +* `os/StarryOS/kernel/src/mm/io.rs`:`IoVectorBuf::new()` 增加 `check_access()`、`checked_add()` 和 `isize::MAX` 总长度限制。 +* `test-suit/starryos/syscall/preadv_pwritev2.c`:新增 C 回归测试源码。 +* `scripts/axbuild/src/starry/perf.rs` 和 `tools/qperf/`:新增 qperf plugin/analyzer 与 StarryOS perf 子命令。 +* BusyBox 脚本和 qemu 配置:增加部分语义测试与 fail matcher。 + +#### 设计分析 + +syscall 部分的设计方向正确:显式表达 Linux ABI 的 `pos_l` / `pos_h` / `flags`,并把 iovec 地址和长度检查前置。qperf 部分建立了“xtask 编排、QEMU plugin 采样、analyzer 后处理”的工具层分工。 + +问题是边界不清。syscall ABI 修复、qperf 工具链和 BusyBox 测试互不依赖,应拆成独立 PR,以便单独验证和回滚。 + +#### 影响范围 + +影响 `readv/writev/preadv/pwritev/preadv2/pwritev2` 及复用 `IoVectorBuf` 的路径;新增 qperf 工具链;新增 BusyBox 测试与文档。但新增 syscall C 文件没有被 test-suit 可发现 case 引用。 + +#### 评审与讨论 + +review 主要阻塞在三点: + +* `preadv2/pwritev2` ABI 和 x86_64 参数映射需要更精确处理。 +* `test-suit/starryos/syscall/preadv_pwritev2.c` 没有 `CMakeLists.txt`、子目录和 `qemu-*.toml` 引用,CI 不会运行。 +* qperf 约 2000 行代码与 syscall 修复混在一起,应拆到独立 PR。 + +最后 `ZR233` 以“长时间未修改”关闭。`gh pr checks` 显示该分支没有 checks。 + +#### 风险与不足 + +最大风险是测试没有进入 CI,无法防止 syscall 行为回退。PR 范围过大也导致 review 成本和合入风险上升。报告中还出现过与 base 代码不完全一致的描述,例如旧 `pwritev2` 是否走 read path,后续 #665 review 再次指出需修正。 + +#### 结论 + +#476 是一次重要探索,但不是合格的合入单元。其核心成果后来以 #665 的形式进入项目;#476 本身由于范围混杂、测试接入缺失和长期未更新而关闭。 + +### PR #663:Integrate qperf profiling for StarryOS + +#### 基本信息 + +* 链接: +* 状态:CLOSED +* 创建 / 更新时间:2026-05-16T04:47:42Z / 2026-05-16T04:55:58Z +* merge 情况:未合入 +* commit 数量:2 +* 修改文件数量:19 +* diff 规模:`+7034/-0` + +#### 背景与目标 + +PR 描述称要把 qperf profiler 接入 StarryOS,并新增 `cargo starry perf`。但实际 diff 与描述完全不一致。 + +#### 核心改动 + +文件列表全部集中在 `.DS_Store` 和 `BigLabA-task4/`,包括课程/实验文档、harness 设计文档、Node.js MCP server 示例等。没有 `scripts/axbuild/src/starry/perf.rs`,没有 `tools/qperf/`,也没有 StarryOS CLI 改动。 + +#### 设计分析 + +实际 diff 不属于 tgoskits 主项目功能,不具备 qperf 集成的代码路径。因此无法按 PR 描述进行 qperf 设计评估。若按实际提交评估,它缺少项目边界、构建接入、测试接入和维护策略。 + +#### 影响范围 + +如果合入,会引入大量非项目目录和 macOS 元数据,对主项目无直接收益,并污染仓库。 + +#### 评审与讨论 + +review 明确指出“PR 描述与实际更改严重不符”,并要求移除 `.DS_Store`、移除 `BigLabA-task4/`、修正标题描述,若要提交 qperf 应另开 PR。PR 创建后约 8 分钟关闭。 + +#### 风险与不足 + +风险是仓库污染和 review 误导。CI 只显示路径检测与 skip 类检查,没有对实际内容提供有意义验证。 + +#### 结论 + +#663 是一次分支或提交选择错误。其主要意义是说明 qperf 工作需要重新整理为真实项目代码提交;后续 #665 才是真正的 qperf 集成 PR。 + +### PR #665:feat(starryos): integrate qperf and expand busybox tests + +#### 基本信息 + +* 链接: +* 状态:MERGED +* 创建 / 更新时间:2026-05-16T05:23:09Z / 2026-05-18T09:36:55Z +* merge 情况:2026-05-18T09:36:55Z 合入 +* commit 数量:6 +* 修改文件数量:23 +* diff 规模:`+3122/-24` + +#### 背景与目标 + +该 PR 继承 #476 的主要工作,并明确包含四项 StarryOS-facing 更新:`preadv2` / `pwritev2` 兼容性修复、qperf profiling 集成、BusyBox 语义测试扩展、BusyBox 中文兼容性报告。 + +#### 核心改动 + +syscall 相关: + +* `os/StarryOS/kernel/src/syscall/mod.rs`:为 `preadv` / `pwritev` / `preadv2` / `pwritev2` 正确传递 `pos_h` 和 flags。 +* `os/StarryOS/kernel/src/syscall/fs/io.rs`:新增 `offset_from_hilo(pos_l, pos_h)`;32 位下组合高低位 offset,64 位下忽略 `pos_h`;`preadv2` / `pwritev2` 支持 `offset == -1` 使用当前文件位置;当前未支持的非零 RWF flags 返回不支持。 +* `os/StarryOS/kernel/src/mm/io.rs`:`IoVectorBuf::new()` 对 iovec 个数、负长度、非零长度用户地址、长度累计溢出和 `isize::MAX` 上限做前置校验。 + +qperf 相关: + +* `scripts/axbuild/src/starry/mod.rs`:新增 `Perf(ArgsPerf)` 子命令,暴露 `--arch`、`--freq`、`--out`、`--format`、`--max-depth`、`--timeout`。 +* `scripts/axbuild/src/starry/perf.rs`:串联 qperf plugin/analyzer 构建、StarryOS debug kernel 构建、rootfs 准备、QEMU `-plugin` 注入、raw samples、folded stack 和 summary 输出。 +* `tools/qperf/src/profiler.rs`:实现 QEMU TCG plugin,使用 bounded channel 与 `try_send` 避免阻塞 QEMU 执行路径,基于 frame pointer 回溯栈。 +* `tools/qperf/analyzer/src/main.rs`:读取 `qperf.bin`,用 `addr2line` 解析符号,输出 folded stack。 + +测试与文档: + +* `test-suit/starryos/syscall/preadv_pwritev2.c`:新增 C 测试源码。 +* `test-suit/starryos/normal/qemu-smp1/busybox/sh/busybox-tests.sh`:新增 12 个 BusyBox 稳定语义测试。 +* BusyBox 四个架构 qemu 配置增加 `(?m)^FAIL: ` fail matcher,并增加 `Test run completed` success marker。 +* 新增 qperf 集成报告、BusyBox 兼容性报告和 syscall 修改报告。 + +#### 设计分析 + +syscall 修复把 Linux ABI 细节显式化,降低参数错位风险。`IoVectorBuf` 前置校验提升边界安全性。qperf 设计保持在工具层,不侵入内核本体,通过 xtask 复用现有 build/rootfs/QEMU 流程。 + +不足是 PR 仍包含四个独立方向。review 虽然 approve,但也建议后续拆分,以降低 review 和回滚风险。 + +#### 影响范围 + +* 内核行为:vectored I/O 的 offset、flags、错误码和 iovec 检查时机变化。 +* 工具链:新增可执行的 StarryOS qperf profiling 工作流。 +* 测试:BusyBox case 更严格,脚本内 `FAIL:` 会被 QEMU harness 捕获。 +* 文档:新增性能工具与 BusyBox 兼容性说明。 + +#### 评审与讨论 + +review 认可实现逻辑,但记录了注意事项:PR 范围偏大;syscall QEMU 端到端验证曾因 rootfs 下载阻塞而不完整;BusyBox 新测试主要验证 riscv64;`O_APPEND + positioned write` 仍有已知 Linux 兼容限制;修改报告中关于旧 `pwritev2` 走 read path 的说法不准确。 + +CI/check 显示合入前 container 路径多项通过,包括 clippy、sync-lint、std test、多架构 Starry/ArceOS/AxVisor QEMU 等。 + +#### 风险与不足 + +主要风险是范围大。`RWF_*` flags 当前统一返回不支持,是阶段性兼容实现。新增 syscall C 测试文件是否完整纳入后续常规 Starry CI 路径,需要继续确认。 + +#### 结论 + +#665 是作者最重要的已合入贡献之一。它同时提升 StarryOS Linux 兼容性、性能分析能力和 BusyBox 测试质量。虽然提交边界偏大,但最终通过 review 和 CI,被项目接受,并成为后续 #940/#990 的基础。 + +### PR #783:perf(starryos): 优化 virtio-blk 队列大小与内存屏障 + +#### 基本信息 + +* 链接: +* 状态:CLOSED +* 创建 / 更新时间:2026-05-19T16:35:14Z / 2026-05-20T07:12:24Z +* merge 情况:未合入 +* commit 数量:6 +* 修改文件数量:75 +* PR 总 diff 规模:`+17058/-25` + +#### 背景与目标 + +PR 目标是优化 StarryOS virtio-blk I/O 路径。描述基于 qperf 和 Linux 对照,认为 virtio-blk queue size 太小、`VirtQueue::add()` 内存屏障过强是可优化点。 + +#### 核心改动 + +核心性能 commit `584dcaffd00a4e917e3ca16e9c754c5d6e76703b` 包含: + +* `Cargo.toml`:新增 `[patch.crates-io] virtio-drivers = { path = "third_party/virtio-drivers" }`。 +* `third_party/virtio-drivers/src/device/blk.rs`:`QUEUE_SIZE` 设置为 `256`。 +* `third_party/virtio-drivers/src/queue.rs`:available index 更新前使用 `fence(Ordering::Release)`,注释说明该屏障保证 descriptor table 和 avail ring 写入先于 `avail.idx` store 可见。 +* `test-suit/starryos/normal/qemu-smp1/bench-virtio-blk/`:新增 C benchmark,覆盖 10MB 顺序读写、不同 block size 和随机 4K read。 +* `docs/virtio_qperf_analysis.md`:新增中文性能分析报告。 + +PR 总 diff 还包含 #665/#476 的 syscall、qperf 和 BusyBox 历史内容,这是分支基线导致的噪声,不是 virtio-blk 优化核心。 + +#### 设计分析 + +从 virtio 语义看,queue size 从 16 提到 256 有助于更多在途请求;`Release` fence 也更接近“发布此前写入给设备”的单向排序需求,比 `SeqCst` 更弱、潜在开销更低。 + +设计问题在提交落点。为两处核心修改 vendoring 整个 `virtio-drivers` crate,并在 tgoskits 中 patch crates.io,会带来上游同步成本。该类变更更适合先提交到 `rcore-os/virtio-drivers`。 + +#### 影响范围 + +影响所有使用 patched `virtio-drivers` 的 virtqueue 行为,并改变依赖来源。新增 benchmark 只配置了 riscv64 QEMU。文档提供了性能数据和分析方法。 + +#### 评审与讨论 + +review 认可 queue size 和 fence 优化方向,但指出 PR 范围过大、vendoring 整个 crate 需要维护策略。`elliott10` 也指出 `tools/qperf/` 和 `third_party/virtio-drivers/` 是否应长期维护需要确认。维护者 `ZR233` 最终要求向 提交 PR,并关闭本 PR。该分支没有 GitHub checks。 + +#### 风险与不足 + +* vendoring 整个驱动 crate 的维护成本高。 +* PR 总 diff 混入无关历史内容。 +* benchmark 只覆盖 riscv64,跨架构影响未验证。 +* 优化应上游化后再回到 tgoskits 更新依赖。 + +#### 结论 + +#783 的技术判断有价值,但仓库边界不合适。它未合入,但为后续 `virtio-drivers` 上游优化提供了补丁方向、benchmark 和分析材料。 + +### PR #940:feat(qperf): TCG hotspot profiling tool for StarryOS + +#### 基本信息 + +* 链接: +* 状态:OPEN +* 创建 / 更新时间:2026-05-25T19:22:38Z / 2026-05-28T12:48:32Z +* merge 情况:未合入 +* commit 数量:4 +* 修改文件数量:9 +* diff 规模:`+881/-33` + +#### 背景与目标 + +#940 在 #665 的 qperf 初版基础上增强热点分析能力,重点解决 OpenSBI 样本噪声、指令级采样开销、release kernel 符号解析和优化前后 diff 问题。 + +#### 核心改动 + +* `scripts/axbuild/src/starry/mod.rs`:`ArgsPerf` 新增 `--mode` 和 `--top`。 +* `scripts/axbuild/src/starry/perf.rs`:用 `object::{Object, ObjectSection}` 读取 kernel ELF `.text` 范围,并传给 qperf plugin 作为 `filter_start/filter_end`;qperf 构建使用 `tools/qperf/target`;analyzer 改为 `resolve` 子命令并支持 `--top`、`--flamegraph`。 +* `tools/qperf/src/profiler.rs`:新增 TB/insn 两种采样模式,支持地址过滤,TB 模式在 translation block 上注册回调。 +* `tools/qperf/analyzer/src/main.rs`:新增 `resolve` / `diff` 子命令,使用 `.symtab` fallback,聚合 top hottest functions,支持 folded stack diff 和可选 flamegraph。 +* `docs/qperf-virtio-optimization-report.md`:新增基于 qperf 的 VirtIO 性能优化分析文档。 + +#### 设计分析 + +#940 把 qperf 从“能跑通”推进到“能定位热点”。`.text` 过滤解决固件样本淹没,TB 采样降低开销,`.symtab` fallback 提升 release kernel 可用性,diff 模式支持优化验证。这些改动都保持在工具层,不改变内核语义。 + +#### 影响范围 + +影响 `cargo starry perf` 的输出质量、采样开销和分析能力。新增文档把 qperf 用于 VirtIO vsock/net/blk 锁竞争分析。构建上增加 analyzer 依赖进入 `Cargo.lock`。 + +#### 评审与讨论 + +前两轮 review 指出格式、clippy、编译和 merge conflict 问题,包括 `ObjectSection` trait import、`collapsible_if`、target dir、Cargo.lock 冲突等。后续修复后,review 转为 approve。 + +最新 `gh pr checks` 显示 container 路径通过,包括 formatting、clippy、std test、多架构 Starry/ArceOS/AxVisor QEMU 等;大量 host 路径 skipped。 + +#### 风险与不足 + +PR 仍未合入。review 提到 `truncate_str()` 截断时没有加 `...` 前缀,是非阻塞小问题。`--format pprof` 仍是预留能力。文档和工具代码放在同一 PR,会增加 review 噪声但不构成阻塞。 + +#### 结论 + +#940 是 #665 qperf 初版后的聚焦增强。它提高了 qperf 的准确性、可读性和对比能力,review 已批准。当前主要问题是与 #990 的重叠和后续合入顺序。 + +### PR #990:feat(starry): add syscall and qperf harness + +#### 基本信息 + +* 链接: +* 状态:OPEN +* 创建 / 更新时间:2026-05-27T10:42:20Z / 2026-05-28T06:15:01Z +* merge 情况:未合入 +* commit 数量:7 +* 修改文件数量:24 +* diff 规模:`+3936/-101` + +#### 背景与目标 + +#990 新增 StarryOS syscall/qperf harness,用于在 Docker 内执行 Linux 语义对拍、StarryOS QEMU 运行和 qperf 性能画像。它同时修复 harness 发现的 `ftruncate` 只读 fd errno 问题,并提供 CLI、MCP server 和本地浏览器 UI。 + +#### 核心改动 + +syscall 修复: + +* `os/StarryOS/kernel/src/syscall/fs/io.rs`:`sys_ftruncate()` 对 `FileFlags::PATH` 或缺少 `FileFlags::WRITE` 的 fd 显式返回 `AxError::BadFileDescriptor`,对齐 Linux/POSIX 的 `EBADF`。 +* `test-suit/starryos/normal/qemu-smp1/syscall/test-ftruncate/c/src/main.c`:只读 fd 场景从宽松接受 `EBADF || EINVAL` 改为严格检查 `EBADF`。 + +qperf 扩展: + +* `scripts/axbuild/src/starry/mod.rs`:`ArgsPerf` 使用 typed `PerfMode`,新增 `--debug` 和 `--kernel-filter`。 +* `scripts/axbuild/src/starry/perf.rs`:支持 debug/release profile,检测 kernel `.text` 虚拟范围和物理别名范围,传递 `filter_alias_start/end/offset`;analyzer 可直接生成 flamegraph。 +* `tools/qperf/src/profiler.rs` 和 `tools/qperf/analyzer/src/main.rs`:增强 timeout flush、物理地址别名映射、top hotspot、diff 和 flamegraph 输出。 + +harness 工具: + +* `tools/starry-syscall-harness/harness.py`:提供 `doctor`、`discover`、`perf-profile`、`perf-diff`、`ui`。`discover` 构建 syscall probe,在 Linux 与 StarryOS 中运行并比较 `CASE` 输出;`perf-profile` 运行 `cargo xtask starry perf`,解析 folded stack,输出 `report.json`、`report.md`、`hotspots.csv`。 +* `tools/starry-syscall-harness/probes/syscall_probe.c`:覆盖 `pipe2` invalid flags、`eventfd2` invalid flags、`memfd_create` invalid flags、`dup3` same fd、`pwritev2` 写入数据、`ftruncate` readonly fd。 +* `tools/starry-syscall-harness/mcp_server.py`:暴露 `starry_syscall_doctor`、`starry_syscall_discover`、`starry_perf_profile`、`starry_perf_diff`、`starry_harness_ui_command` 五个工具,并自动定位仓库根。 +* `tools/starry-syscall-harness/ui_server.py` 与 `web/`:提供本地 UI、job queue、report/file API;artifact 文件服务限制在 harness artifact root 下。 +* `.claude/skills/starry-syscall-harness/SKILL.md`、`AGENTS.md`、`docs/starry-syscall-harness.md`:补充使用文档和项目技能说明。 +* `test-suit/starryos/normal/qemu-smp1/apk-curl/qemu-*.toml`:改用 `printf` 输出 PASS/FAIL marker,避免 shell trace 下 `echo` 标记误匹配。 + +#### 设计分析 + +#990 把前面几类工作串成自动化闭环:syscall probe 发现语义差异,StarryOS 修复由 test-suit 回归锁住,qperf profile/diff 支撑性能迭代,MCP/UI 提供交互入口。工具位于 `tools/`,不侵入内核。UI server 对 repo path 和 artifact path 做白名单限制,安全设计较清楚。 + +主要设计风险是与 #940 重叠。review 明确指出 #940 是 qperf 基础增强,#990 在其上扩展 harness 和更多 qperf 能力,存在合并顺序依赖。 + +#### 影响范围 + +* syscall:`ftruncate` 只读 fd errno 收敛为 `EBADF`。 +* 测试:`test-ftruncate` 更严格;`apk-curl` marker 规避误判。 +* 工具链:新增 Docker harness、MCP server、本地 UI 和 qperf report pipeline。 +* 文档:新增 harness README、项目 skill 和用户文档。 + +#### 评审与讨论 + +前两轮 review 请求修改:`sys_ftruncate` 只读 fd 应返回 `EBADF`;缺少回归测试;`mcp_server.py` 和文档中有 `/home/cg24/tgoskits` 硬编码;`bincode` 应保留 workspace dependency。后续 commit 修复后 review 转为 approve。 + +最后一轮 review 明确指出与 #940 的文件级重叠和合并顺序依赖。CI/check 方面,分析时 `gh pr checks` 显示 `Test starry riscv64 qemu / run_container` 失败,`Run clippy / run_container` 也有失败或取消记录;其他多项检查通过或 skipped。因此该 PR 虽获 approve,但当前不应直接合入。 + +#### 风险与不足 + +* PR 范围很大,包含 syscall 修复、qperf 增强、harness、UI、MCP、文档和 test marker 修复。 +* 与 #940 重叠,需要明确先后或合并策略。 +* Docker harness、UI、MCP 增加长期维护面,需要持续审计命令执行边界。 +* `ftruncate` 修复可以独立拆出,避免被工具链大 PR 阻塞。 +* 最新 CI 仍有失败项。 + +#### 结论 + +#990 是作者从单点修复走向可重复验证框架的标志性 PR。它的工程化价值高,但当前最大问题是范围过大、与 #940 重叠和 checks 未全绿。建议先拆分或明确 #940/#990 合并策略。 + +## 4. 整体贡献脉络 + +这些 PR 呈现出递进关系: + +* Linux syscall 兼容性:#268 修 `pipe2` invalid flags;#476/#665 推进 `preadv/pwritev2` ABI 和 iovec 边界;#990 修 `ftruncate` readonly fd errno。 +* 测试体系:#268 早期尝试回归测试但未合入;#665 强化 BusyBox 测试和 fail matcher;#990 建立 Linux/Starry syscall differential harness。 +* 性能工具:#665 合入 qperf 初版;#940 增强热点分析;#990 把 qperf 纳入 harness、UI 和 MCP。 +* 性能优化探索:#783 基于 qperf 分析尝试 virtio-blk 优化,但应上游到 `virtio-drivers`。 +* 工程边界演进:#476/#663/#783 暴露范围混杂、分支错误和上游归属问题;#665/#940/#990 的质量逐步提升,但仍需进一步拆分。 + +## 5. 技术主题归类 + +* 内核机制:#268、#665、#990。 +* 用户态支持:#665 的 BusyBox 测试和 #990 的 syscall probe。 +* 驱动 / 设备:#783 的 virtio-blk 优化探索;#940 文档中的 VirtIO 锁竞争分析。 +* 文件系统:#665 的 vectored I/O、#990 的 `ftruncate`。 +* 构建与工具链:#665 的 `cargo starry perf`、#940 的 qperf 增强、#990 的 Docker harness/MCP/UI。 +* 测试与 CI:#476 的测试接入失败、#665 的 BusyBox matcher、#990 的 differential harness。 +* 文档与工程化:#665、#783、#940、#990 都包含较多分析和使用文档。 + +## 6. 综合评价 + +`cg24-THU` 的贡献集中在 StarryOS Linux 兼容性、测试体系和性能分析工具链。已合入的 #268 和 #665 对项目有直接贡献:前者修复明确 syscall 语义错误,后者提升 vectored I/O 兼容性、qperf 工具能力和 BusyBox 测试质量。 + +未合入 PR 也有技术价值,但暴露出工程边界问题。#476 和 #783 都有可取技术点,却因范围混杂、测试接入不足或上游归属不合适而关闭。#663 是明显的分支内容错误。#940 和 #990 是更成熟的后续工作,review 已基本认可方向,但需要处理合并顺序和 CI 状态。 + +整体看,这些 PR 把 tgoskits 的 StarryOS 工作从“修具体兼容 bug”推进到“用测试和 profiling 工具持续发现问题”。qperf 与 syscall harness 的结合,为后续性能优化和 Linux 语义对齐提供了可重复方法。 + +## 7. 后续建议 + +1. 明确 #940/#990 的合并策略:优先合入 #940 后 rebase #990,或确认 #990 完整覆盖 #940 后关闭 #940。 +2. 将 #990 中 `ftruncate` errno 修复拆成小 PR,避免被 harness 大 PR 阻塞。 +3. 为 #268 补当前 C pipeline 下的 `pipe2` invalid flags 回归测试。 +4. 将 `preadv_pwritev2.c` 迁移到可发现、可编译、可运行的 Starry test-suit case,并在 qemu config 中明确引用。 +5. #783 的 virtio-blk queue/fence 优化应转投 `rcore-os/virtio-drivers`,上游合入后再更新 tgoskits 依赖。 +6. 为 qperf/harness 增加最小 CI:Python `py_compile`、Node `--check`、qperf clippy、`cargo xtask starry perf --help`。 +7. 对 harness UI/MCP 持续审计命令参数、artifact 读取范围和长任务并发,避免工具链成为维护风险。 diff --git a/docs/flamegraphs/ai-harness-ppt__assets__flamegraph-panel.png b/docs/flamegraphs/ai-harness-ppt__assets__flamegraph-panel.png new file mode 100644 index 0000000000..140851fcab Binary files /dev/null and b/docs/flamegraphs/ai-harness-ppt__assets__flamegraph-panel.png differ diff --git a/docs/flamegraphs/ai-harness-ppt__assets__flamegraph.png b/docs/flamegraphs/ai-harness-ppt__assets__flamegraph.png new file mode 100644 index 0000000000..1ecf0c8e82 Binary files /dev/null and b/docs/flamegraphs/ai-harness-ppt__assets__flamegraph.png differ diff --git a/docs/flamegraphs/qperf-host-rerun-blk-focus.png b/docs/flamegraphs/qperf-host-rerun-blk-focus.png new file mode 100644 index 0000000000..f8765b6900 Binary files /dev/null and b/docs/flamegraphs/qperf-host-rerun-blk-focus.png differ diff --git a/docs/flamegraphs/qperf-host-rerun-blk-workload.png b/docs/flamegraphs/qperf-host-rerun-blk-workload.png new file mode 100644 index 0000000000..1106de7bd9 Binary files /dev/null and b/docs/flamegraphs/qperf-host-rerun-blk-workload.png differ diff --git a/docs/flamegraphs/qperf-host-rerun-net-workload.png b/docs/flamegraphs/qperf-host-rerun-net-workload.png new file mode 100644 index 0000000000..57309eb42f Binary files /dev/null and b/docs/flamegraphs/qperf-host-rerun-net-workload.png differ diff --git a/docs/flamegraphs/qperf-long-chain-demo.synthetic.flamegraph.svg b/docs/flamegraphs/qperf-long-chain-demo.synthetic.flamegraph.svg new file mode 100644 index 0000000000..f34c1be1ed --- /dev/null +++ b/docs/flamegraphs/qperf-long-chain-demo.synthetic.flamegraph.svg @@ -0,0 +1,491 @@ +StarryOS qperf Flame Graph Reset ZoomSearch os::task::current (402 samples, 2.57%)os::task..starry_process::fd_manager::FileLike::read (402 samples, 2.57%)starry_p..ax_fs_ng::fs::ext4::Ext4File::read_at (402 samples, 2.57%)ax_fs_ng..rsext4::file::File::read_at (402 samples, 2.57%)rsext4::..rsext4::cache::data_block::DataBlockCache::get (402 samples, 2.57%)rsext4::..rsext4::cache::data_block::DataBlockCache::evict_lru (402 samples, 2.57%)rsext4::..alloc::collections::btree::map::BTreeMap<K,V,A>::get (402 samples, 2.57%)alloc::c..alloc::collections::btree::search::search_tree (402 samples, 2.57%)alloc::c..rd_block::BlockDevice::read_blocks (402 samples, 2.57%)rd_block..ax_driver::virtio::block::VirtIoBlkDev::read_block (402 samples, 2.57%)ax_drive..virtio_drivers::device::blk::VirtIOBlk::read_blocks (402 samples, 2.57%)virtio_d..virtio_drivers::queue::VirtQueue::add_notify_wait_pop (402 samples, 2.57%)virtio_d..virtio_drivers::queue::VirtQueue::add (402 samples, 2.57%)virtio_d..virtio_drivers::transport::pci::PciTransport::notify (402 samples, 2.57%)virtio_d..virtio_drivers::queue::VirtQueue::pop_used (402 samples, 2.57%)virtio_d..core::ptr::drop_in_place<alloc::boxed::Box<[u8]>> (99 samples, 0.63%)compiler_builtins::mem::memset (459 samples, 2.93%)compiler_b..os::syscall::fs::sys_read (4,305 samples, 27.49%)os::syscall::fs::sys_readstarry_process::fd_manager::FileLike::read (3,903 samples, 24.92%)starry_process::fd_manager::FileLike::readax_fs_ng::fs::ext4::Ext4File::read_at (3,903 samples, 24.92%)ax_fs_ng::fs::ext4::Ext4File::read_atrsext4::file::File::read_at (3,903 samples, 24.92%)rsext4::file::File::read_atrsext4::cache::data_block::DataBlockCache::get (3,903 samples, 24.92%)rsext4::cache::data_block::DataBlockCache::getrsext4::cache::data_block::DataBlockCache::evict_lru (3,903 samples, 24.92%)rsext4::cache::data_block::DataBlockCache::evict_lrualloc::collections::btree::map::BTreeMap<K,V,A>::get (3,903 samples, 24.92%)alloc::collections::btree::map::BTreeMap<K,V,A>::getalloc::collections::btree::search::search_tree (3,903 samples, 24.92%)alloc::collections::btree::search::search_treerd_block::BlockDevice::read_blocks (3,903 samples, 24.92%)rd_block::BlockDevice::read_blocksax_driver::virtio::block::VirtIoBlkDev::read_block (3,903 samples, 24.92%)ax_driver::virtio::block::VirtIoBlkDev::read_blockvirtio_drivers::device::blk::VirtIOBlk::read_blocks (3,903 samples, 24.92%)virtio_drivers::device::blk::VirtIOBlk::read_blocksvirtio_drivers::queue::VirtQueue::add_notify_wait_pop (3,903 samples, 24.92%)virtio_drivers::queue::VirtQueue::add_notify_wait_popvirtio_drivers::queue::VirtQueue::add (3,903 samples, 24.92%)virtio_drivers::queue::VirtQueue::addvirtio_drivers::transport::pci::PciTransport::notify (3,903 samples, 24.92%)virtio_drivers::transport::pci::PciTransport::notifyvirtio_drivers::queue::VirtQueue::pop_used (3,903 samples, 24.92%)virtio_drivers::queue::VirtQueue::pop_usedcore::ptr::drop_in_place<alloc::boxed::Box<[u8]>> (766 samples, 4.89%)core::ptr::drop_in..compiler_builtins::mem::memset (105 samples, 0.67%)compiler_builtins::mem::memset (342 samples, 2.18%)compile..ax_net_ng::tcp::Socket::recv (2,922 samples, 18.66%)ax_net_ng::tcp::Socket::recvsmoltcp::socket::tcp::Socket::recv_slice (2,922 samples, 18.66%)smoltcp::socket::tcp::Socket::recv_slicerd_net::VirtioNetDriver::receive (2,922 samples, 18.66%)rd_net::VirtioNetDriver::receiveax_driver::virtio::net::VirtIoNetDev::receive (2,922 samples, 18.66%)ax_driver::virtio::net::VirtIoNetDev::receivevirtio_drivers::device::net::VirtIONetRaw::receive (2,922 samples, 18.66%)virtio_drivers::device::net::VirtIONetRaw::receivevirtio_drivers::queue::VirtQueue::pop_used (2,922 samples, 18.66%)virtio_drivers::queue::VirtQueue::pop_usedax_driver::virtio::net::RxBuffer::copy_within (2,922 samples, 18.66%)ax_driver::virtio::net::RxBuffer::copy_withincompiler_builtins::mem::memmove (2,922 samples, 18.66%)compiler_builtins::mem::memmovecompiler_builtins::mem::memcpy (2,922 samples, 18.66%)compiler_builtins::mem::memcpycore::ptr::drop_in_place<alloc::boxed::Box<[u8]>> (577 samples, 3.68%)core::ptr::dr..compiler_builtins::mem::memset (78 samples, 0.50%)os::syscall::net::sys_recvfrom (3,225 samples, 20.59%)os::syscall::net::sys_recvfromos::task::current (303 samples, 1.93%)os::ta..ax_net_ng::tcp::Socket::recv (303 samples, 1.93%)ax_net..smoltcp::socket::tcp::Socket::recv_slice (303 samples, 1.93%)smoltc..rd_net::VirtioNetDriver::receive (303 samples, 1.93%)rd_net..ax_driver::virtio::net::VirtIoNetDev::receive (303 samples, 1.93%)ax_dri..virtio_drivers::device::net::VirtIONetRaw::receive (303 samples, 1.93%)virtio..virtio_drivers::queue::VirtQueue::pop_used (303 samples, 1.93%)virtio..ax_driver::virtio::net::RxBuffer::copy_within (303 samples, 1.93%)ax_dri..compiler_builtins::mem::memmove (303 samples, 1.93%)compil..compiler_builtins::mem::memcpy (303 samples, 1.93%)compil..core::ptr::drop_in_place<alloc::boxed::Box<[u8]>> (72 samples, 0.46%)alloc::collections::btree::node::drop_child::11 (52 samples, 0.33%)core::mem::drop (52 samples, 0.33%)os::mm::area::MapArea::drop (52 samples, 0.33%)os::mm::page::Page::drop (52 samples, 0.33%)ax_alloc::buddy_slab::GlobalAllocator::dealloc (52 samples, 0.33%)alloc::collections::btree::node::drop_child::14 (49 samples, 0.31%)core::mem::drop (49 samples, 0.31%)os::mm::area::MapArea::drop (49 samples, 0.31%)os::mm::page::Page::drop (49 samples, 0.31%)ax_alloc::buddy_slab::GlobalAllocator::dealloc (49 samples, 0.31%)alloc::collections::btree::node::drop_child::16 (48 samples, 0.31%)core::mem::drop (48 samples, 0.31%)os::mm::area::MapArea::drop (48 samples, 0.31%)os::mm::page::Page::drop (48 samples, 0.31%)ax_alloc::buddy_slab::GlobalAllocator::dealloc (48 samples, 0.31%)alloc::collections::btree::node::drop_child::3 (51 samples, 0.33%)core::mem::drop (51 samples, 0.33%)os::mm::area::MapArea::drop (51 samples, 0.33%)os::mm::page::Page::drop (51 samples, 0.33%)ax_alloc::buddy_slab::GlobalAllocator::dealloc (51 samples, 0.33%)alloc::collections::btree::node::drop_child::5 (50 samples, 0.32%)core::mem::drop (50 samples, 0.32%)os::mm::area::MapArea::drop (50 samples, 0.32%)os::mm::page::Page::drop (50 samples, 0.32%)ax_alloc::buddy_slab::GlobalAllocator::dealloc (50 samples, 0.32%)alloc::collections::btree::node::drop_child::8 (47 samples, 0.30%)core::mem::drop (47 samples, 0.30%)os::mm::area::MapArea::drop (47 samples, 0.30%)os::mm::page::Page::drop (47 samples, 0.30%)ax_alloc::buddy_slab::GlobalAllocator::dealloc (47 samples, 0.30%)core::ptr::drop_in_place<alloc::boxed::Box<[u8]>> (47 samples, 0.30%)os::task::current (523 samples, 3.34%)os::task::c..os::task::spawn_user_task (523 samples, 3.34%)os::task::s..os::task::Task::exec (523 samples, 3.34%)os::task::T..os::mm::memory_set::MemorySet::from_elf (523 samples, 3.34%)os::mm::mem..os::mm::memory_set::MemorySet::map_area (523 samples, 3.34%)os::mm::mem..alloc::sync::Arc<T,A>::drop_slow (523 samples, 3.34%)alloc::sync..core::ptr::drop_in_place<os::mm::memory_set::MemorySet> (523 samples, 3.34%)core::ptr::..core::ptr::drop_in_place<alloc::sync::Arc<spin::rw_lock::RwLock<os::mm::memory_set::MemorySet>>> (523 samples, 3.34%)core::ptr::..alloc::collections::btree::map::BTreeMap<K,V,A>::drop (523 samples, 3.34%)alloc::coll..alloc::collections::btree::node::NodeRef::drop (523 samples, 3.34%)alloc::coll..alloc::collections::btree::node::Handle::drop (523 samples, 3.34%)alloc::coll..core::ptr::drop_in_place<alloc::collections::btree::node::Handle<alloc::alloc::Global>> (523 samples, 3.34%)core::ptr::..alloc::collections::btree::node::drop_child::9 (53 samples, 0.34%)core::mem::drop (53 samples, 0.34%)os::mm::area::MapArea::drop (53 samples, 0.34%)os::mm::page::Page::drop (53 samples, 0.34%)ax_alloc::buddy_slab::GlobalAllocator::dealloc (53 samples, 0.34%)compiler_builtins::mem::memset (53 samples, 0.34%)alloc::collections::btree::node::drop_child::0 (334 samples, 2.13%)alloc:..core::mem::drop (334 samples, 2.13%)core::..os::mm::area::MapArea::drop (334 samples, 2.13%)os::mm..os::mm::page::Page::drop (334 samples, 2.13%)os::mm..ax_alloc::buddy_slab::GlobalAllocator::dealloc (334 samples, 2.13%)ax_all..core::ptr::drop_in_place<alloc::boxed::Box<[u8]>> (48 samples, 0.31%)compiler_builtins::mem::memset (49 samples, 0.31%)alloc::collections::btree::node::drop_child::10 (278 samples, 1.78%)alloc..core::mem::drop (278 samples, 1.78%)core:..os::mm::area::MapArea::drop (278 samples, 1.78%)os::m..os::mm::page::Page::drop (278 samples, 1.78%)os::m..ax_alloc::buddy_slab::GlobalAllocator::dealloc (278 samples, 1.78%)ax_al..core::ptr::drop_in_place<alloc::boxed::Box<[u8]>> (96 samples, 0.61%)alloc::collections::btree::node::drop_child::11 (279 samples, 1.78%)alloc..core::mem::drop (279 samples, 1.78%)core:..os::mm::area::MapArea::drop (279 samples, 1.78%)os::m..os::mm::page::Page::drop (279 samples, 1.78%)os::m..ax_alloc::buddy_slab::GlobalAllocator::dealloc (279 samples, 1.78%)ax_al..core::ptr::drop_in_place<alloc::boxed::Box<[u8]>> (47 samples, 0.30%)compiler_builtins::mem::memset (52 samples, 0.33%)alloc::collections::btree::node::drop_child::12 (338 samples, 2.16%)alloc::..core::mem::drop (338 samples, 2.16%)core::m..os::mm::area::MapArea::drop (338 samples, 2.16%)os::mm:..os::mm::page::Page::drop (338 samples, 2.16%)os::mm:..ax_alloc::buddy_slab::GlobalAllocator::dealloc (338 samples, 2.16%)ax_allo..compiler_builtins::mem::memset (48 samples, 0.31%)alloc::collections::btree::node::drop_child::13 (332 samples, 2.12%)alloc:..core::mem::drop (332 samples, 2.12%)core::..os::mm::area::MapArea::drop (332 samples, 2.12%)os::mm..os::mm::page::Page::drop (332 samples, 2.12%)os::mm..ax_alloc::buddy_slab::GlobalAllocator::dealloc (332 samples, 2.12%)ax_all..core::ptr::drop_in_place<alloc::boxed::Box<[u8]>> (97 samples, 0.62%)alloc::collections::btree::node::drop_child::14 (277 samples, 1.77%)alloc..core::mem::drop (277 samples, 1.77%)core:..os::mm::area::MapArea::drop (277 samples, 1.77%)os::m..os::mm::page::Page::drop (277 samples, 1.77%)os::m..ax_alloc::buddy_slab::GlobalAllocator::dealloc (277 samples, 1.77%)ax_al..compiler_builtins::mem::memset (51 samples, 0.33%)alloc::collections::btree::node::drop_child::15 (278 samples, 1.78%)alloc..core::mem::drop (278 samples, 1.78%)core:..os::mm::area::MapArea::drop (278 samples, 1.78%)os::m..os::mm::page::Page::drop (278 samples, 1.78%)os::m..ax_alloc::buddy_slab::GlobalAllocator::dealloc (278 samples, 1.78%)ax_al..core::ptr::drop_in_place<alloc::boxed::Box<[u8]>> (93 samples, 0.59%)compiler_builtins::mem::memset (47 samples, 0.30%)alloc::collections::btree::node::drop_child::16 (279 samples, 1.78%)alloc..core::mem::drop (279 samples, 1.78%)core:..os::mm::area::MapArea::drop (279 samples, 1.78%)os::m..os::mm::page::Page::drop (279 samples, 1.78%)os::m..ax_alloc::buddy_slab::GlobalAllocator::dealloc (279 samples, 1.78%)ax_al..core::ptr::drop_in_place<alloc::boxed::Box<[u8]>> (52 samples, 0.33%)alloc::collections::btree::node::drop_child::1 (326 samples, 2.08%)alloc:..core::mem::drop (326 samples, 2.08%)core::..os::mm::area::MapArea::drop (326 samples, 2.08%)os::mm..os::mm::page::Page::drop (326 samples, 2.08%)os::mm..ax_alloc::buddy_slab::GlobalAllocator::dealloc (326 samples, 2.08%)ax_all..core::ptr::drop_in_place<alloc::boxed::Box<[u8]>> (50 samples, 0.32%)compiler_builtins::mem::memset (50 samples, 0.32%)alloc::collections::btree::node::drop_child::2 (320 samples, 2.04%)alloc:..core::mem::drop (320 samples, 2.04%)core::..os::mm::area::MapArea::drop (320 samples, 2.04%)os::mm..os::mm::page::Page::drop (320 samples, 2.04%)os::mm..ax_alloc::buddy_slab::GlobalAllocator::dealloc (320 samples, 2.04%)ax_all..alloc::collections::btree::node::drop_child::3 (276 samples, 1.76%)alloc..core::mem::drop (276 samples, 1.76%)core:..os::mm::area::MapArea::drop (276 samples, 1.76%)os::m..os::mm::page::Page::drop (276 samples, 1.76%)os::m..ax_alloc::buddy_slab::GlobalAllocator::dealloc (276 samples, 1.76%)ax_al..core::ptr::drop_in_place<alloc::boxed::Box<[u8]>> (90 samples, 0.57%)alloc::collections::btree::node::drop_child::4 (290 samples, 1.85%)alloc..core::mem::drop (290 samples, 1.85%)core:..os::mm::area::MapArea::drop (290 samples, 1.85%)os::m..os::mm::page::Page::drop (290 samples, 1.85%)os::m..ax_alloc::buddy_slab::GlobalAllocator::dealloc (290 samples, 1.85%)ax_al..compiler_builtins::mem::memset (49 samples, 0.31%)alloc::collections::btree::node::drop_child::5 (278 samples, 1.78%)alloc..core::mem::drop (278 samples, 1.78%)core:..os::mm::area::MapArea::drop (278 samples, 1.78%)os::m..os::mm::page::Page::drop (278 samples, 1.78%)os::m..ax_alloc::buddy_slab::GlobalAllocator::dealloc (278 samples, 1.78%)ax_al..core::ptr::drop_in_place<alloc::boxed::Box<[u8]>> (99 samples, 0.63%)alloc::collections::btree::node::drop_child::6 (322 samples, 2.06%)alloc:..core::mem::drop (322 samples, 2.06%)core::..os::mm::area::MapArea::drop (322 samples, 2.06%)os::mm..os::mm::page::Page::drop (322 samples, 2.06%)os::mm..ax_alloc::buddy_slab::GlobalAllocator::dealloc (322 samples, 2.06%)ax_all..compiler_builtins::mem::memset (48 samples, 0.31%)alloc::collections::btree::node::drop_child::7 (329 samples, 2.10%)alloc:..core::mem::drop (329 samples, 2.10%)core::..os::mm::area::MapArea::drop (329 samples, 2.10%)os::mm..os::mm::page::Page::drop (329 samples, 2.10%)os::mm..ax_alloc::buddy_slab::GlobalAllocator::dealloc (329 samples, 2.10%)ax_all..core::ptr::drop_in_place<alloc::boxed::Box<[u8]>> (51 samples, 0.33%)alloc::collections::btree::node::drop_child::8 (289 samples, 1.85%)alloc..core::mem::drop (289 samples, 1.85%)core:..os::mm::area::MapArea::drop (289 samples, 1.85%)os::m..os::mm::page::Page::drop (289 samples, 1.85%)os::m..ax_alloc::buddy_slab::GlobalAllocator::dealloc (289 samples, 1.85%)ax_al..core::ptr::drop_in_place<alloc::boxed::Box<[u8]>> (53 samples, 0.34%)os::syscall::task::sys_execve (5,625 samples, 35.92%)os::syscall::task::sys_execveos::task::spawn_user_task (5,102 samples, 32.58%)os::task::spawn_user_taskos::task::Task::exec (5,102 samples, 32.58%)os::task::Task::execos::mm::memory_set::MemorySet::from_elf (5,102 samples, 32.58%)os::mm::memory_set::MemorySet::from_elfos::mm::memory_set::MemorySet::map_area (5,102 samples, 32.58%)os::mm::memory_set::MemorySet::map_areaalloc::sync::Arc<T,A>::drop_slow (5,102 samples, 32.58%)alloc::sync::Arc<T,A>::drop_slowcore::ptr::drop_in_place<os::mm::memory_set::MemorySet> (5,102 samples, 32.58%)core::ptr::drop_in_place<os::mm::memory_set::MemorySet>core::ptr::drop_in_place<alloc::sync::Arc<spin::rw_lock::RwLock<os::mm::memory_set::MemorySet>>> (5,102 samples, 32.58%)core::ptr::drop_in_place<alloc::sync::Arc<spin::rw_lock::RwLock<os::mm::memory_set::MemorySet>>>alloc::collections::btree::map::BTreeMap<K,V,A>::drop (5,102 samples, 32.58%)alloc::collections::btree::map::BTreeMap<K,V,A>::dropalloc::collections::btree::node::NodeRef::drop (5,102 samples, 32.58%)alloc::collections::btree::node::NodeRef::dropalloc::collections::btree::node::Handle::drop (5,102 samples, 32.58%)alloc::collections::btree::node::Handle::dropcore::ptr::drop_in_place<alloc::collections::btree::node::Handle<alloc::alloc::Global>> (5,102 samples, 32.58%)core::ptr::drop_in_place<alloc::collections::btree::node::Handle<alloc::alloc::Global>>alloc::collections::btree::node::drop_child::9 (277 samples, 1.77%)alloc..core::mem::drop (277 samples, 1.77%)core:..os::mm::area::MapArea::drop (277 samples, 1.77%)os::m..os::mm::page::Page::drop (277 samples, 1.77%)os::m..ax_alloc::buddy_slab::GlobalAllocator::dealloc (277 samples, 1.77%)ax_al..core::ptr::drop_in_place<alloc::boxed::Box<[u8]>> (49 samples, 0.31%)os::task::current (237 samples, 1.51%)os::..starry_process::thread::Thread::wait (237 samples, 1.51%)star..ax_task::wait_queue::WaitQueue::wait_until (237 samples, 1.51%)ax_t..ax_task::run_queue::AxRunQueue::block_current (237 samples, 1.51%)ax_t..ax_task::run_queue::AxRunQueue::resched (237 samples, 1.51%)ax_t..ax_task::run_queue::AxRunQueue::switch_to (237 samples, 1.51%)ax_t..riscv::register::sstatus::set_spie (237 samples, 1.51%)risc..ax_hal::arch::context::TaskContext::switch (237 samples, 1.51%)ax_h..core::ptr::drop_in_place<alloc::boxed::Box<[u8]>> (54 samples, 0.34%)compiler_builtins::mem::memset (264 samples, 1.69%)compi..all (15,660 samples, 100%)os::syscall::task::sys_waitpid (2,505 samples, 16.00%)os::syscall::task::sys_waitpidstarry_process::thread::Thread::wait (2,268 samples, 14.48%)starry_process::thread::Thread::waitax_task::wait_queue::WaitQueue::wait_until (2,268 samples, 14.48%)ax_task::wait_queue::WaitQueue::wait_untilax_task::run_queue::AxRunQueue::block_current (2,268 samples, 14.48%)ax_task::run_queue::AxRunQueue::block_currentax_task::run_queue::AxRunQueue::resched (2,268 samples, 14.48%)ax_task::run_queue::AxRunQueue::reschedax_task::run_queue::AxRunQueue::switch_to (2,268 samples, 14.48%)ax_task::run_queue::AxRunQueue::switch_toriscv::register::sstatus::set_spie (2,268 samples, 14.48%)riscv::register::sstatus::set_spieax_hal::arch::context::TaskContext::switch (2,268 samples, 14.48%)ax_hal::arch::context::TaskContext::switchcore::ptr::drop_in_place<alloc::boxed::Box<[u8]>> (451 samples, 2.88%)core::ptr:..compiler_builtins::mem::memset (60 samples, 0.38%) \ No newline at end of file diff --git a/docs/flamegraphs/qperf-long-chain-real.virtio-blk-patched.flamegraph.svg b/docs/flamegraphs/qperf-long-chain-real.virtio-blk-patched.flamegraph.svg new file mode 100644 index 0000000000..06631b97f1 --- /dev/null +++ b/docs/flamegraphs/qperf-long-chain-real.virtio-blk-patched.flamegraph.svg @@ -0,0 +1,491 @@ +StarryOS qperf Flame Graph Reset ZoomSearch <starry_kernel::mm::aspace::backend::Backend as starry_kernel::mm::aspace::backend::BackendOps>::populate (858 samples, 0.48%)0x109b (1,514 samples, 0.85%)0..<alloc::collections::btree::map::BTreeMap<u32, starry_kernel::syscall::ipc::shm::BiBTreeMap<i32, ax_memory_addr::addr::VirtAddr>>>::remove::<u32> (546 samples, 0.31%)<core::option::Option<(u32, starry_kernel::syscall::ipc::shm::BiBTreeMap<i32, ax_memory_addr::addr::VirtAddr>)>>::map::<starry_kernel::syscall::ipc::shm::BiBTreeMap<i32, ax_memory_addr::addr::VirtAddr>, <alloc::collections::btree::map::BTreeMap<u32, starry_kernel::syscall::ipc::shm::BiBTreeMap<i32, ax_memory_addr::addr::VirtAddr>>>::remove<u32>::{closure#0}> (546 samples, 0.31%)<core::option::Option<ax_task::future::poll::poll_io<ax_net_ng::unix::stream::StreamTransport, <ax_net_ng::unix::stream::StreamTransport as ax_net_ng::unix::TransportOps>::send<&mut dyn starry_kernel::file::ReadBuf>::{closure#0}, usize>::{closure#0}>>::as_pin_mut (700 samples, 0.39%)<core::option::Option<ax_task::future::poll::poll_io<ax_net_ng::vsock::stream::VsockStreamTransport, <ax_net_ng::vsock::stream::VsockStreamTransport as ax_net_ng::vsock::VsockTransportOps>::recv<&mut dyn starry_kernel::file::WriteBuf>::{closure#0}, usize>::{closure#0}>>::as_pin_mut (546 samples, 0.31%)<hashbrown::raw::FullBucketsIndices as core::iter::traits::iterator::Iterator>::next (19,622 samples, 10.97%)<hashbrown::raw::FullBucketsIndices as core..<hashbrown::raw::FullBucketsIndices>::next_impl (19,085 samples, 10.67%)<hashbrown::raw::FullBucketsIndices>::next..<hashbrown::raw::RawTable<(alloc::sync::Arc<[u8]>, ax_net_ng::unix::BindSlot)>>::reserve_rehash::<hashbrown::map::make_hasher<alloc::sync::Arc<[u8]>, ax_net_ng::unix::BindSlot, hashbrown::hasher::DefaultHashBuilder>::{closure#0}> (20,957 samples, 11.71%)<hashbrown::raw::RawTable<(alloc::sync::Arc<[u..<hashbrown::raw::RawTableInner>::reserve_rehash_inner::<allocator_api2::stable::alloc::global::Global> (20,952 samples, 11.71%)<hashbrown::raw::RawTableInner>::reserve_rehas..<hashbrown::raw::RawTableInner>::resize_inner::<allocator_api2::stable::alloc::global::Global> (20,945 samples, 11.71%)<hashbrown::raw::RawTableInner>::resize_inner:..<hashbrown::raw::RawTable<(smoltcp::wire::ip::Address, ax_net_ng::device::ethernet::PendingNeighbor)>>::remove_entry::<hashbrown::map::equivalent_key<smoltcp::wire::ip::Address, smoltcp::wire::ip::Address, ax_net_ng::device::ethernet::PendingNeighbor>::{closure#0}> (4,091 samples, 2.29%)<hashbr..<hashbrown::raw::RawTable<(usize, alloc::sync::Arc<starry_kernel::task::futex::FutexEntry>)>>::get::<hashbrown::map::equivalent_key<usize, usize, alloc::sync::Arc<starry_kernel::task::futex::FutexEntry>>::{closure#0}> (692 samples, 0.39%)<hashbrown::raw::RawTable<(usize, alloc::sync::Arc<starry_kernel::task::futex::FutexEntry>)>>::insert::<hashbrown::map::make_hasher<usize, alloc::sync::Arc<starry_kernel::task::futex::FutexEntry>, hashbrown::hasher::DefaultHashBuilder>::{closure#0}> (1,561 samples, 0.87%)<..<hashbrown::raw::RawTableInner>::rehash_in_place (29,142 samples, 16.29%)<hashbrown::raw::RawTableInner>::rehash_in_placehashbrown::util::likely (12,224 samples, 6.83%)hashbrown::util::likely<hashbrown::raw::RawTable<(usize, alloc::sync::Arc<starry_kernel::task::futex::FutexEntry>)>>::reserve_rehash::<hashbrown::map::make_hasher<usize, alloc::sync::Arc<starry_kernel::task::futex::FutexEntry>, hashbrown::hasher::DefaultHashBuilder>::{closure#0}> (30,425 samples, 17.01%)<hashbrown::raw::RawTable<(usize, alloc::sync::Arc<starry_kernel::ta..<hashbrown::raw::RawTableInner>::reserve_rehash_inner::<allocator_api2::stable::alloc::global::Global> (30,402 samples, 16.99%)<hashbrown::raw::RawTableInner>::reserve_rehash_inner::<allocator_ap..<hashbrown::raw::RawTableInner>::resize_inner::<allocator_api2::stable::alloc::global::Global> (926 samples, 0.52%)<starry_kernel::mm::aspace::backend::Backend as starry_kernel::mm::aspace::backend::BackendOps>::populate (1,559 samples, 0.87%)<..<rsext4::jbd2::jbdstruct::JournalSuperBllockS as rsext4::endian::DiskFormat>::from_disk_bytes (2,835 samples, 1.58%)<rse..starry_vm::alloc::vm_load_until_nul::<*const u8> (808 samples, 0.45%)<starry_kernel::mm::loader::load_user_app::{closure#3} as core::str::pattern::Pattern>::into_searcher (631 samples, 0.35%)<starry_kernel::pseudofs::dev::event::EventDev as starry_kernel::pseudofs::device::DeviceOps>::ioctl (647 samples, 0.36%)<starry_kernel::syscall::task::clone::CloneArgs>::do_clone (1,064 samples, 0.59%)<starry_kernel::syscall::task::clone::CloneArgs>::validate (28,394 samples, 15.87%)<starry_kernel::syscall::task::clone::CloneArgs>::validate<starry_kernel::task::timer::EVENT_NEW_TIMER as core::ops::deref::Deref>::deref (14,081 samples, 7.87%)<starry_kernel::task::timer::E..<starry_kernel::task::timer::ITimerType as core::fmt::Debug>::fmt (37,928 samples, 21.20%)<starry_kernel::task::timer::ITimerType as core::fmt::Debug>::fmtcore::ptr::drop_in_place::<async_channel::TrySendError<ax_net_ng::unix::dgram::Packet>> (605 samples, 0.34%)core::ptr::drop_in_place::<core::result::Result<alloc::boxed::Box<starry_kernel::syscall::net::cmsg::CMsg>, alloc::boxed::Box<dyn core::any::Any + core::marker::Send + core::marker::Sync>>> (621 samples, 0.35%)starry_kernel::pseudofs::dev::builder (1,639 samples, 0.92%)s..starry_kernel::pseudofs::dev::event::return_zero_bits (782 samples, 0.44%)starry_kernel::pseudofs::mount_all (793 samples, 0.44%)starry_kernel::syscall::net::opt::sys_setsockopt (1,390 samples, 0.78%)s..all (178,906 samples, 100%) \ No newline at end of file diff --git a/docs/flamegraphs/qperf-virtio-blk-baseline-fullstack.png b/docs/flamegraphs/qperf-virtio-blk-baseline-fullstack.png new file mode 100644 index 0000000000..3749aa758a Binary files /dev/null and b/docs/flamegraphs/qperf-virtio-blk-baseline-fullstack.png differ diff --git a/docs/flamegraphs/qperf-virtio-blk-readahead-fullstack.png b/docs/flamegraphs/qperf-virtio-blk-readahead-fullstack.png new file mode 100644 index 0000000000..37ca55c10a Binary files /dev/null and b/docs/flamegraphs/qperf-virtio-blk-readahead-fullstack.png differ diff --git a/docs/flamegraphs/target__qperf-integration-smoke__analyzer__flamegraph.svg b/docs/flamegraphs/target__qperf-integration-smoke__analyzer__flamegraph.svg new file mode 100644 index 0000000000..32aa5ce03a --- /dev/null +++ b/docs/flamegraphs/target__qperf-integration-smoke__analyzer__flamegraph.svg @@ -0,0 +1,491 @@ +StarryOS qperf Flame Graph Reset ZoomSearch <alloc[22389da7bd10ef6f]::collections::btree::map::BTreeMap<rsext4[d387a3b1449c130e]::bmalloc::AbsoluteBN, rsext4[d387a3b1449c130e]::cache::data_block::CachedBlock>>::insert+0x460 (3 samples, 0.51%)<alloc[22389da7bd10ef6f]::collections::btree::node::BalancingContext<rsext4[d387a3b1449c130e]::bmalloc::AbsoluteBN, rsext4[d387a3b1449c130e]::cache::data_block::CachedBlock>>::bulk_steal_left+0x42 (2 samples, 0.34%)<ax_alloc[e6793b4fc39b793d]::buddy_slab::GlobalAllocator>::alloc (7 samples, 1.19%)<a..<ax_alloc[e6793b4fc39b793d]::buddy_slab::GlobalAllocator>::alloc+0x20a (2 samples, 0.34%)<ax_alloc[e6793b4fc39b793d]::buddy_slab::GlobalAllocator>::alloc+0xc2 (2 samples, 0.34%)<ax_alloc[e6793b4fc39b793d]::buddy_slab::GlobalAllocator>::dealloc+0x11a (2 samples, 0.34%)<ax_alloc[e6793b4fc39b793d]::buddy_slab::GlobalAllocator>::dealloc+0x13e (2 samples, 0.34%)<ax_alloc[e6793b4fc39b793d]::buddy_slab::GlobalAllocator>::dealloc+0x144 (2 samples, 0.34%)<ax_alloc[e6793b4fc39b793d]::buddy_slab::GlobalAllocator>::dealloc+0x18 (2 samples, 0.34%)<ax_alloc[e6793b4fc39b793d]::buddy_slab::GlobalAllocator>::dealloc+0x37e (2 samples, 0.34%)<ax_alloc[e6793b4fc39b793d]::buddy_slab::GlobalAllocator>::dealloc+0x3a (2 samples, 0.34%)<ax_alloc[e6793b4fc39b793d]::buddy_slab::GlobalAllocator>::dealloc+0x4a (2 samples, 0.34%)<ax_alloc[e6793b4fc39b793d]::buddy_slab::GlobalAllocator>::dealloc+0x76 (2 samples, 0.34%)<ax_runtime[4ca9a3a5d57819d0]::devices::FsBlockDevice as ax_fs_ng[ae106d1ca4859199]::block::FsBlockDevice>::write_block+0x64a (2 samples, 0.34%)<ax_task[e1e9fe55ba492fb1]::run_queue::AxRunQueue>::switch_to+0x2fc (2 samples, 0.34%)<ax_task[e1e9fe55ba492fb1]::run_queue::AxRunQueue>::switch_to+0x300 (2 samples, 0.34%)<ax_task[e1e9fe55ba492fb1]::task::TaskInner>::current_check_preempt_pending+0x2e0 (2 samples, 0.34%)<rsext4[d387a3b1449c130e]::cache::data_block::DataBlockCache>::modify::<ax_fs_ng[ae106d1ca4859199]::fs::ext4::rsext4::Ext4Disk, rsext4[d387a3b1449c130e]::file::delete::try_remove_dentry_in_block<ax_fs_ng[ae106d1ca4859199]::fs::ext4::rsext4::Ext4Disk>::{closure#0}>+0x3e (6 samples, 1.02%)<r..<rsext4[d387a3b1449c130e]::cache::data_block::DataBlockCache>::modify::<ax_fs_ng[ae106d1ca4859199]::fs::ext4::rsext4::Ext4Disk, rsext4[d387a3b1449c130e]::file::delete::try_remove_dentry_in_block<ax_fs_ng[ae106d1ca4859199]::fs::ext4::rsext4::Ext4Disk>::{closure#0}>+0x4c (5 samples, 0.85%)<..<rsext4[d387a3b1449c130e]::cache::data_block::DataBlockCache>::modify::<ax_fs_ng[ae106d1ca4859199]::fs::ext4::rsext4::Ext4Disk, rsext4[d387a3b1449c130e]::file::delete::try_remove_dentry_in_block<ax_fs_ng[ae106d1ca4859199]::fs::ext4::rsext4::Ext4Disk>::{closure#0}>+0x4e (3 samples, 0.51%)<rsext4[d387a3b1449c130e]::cache::data_block::DataBlockCache>::modify::<ax_fs_ng[ae106d1ca4859199]::fs::ext4::rsext4::Ext4Disk, rsext4[d387a3b1449c130e]::file::delete::try_remove_dentry_in_block<ax_fs_ng[ae106d1ca4859199]::fs::ext4::rsext4::Ext4Disk>::{closure#0}>+0x58 (7 samples, 1.19%)<r..<rsext4[d387a3b1449c130e]::cache::data_block::DataBlockCache>::modify::<ax_fs_ng[ae106d1ca4859199]::fs::ext4::rsext4::Ext4Disk, rsext4[d387a3b1449c130e]::file::delete::try_remove_dentry_in_block<ax_fs_ng[ae106d1ca4859199]::fs::ext4::rsext4::Ext4Disk>::{closure#0}>+0xf4 (2 samples, 0.34%)<rsext4[d387a3b1449c130e]::cache::data_block::DataBlockCache>::modify::<ax_fs_ng[ae106d1ca4859199]::fs::ext4::rsext4::Ext4Disk, rsext4[d387a3b1449c130e]::file::rename::mv<ax_fs_ng[ae106d1ca4859199]::fs::ext4::rsext4::Ext4Disk>::{closure#0}>+0x1a (2 samples, 0.34%)<rsext4[d387a3b1449c130e]::cache::inode_table::InodeCache>::evict_lru::<ax_fs_ng[ae106d1ca4859199]::fs::ext4::rsext4::Ext4Disk>+0x3dc (2 samples, 0.34%)<virtio_drivers[764ba4b562043b66]::queue::VirtQueue<ax_driver[a4b561a240288da2]::virtio::VirtIoHalImpl, 16usize>>::add_notify_wait_pop::<virtio_drivers[764ba4b562043b66]::transport::pci::PciTransport>+0xaa (3 samples, 0.51%)<virtio_drivers[764ba4b562043b66]::queue::VirtQueue<ax_driver[a4b561a240288da2]::virtio::VirtIoHalImpl, 16usize>>::add_notify_wait_pop::<virtio_drivers[764ba4b562043b66]::transport::pci::PciTransport>+0xc8 (9 samples, 1.53%)<vir..<virtio_drivers[764ba4b562043b66]::queue::VirtQueue<ax_driver[a4b561a240288da2]::virtio::VirtIoHalImpl, 16usize>>::add_notify_wait_pop::<virtio_drivers[764ba4b562043b66]::transport::pci::PciTransport>+0xca (62 samples, 10.51%)<virtio_drivers[764ba4b562043b66]::queue:..<virtio_drivers[764ba4b562043b66]::queue::VirtQueue<ax_driver[a4b561a240288da2]::virtio::VirtIoHalImpl, 16usize>>::add_notify_wait_pop::<virtio_drivers[764ba4b562043b66]::transport::pci::PciTransport>+0xce (75 samples, 12.71%)<virtio_drivers[764ba4b562043b66]::queue::VirtQueue.._head+0x1144 (5 samples, 0.85%)_..compiler_builtins[7242cd7a182d5fa8]::int::specialized_div_rem::u128_div_rem+0x2d6 (2 samples, 0.34%)compiler_builtins[7242cd7a182d5fa8]::int::specialized_div_rem::u128_div_rem+0x2ec (3 samples, 0.51%)compiler_builtins[7242cd7a182d5fa8]::int::specialized_div_rem::u128_div_rem+0x2f2 (159 samples, 26.95%)compiler_builtins[7242cd7a182d5fa8]::int::specialized_div_rem::u128_div_rem+0x2f2compiler_builtins[7242cd7a182d5fa8]::int::specialized_div_rem::u128_div_rem+0x300 (3 samples, 0.51%)compiler_builtins[7242cd7a182d5fa8]::int::specialized_div_rem::u128_div_rem+0x32a (2 samples, 0.34%)compiler_builtins[7242cd7a182d5fa8]::int::specialized_div_rem::u128_div_rem+0x4a0 (2 samples, 0.34%)compiler_builtins[7242cd7a182d5fa8]::int::specialized_div_rem::u128_div_rem+0x5ba (3 samples, 0.51%)rsext4[d387a3b1449c130e]::dir::mkdir::mkdir_internal::<ax_fs_ng[ae106d1ca4859199]::fs::ext4::rsext4::Ext4Disk>+0x1c0 (11 samples, 1.86%)rsext..rsext4[d387a3b1449c130e]::dir::mkdir::mkdir_internal::<ax_fs_ng[ae106d1ca4859199]::fs::ext4::rsext4::Ext4Disk>+0x1c4 (6 samples, 1.02%)rs..rsext4[d387a3b1449c130e]::dir::mkdir::mkdir_internal::<ax_fs_ng[ae106d1ca4859199]::fs::ext4::rsext4::Ext4Disk>+0x1cc (4 samples, 0.68%)rsext4[d387a3b1449c130e]::dir::mkdir::mkdir_internal::<ax_fs_ng[ae106d1ca4859199]::fs::ext4::rsext4::Ext4Disk>+0x1d0 (12 samples, 2.03%)rsext4..rsext4[d387a3b1449c130e]::dir::mkdir::mkdir_internal::<ax_fs_ng[ae106d1ca4859199]::fs::ext4::rsext4::Ext4Disk>+0x1dc (8 samples, 1.36%)rse..rsext4[d387a3b1449c130e]::dir::mkdir::mkdir_internal::<ax_fs_ng[ae106d1ca4859199]::fs::ext4::rsext4::Ext4Disk>+0x220 (4 samples, 0.68%)rsext4[d387a3b1449c130e]::dir::mkdir::mkdir_internal::<ax_fs_ng[ae106d1ca4859199]::fs::ext4::rsext4::Ext4Disk>+0x23c (2 samples, 0.34%)all (590 samples, 100%) \ No newline at end of file diff --git a/docs/flamegraphs/target__qperf-integration-smoke__analyzer__flamegraph.virtio.svg b/docs/flamegraphs/target__qperf-integration-smoke__analyzer__flamegraph.virtio.svg new file mode 100644 index 0000000000..276a65fa65 --- /dev/null +++ b/docs/flamegraphs/target__qperf-integration-smoke__analyzer__flamegraph.virtio.svg @@ -0,0 +1,491 @@ +StarryOS qperf Flame Graph Reset ZoomSearch <virtio_drivers[764ba4b562043b66]::transport::pci::PciTransport>+0xa6 (1 samples, 0.63%)<virtio_drivers[764ba4b562043b66]::transport::pci::PciTransport>+0xaa (3 samples, 1.89%)<virt..<virtio_drivers[764ba4b562043b66]::transport::pci::PciTransport>+0xc8 (9 samples, 5.66%)<virtio_drivers[764ba..<virtio_drivers[764ba4b562043b66]::transport::pci::PciTransport>+0xca (62 samples, 38.99%)<virtio_drivers[764ba4b562043b66]::transport::pci::PciTransport>+0xca<virtio_drivers[764ba4b562043b66]::transport::pci::PciTransport>+0xce (75 samples, 47.17%)<virtio_drivers[764ba4b562043b66]::transport::pci::PciTransport>+0xce<virtio_drivers[764ba4b562043b66]::transport::pci::PciTransport>+0xe2 (1 samples, 0.63%)<virtio_drivers[764ba4b562043b66]::virtio::VirtIoHalImpl, 16usize>>::add+0x282 (1 samples, 0.63%)<virtio_drivers[764ba4b562043b66]::virtio::VirtIoHalImpl, 16usize>>::add+0xbe (1 samples, 0.63%)<virtio_drivers[764ba4b562043b66]::virtio::VirtIoHalImpl, 16usize>>::pop_used+0x120 (1 samples, 0.63%)<virtio_drivers[764ba4b562043b66]::virtio::VirtIoHalImpl, 16usize>>::pop_used+0xf8 (1 samples, 0.63%)ax_driver[a4b561a240288da2]::pci::take_virtio_transport+0xb0 (1 samples, 0.63%)ax_driver[a4b561a240288da2]::virtio::block::probe_pci+0xfea (1 samples, 0.63%)ax_driver[a4b561a240288da2]::virtio::input::probe_pci+0x6ec (1 samples, 0.63%)all (159 samples, 100%)ax_driver[a4b561a240288da2]::virtio::input::probe_pci+0x7a4 (1 samples, 0.63%) \ No newline at end of file diff --git a/docs/flamegraphs/target__qperf-validation__blk__perf__riscv64__latest__qperf__flamegraph.svg b/docs/flamegraphs/target__qperf-validation__blk__perf__riscv64__latest__qperf__flamegraph.svg new file mode 100644 index 0000000000..ee2616ebff --- /dev/null +++ b/docs/flamegraphs/target__qperf-validation__blk__perf__riscv64__latest__qperf__flamegraph.svg @@ -0,0 +1,491 @@ +StarryOS qperf Flame Graph Reset ZoomSearch _RINvMNtCsa9GpAcvErGs_14virtio_drivers5queueINtB3_9VirtQueueNtNtCscSq4qA0b9S3_9ax_driver6virtio13VirtIoHalImplKj10_E19add_notify_wait_popNtNtNtB5_9transport3pci12PciTransportEBZ_+0xa8 (3 samples, 0.51%)_RINvMNtCsa9GpAcvErGs_14virtio_drivers5queueINtB3_9VirtQueueNtNtCscSq4qA0b9S3_9ax_driver6virtio13VirtIoHalImplKj10_E19add_notify_wait_popNtNtNtB5_9transport3pci12PciTransportEBZ_+0xc6 (9 samples, 1.53%)_RIN.._RINvMNtCsa9GpAcvErGs_14virtio_drivers5queueINtB3_9VirtQueueNtNtCscSq4qA0b9S3_9ax_driver6virtio13VirtIoHalImplKj10_E19add_notify_wait_popNtNtNtB5_9transport3pci12PciTransportEBZ_+0xc8 (62 samples, 10.51%)_RINvMNtCsa9GpAcvErGs_14virtio_drivers5qu.._RINvMNtCsa9GpAcvErGs_14virtio_drivers5queueINtB3_9VirtQueueNtNtCscSq4qA0b9S3_9ax_driver6virtio13VirtIoHalImplKj10_E19add_notify_wait_popNtNtNtB5_9transport3pci12PciTransportEBZ_+0xcc (75 samples, 12.71%)_RINvMNtCsa9GpAcvErGs_14virtio_drivers5queueINtB3_9.._RINvMs_NtNtCsi9Y2sIRgCK0_6rsext45cache10data_blockNtB5_14DataBlockCache9evict_lruNtNtNtNtCse5NgyeWvL4u_8ax_fs_ng2fs4ext46rsext48Ext4DiskEB1p_+0x5a (6 samples, 1.02%)_R.._RINvMs_NtNtCsi9Y2sIRgCK0_6rsext45cache10data_blockNtB5_14DataBlockCache9evict_lruNtNtNtNtCse5NgyeWvL4u_8ax_fs_ng2fs4ext46rsext48Ext4DiskEB1p_+0x68 (5 samples, 0.85%)_.._RINvMs_NtNtCsi9Y2sIRgCK0_6rsext45cache10data_blockNtB5_14DataBlockCache9evict_lruNtNtNtNtCse5NgyeWvL4u_8ax_fs_ng2fs4ext46rsext48Ext4DiskEB1p_+0x6a (3 samples, 0.51%)_RINvMs_NtNtCsi9Y2sIRgCK0_6rsext45cache10data_blockNtB5_14DataBlockCache9evict_lruNtNtNtNtCse5NgyeWvL4u_8ax_fs_ng2fs4ext46rsext48Ext4DiskEB1p_+0x74 (7 samples, 1.19%)_R.._RNvMs2_NtCsjMNVNv9nEZt_8ax_alloc10buddy_slabNtB5_15GlobalAllocator5alloc (7 samples, 1.19%)_R.._RNvMsi_NtNtNtCs2W9OV9R0Aa1_5alloc11collections5btree3mapINtB5_8BTreeMapNtNtCsi9Y2sIRgCK0_6rsext47bmalloc10AbsoluteBNNtNtNtB1b_5cache10data_block11CachedBlockE6insertCse5NgyeWvL4u_8ax_fs_ng+0x42 (3 samples, 0.51%)_RNvNtCs9OcUSfjU0zs_17compiler_builtins3mem6memcpy+0x44 (3 samples, 0.51%)_RNvNtCs9OcUSfjU0zs_17compiler_builtins3mem6memcpy+0x4a (159 samples, 26.95%)_RNvNtCs9OcUSfjU0zs_17compiler_builtins3mem6memcpy+0x4a_RNvNtCs9OcUSfjU0zs_17compiler_builtins3mem6memcpy+0x58 (3 samples, 0.51%)_RNvNtCs9OcUSfjU0zs_17compiler_builtins3mem7memmove+0xf0 (3 samples, 0.51%)_RNvXsk_NtNtNtCs2W9OV9R0Aa1_5alloc11collections5btree3mapINtB5_4IterNtNtCsi9Y2sIRgCK0_6rsext47bmalloc10AbsoluteBNNtNtNtB17_5cache10data_block11CachedBlockENtNtNtNtCsgiRWr7r9Nzy_4core4iter6traits8iterator8Iterator4nextCse5NgyeWvL4u_8ax_fs_ng (11 samples, 1.86%)_RNvX.._RNvXsk_NtNtNtCs2W9OV9R0Aa1_5alloc11collections5btree3mapINtB5_4IterNtNtCsi9Y2sIRgCK0_6rsext47bmalloc10AbsoluteBNNtNtNtB17_5cache10data_block11CachedBlockENtNtNtNtCsgiRWr7r9Nzy_4core4iter6traits8iterator8Iterator4nextCse5NgyeWvL4u_8ax_fs_ng+0x10 (12 samples, 2.03%)_RNvXs.._RNvXsk_NtNtNtCs2W9OV9R0Aa1_5alloc11collections5btree3mapINtB5_4IterNtNtCsi9Y2sIRgCK0_6rsext47bmalloc10AbsoluteBNNtNtNtB17_5cache10data_block11CachedBlockENtNtNtNtCsgiRWr7r9Nzy_4core4iter6traits8iterator8Iterator4nextCse5NgyeWvL4u_8ax_fs_ng+0x1c (8 samples, 1.36%)_RN.._RNvXsk_NtNtNtCs2W9OV9R0Aa1_5alloc11collections5btree3mapINtB5_4IterNtNtCsi9Y2sIRgCK0_6rsext47bmalloc10AbsoluteBNNtNtNtB17_5cache10data_block11CachedBlockENtNtNtNtCsgiRWr7r9Nzy_4core4iter6traits8iterator8Iterator4nextCse5NgyeWvL4u_8ax_fs_ng+0x4 (6 samples, 1.02%)_R.._RNvXsk_NtNtNtCs2W9OV9R0Aa1_5alloc11collections5btree3mapINtB5_4IterNtNtCsi9Y2sIRgCK0_6rsext47bmalloc10AbsoluteBNNtNtNtB17_5cache10data_block11CachedBlockENtNtNtNtCsgiRWr7r9Nzy_4core4iter6traits8iterator8Iterator4nextCse5NgyeWvL4u_8ax_fs_ng+0x60 (4 samples, 0.68%)_RNvXsk_NtNtNtCs2W9OV9R0Aa1_5alloc11collections5btree3mapINtB5_4IterNtNtCsi9Y2sIRgCK0_6rsext47bmalloc10AbsoluteBNNtNtNtB17_5cache10data_block11CachedBlockENtNtNtNtCsgiRWr7r9Nzy_4core4iter6traits8iterator8Iterator4nextCse5NgyeWvL4u_8ax_fs_ng+0xc (4 samples, 0.68%)_head+0x1144 (5 samples, 0.85%)_..all (590 samples, 100%) \ No newline at end of file diff --git a/docs/flamegraphs/target__qperf-validation__missing-stop__perf__riscv64__latest__qperf__flamegraph.svg b/docs/flamegraphs/target__qperf-validation__missing-stop__perf__riscv64__latest__qperf__flamegraph.svg new file mode 100644 index 0000000000..18e8ea6af2 --- /dev/null +++ b/docs/flamegraphs/target__qperf-validation__missing-stop__perf__riscv64__latest__qperf__flamegraph.svg @@ -0,0 +1,491 @@ +StarryOS qperf Flame Graph Reset ZoomSearch 0x60157020 (1 samples, 0.51%)_RINvMs8_NtNtCseWxrHIpmU4v_8ax_fs_ng9highlevel4fileNtB6_11FileBackend7read_atQQShECsbgXMhWHegTz_13starry_kernel+0x90 (1 samples, 0.51%)_RINvMsW_NtNtNtCs2W9OV9R0Aa1_5alloc11collections5btree4nodeINtB6_6HandleINtB6_7NodeRefNtNtB6_6marker3MuttNtNtNtCse8JQZBARWTK_9ax_driver6virtio3net10RxInflightNtB1n_8InternalENtB1n_2KVE5splitNtNtBc_5alloc6GlobalEB1K_+0x11a (1 samples, 0.51%)_RINvMs_NtCsjoxaZGNdFP9_7ax_task10wait_queueNtB5_9WaitQueue10wait_untilNCNvMs2_NtCs2x05nxSvmHt_7ax_sync5mutexNtB1e_8RawMutex18lock_after_prepare0ECs41CxRoq78v7_10ax_display+0x434 (1 samples, 0.51%)_RINvMs_NtCsjoxaZGNdFP9_7ax_task10wait_queueNtB5_9WaitQueue10wait_untilNCNvMs2_NtCs2x05nxSvmHt_7ax_sync5mutexNtB1e_8RawMutex18lock_after_prepare0ECs41CxRoq78v7_10ax_display+0x45a (8 samples, 4.06%)_RINvMs_NtCsjo.._RINvMs_NtCsjoxaZGNdFP9_7ax_task10wait_queueNtB5_9WaitQueue10wait_untilNCNvMs2_NtCs2x05nxSvmHt_7ax_sync5mutexNtB1e_8RawMutex18lock_after_prepare0ECs41CxRoq78v7_10ax_display+0x466 (4 samples, 2.03%)_RINvM.._RINvNtCsgiRWr7r9Nzy_4core3ptr13drop_in_placeINtNtNtCse8JQZBARWTK_9ax_driver6virtio5block10BlockQueueNtNtNtCsa9GpAcvErGs_14virtio_drivers9transport3pci12PciTransportEEBN_+0x3c (6 samples, 3.05%)_RINvNtCsg.._RNSNvYNCNvMs1_NtNtNtNtNtCsbgXMhWHegTz_13starry_kernel8pseudofs3dev3tty8terminal5ldiscINtBc_14LineDisciplineNtNtBg_4ntty7ConsoleB1H_E20spawn_polling_reader0INtNtNtCsgiRWr7r9Nzy_4core3ops8function6FnOnceuE9call_once6vtableBm_+0x10a (1 samples, 0.51%)_RNSNvYNCNvMs1_NtNtNtNtNtCsbgXMhWHegTz_13starry_kernel8pseudofs3dev3tty8terminal5ldiscINtBc_14LineDisciplineNtNtBg_4ntty7ConsoleB1H_E20spawn_polling_reader0INtNtNtCsgiRWr7r9Nzy_4core3ops8function6FnOnceuE9call_once6vtableBm_+0x11a (2 samples, 1.02%)_R.._RNSNvYNCNvMs1_NtNtNtNtNtCsbgXMhWHegTz_13starry_kernel8pseudofs3dev3tty8terminal5ldiscINtBc_14LineDisciplineNtNtBg_4ntty7ConsoleB1H_E20spawn_polling_reader0INtNtNtCsgiRWr7r9Nzy_4core3ops8function6FnOnceuE9call_once6vtableBm_+0x146 (2 samples, 1.02%)_R.._RNSNvYNCNvMs1_NtNtNtNtNtCsbgXMhWHegTz_13starry_kernel8pseudofs3dev3tty8terminal5ldiscINtBc_14LineDisciplineNtNtBg_4ntty7ConsoleB1H_E20spawn_polling_reader0INtNtNtCsgiRWr7r9Nzy_4core3ops8function6FnOnceuE9call_once6vtableBm_+0x150 (6 samples, 3.05%)_RNSNvYNCN.._RNSNvYNCNvMs1_NtNtNtNtNtCsbgXMhWHegTz_13starry_kernel8pseudofs3dev3tty8terminal5ldiscINtBc_14LineDisciplineNtNtBg_4ntty7ConsoleB1H_E20spawn_polling_reader0INtNtNtCsgiRWr7r9Nzy_4core3ops8function6FnOnceuE9call_once6vtableBm_+0x162 (1 samples, 0.51%)_RNSNvYNCNvMs1_NtNtNtNtNtCsbgXMhWHegTz_13starry_kernel8pseudofs3dev3tty8terminal5ldiscINtBc_14LineDisciplineNtNtBg_4ntty7ConsoleB1H_E20spawn_polling_reader0INtNtNtCsgiRWr7r9Nzy_4core3ops8function6FnOnceuE9call_once6vtableBm_+0x166 (1 samples, 0.51%)_RNSNvYNCNvMs1_NtNtNtNtNtCsbgXMhWHegTz_13starry_kernel8pseudofs3dev3tty8terminal5ldiscINtBc_14LineDisciplineNtNtBg_4ntty7ConsoleB1H_E20spawn_polling_reader0INtNtNtCsgiRWr7r9Nzy_4core3ops8function6FnOnceuE9call_once6vtableBm_+0x182 (1 samples, 0.51%)_RNSNvYNCNvMs1_NtNtNtNtNtCsbgXMhWHegTz_13starry_kernel8pseudofs3dev3tty8terminal5ldiscINtBc_14LineDisciplineNtNtBg_4ntty7ConsoleB1H_E20spawn_polling_reader0INtNtNtCsgiRWr7r9Nzy_4core3ops8function6FnOnceuE9call_once6vtableBm_+0x194 (3 samples, 1.52%)_RNS.._RNSNvYNCNvMs1_NtNtNtNtNtCsbgXMhWHegTz_13starry_kernel8pseudofs3dev3tty8terminal5ldiscINtBc_14LineDisciplineNtNtBg_4ntty7ConsoleB1H_E20spawn_polling_reader0INtNtNtCsgiRWr7r9Nzy_4core3ops8function6FnOnceuE9call_once6vtableBm_+0x5c (1 samples, 0.51%)_RNSNvYNCNvMs1_NtNtNtNtNtCsbgXMhWHegTz_13starry_kernel8pseudofs3dev3tty8terminal5ldiscINtBc_14LineDisciplineNtNtBg_4ntty7ConsoleB1H_E20spawn_polling_reader0INtNtNtCsgiRWr7r9Nzy_4core3ops8function6FnOnceuE9call_once6vtableBm_+0x8a8 (3 samples, 1.52%)_RNS.._RNSNvYNCNvMs1_NtNtNtNtNtCsbgXMhWHegTz_13starry_kernel8pseudofs3dev3tty8terminal5ldiscINtBc_14LineDisciplineNtNtBg_4ntty7ConsoleB1H_E20spawn_polling_reader0INtNtNtCsgiRWr7r9Nzy_4core3ops8function6FnOnceuE9call_once6vtableBm_+0x8c8 (2 samples, 1.02%)_R.._RNSNvYNCNvMs1_NtNtNtNtNtCsbgXMhWHegTz_13starry_kernel8pseudofs3dev3tty8terminal5ldiscINtBc_14LineDisciplineNtNtBg_4ntty7ConsoleB1H_E20spawn_polling_reader0INtNtNtCsgiRWr7r9Nzy_4core3ops8function6FnOnceuE9call_once6vtableBm_+0x8e (1 samples, 0.51%)_RNSNvYNCNvMs1_NtNtNtNtNtCsbgXMhWHegTz_13starry_kernel8pseudofs3dev3tty8terminal5ldiscINtBc_14LineDisciplineNtNtBg_4ntty7ConsoleB1H_E20spawn_polling_reader0INtNtNtCsgiRWr7r9Nzy_4core3ops8function6FnOnceuE9call_once6vtableBm_+0xbe (2 samples, 1.02%)_R.._RNSNvYNCNvMs1_NtNtNtNtNtCsbgXMhWHegTz_13starry_kernel8pseudofs3dev3tty8terminal5ldiscINtBc_14LineDisciplineNtNtBg_4ntty7ConsoleB1H_E20spawn_polling_reader0INtNtNtCsgiRWr7r9Nzy_4core3ops8function6FnOnceuE9call_once6vtableBm_+0xc2 (1 samples, 0.51%)_RNSNvYNCNvMs1_NtNtNtNtNtCsbgXMhWHegTz_13starry_kernel8pseudofs3dev3tty8terminal5ldiscINtBc_14LineDisciplineNtNtBg_4ntty7ConsoleB1H_E20spawn_polling_reader0INtNtNtCsgiRWr7r9Nzy_4core3ops8function6FnOnceuE9call_once6vtableBm_+0xe4 (1 samples, 0.51%)_RNvCs41CxRoq78v7_10ax_display17framebuffer_flush+0x18 (1 samples, 0.51%)_RNvMs0_Cse38cudTX6ZT_11ax_lazyinitINtB5_8LazyInitINtNtCs4iPnrq9U4Rv_8lock_api5mutex5MutexNtNtCs2x05nxSvmHt_7ax_sync5mutex8RawMutexNtNtCs41CxRoq78v7_10ax_display6device19ErasedDisplayDeviceEE13panic_messageB28_+0x10 (1 samples, 0.51%)_RNvMs10_NtNtNtCs2W9OV9R0Aa1_5alloc11collections5btree4nodeINtB6_16BalancingContexttNtNtNtCse8JQZBARWTK_9ax_driver6virtio3net10RxInflightE15bulk_steal_leftB1p_+0x1c8 (3 samples, 1.52%)_RNv.._RNvMs10_NtNtNtCs2W9OV9R0Aa1_5alloc11collections5btree4nodeINtB6_16BalancingContexttNtNtNtCse8JQZBARWTK_9ax_driver6virtio3net10RxInflightE15bulk_steal_leftB1p_+0x1cc (2 samples, 1.02%)_R.._RNvMs1_NtCsjoxaZGNdFP9_7ax_task9run_queueINtB5_18CurrentRunQueueRefNtCs9J4N2FZfJib_15ax_kernel_guard16NoPreemptIrqSaveE13yield_currentB7_ (1 samples, 0.51%)_RNvMs1_NtCsjoxaZGNdFP9_7ax_task9run_queueINtB5_18CurrentRunQueueRefNtCs9J4N2FZfJib_15ax_kernel_guard16NoPreemptIrqSaveE13yield_currentB7_+0x116 (1 samples, 0.51%)_RNvMs1_NtCsjoxaZGNdFP9_7ax_task9run_queueINtB5_18CurrentRunQueueRefNtCs9J4N2FZfJib_15ax_kernel_guard16NoPreemptIrqSaveE13yield_currentB7_+0x11c (3 samples, 1.52%)_RNv.._RNvMs1_NtCsjoxaZGNdFP9_7ax_task9run_queueINtB5_18CurrentRunQueueRefNtCs9J4N2FZfJib_15ax_kernel_guard16NoPreemptIrqSaveE13yield_currentB7_+0x166 (1 samples, 0.51%)_RNvMs1_NtCsjoxaZGNdFP9_7ax_task9run_queueINtB5_18CurrentRunQueueRefNtCs9J4N2FZfJib_15ax_kernel_guard16NoPreemptIrqSaveE13yield_currentB7_+0x176 (2 samples, 1.02%)_R.._RNvMs1_NtCsjoxaZGNdFP9_7ax_task9run_queueINtB5_18CurrentRunQueueRefNtCs9J4N2FZfJib_15ax_kernel_guard16NoPreemptIrqSaveE13yield_currentB7_+0x17a (1 samples, 0.51%)_RNvMs1_NtCsjoxaZGNdFP9_7ax_task9run_queueINtB5_18CurrentRunQueueRefNtCs9J4N2FZfJib_15ax_kernel_guard16NoPreemptIrqSaveE13yield_currentB7_+0x1a0 (1 samples, 0.51%)_RNvMs1_NtCsjoxaZGNdFP9_7ax_task9run_queueINtB5_18CurrentRunQueueRefNtCs9J4N2FZfJib_15ax_kernel_guard16NoPreemptIrqSaveE13yield_currentB7_+0x220 (1 samples, 0.51%)_RNvMs1_NtCsjoxaZGNdFP9_7ax_task9run_queueINtB5_18CurrentRunQueueRefNtCs9J4N2FZfJib_15ax_kernel_guard16NoPreemptIrqSaveE13yield_currentB7_+0x254 (2 samples, 1.02%)_R.._RNvMs1_NtCsjoxaZGNdFP9_7ax_task9run_queueINtB5_18CurrentRunQueueRefNtCs9J4N2FZfJib_15ax_kernel_guard16NoPreemptIrqSaveE13yield_currentB7_+0x2e4 (2 samples, 1.02%)_R.._RNvMs1_NtCsjoxaZGNdFP9_7ax_task9run_queueINtB5_18CurrentRunQueueRefNtCs9J4N2FZfJib_15ax_kernel_guard16NoPreemptIrqSaveE13yield_currentB7_+0xda (1 samples, 0.51%)_RNvMs1_NtCsjoxaZGNdFP9_7ax_task9run_queueINtB5_18CurrentRunQueueRefNtCs9J4N2FZfJib_15ax_kernel_guard16NoPreemptIrqSaveE13yield_currentB7_+0xec (1 samples, 0.51%)_RNvMs2_NtCsjMNVNv9nEZt_8ax_alloc10buddy_slabNtB5_15GlobalAllocator11alloc_pages+0x80 (2 samples, 1.02%)_R.._RNvMs2_NtCsjMNVNv9nEZt_8ax_alloc10buddy_slabNtB5_15GlobalAllocator11alloc_pages+0x9e (1 samples, 0.51%)_RNvMs2_NtCsjMNVNv9nEZt_8ax_alloc10buddy_slabNtB5_15GlobalAllocator11alloc_pages+0xd6 (1 samples, 0.51%)_RNvMs2_NtCsjMNVNv9nEZt_8ax_alloc10buddy_slabNtB5_15GlobalAllocator11alloc_pages+0xdc (1 samples, 0.51%)_RNvMs2_NtCsjMNVNv9nEZt_8ax_alloc10buddy_slabNtB5_15GlobalAllocator11alloc_pages+0xf8 (2 samples, 1.02%)_R.._RNvMs2_NtCsjoxaZGNdFP9_7ax_task9run_queueNtB5_10AxRunQueue7resched (1 samples, 0.51%)_RNvMs2_NtCsjoxaZGNdFP9_7ax_task9run_queueNtB5_10AxRunQueue7resched+0x18 (1 samples, 0.51%)_RNvMs2_NtCsjoxaZGNdFP9_7ax_task9run_queueNtB5_10AxRunQueue7resched+0x2a (1 samples, 0.51%)_RNvMs2_NtCsjoxaZGNdFP9_7ax_task9run_queueNtB5_10AxRunQueue7resched+0x2e (1 samples, 0.51%)_RNvMs2_NtCsjoxaZGNdFP9_7ax_task9run_queueNtB5_10AxRunQueue7resched+0x78 (3 samples, 1.52%)_RNv.._RNvMs2_NtCsjoxaZGNdFP9_7ax_task9run_queueNtB5_10AxRunQueue7resched+0xa8 (1 samples, 0.51%)_RNvMs2_NtCsjoxaZGNdFP9_7ax_task9run_queueNtB5_10AxRunQueue7resched+0xb2 (4 samples, 2.03%)_RNvMs.._RNvMs2_NtCsjoxaZGNdFP9_7ax_task9run_queueNtB5_10AxRunQueue7resched+0xd2 (2 samples, 1.02%)_R.._RNvMs2_NtCsjoxaZGNdFP9_7ax_task9run_queueNtB5_10AxRunQueue7resched+0xd4 (2 samples, 1.02%)_R.._RNvMs2_NtCsjoxaZGNdFP9_7ax_task9run_queueNtB5_10AxRunQueue9switch_to (1 samples, 0.51%)_RNvMs2_NtCsjoxaZGNdFP9_7ax_task9run_queueNtB5_10AxRunQueue9switch_to+0x110 (1 samples, 0.51%)_RNvMs2_NtCsjoxaZGNdFP9_7ax_task9run_queueNtB5_10AxRunQueue9switch_to+0x128 (1 samples, 0.51%)_RNvMs2_NtCsjoxaZGNdFP9_7ax_task9run_queueNtB5_10AxRunQueue9switch_to+0x1e (2 samples, 1.02%)_R.._RNvMs2_NtCsjoxaZGNdFP9_7ax_task9run_queueNtB5_10AxRunQueue9switch_to+0x24 (1 samples, 0.51%)_RNvMs3_NtCs2W9OV9R0Aa1_5alloc3stre12to_uppercase+0x434 (3 samples, 1.52%)_RNv.._RNvMs3_NtCs2W9OV9R0Aa1_5alloc3stre12to_uppercase+0x440 (3 samples, 1.52%)_RNv.._RNvMs3_NtCs2W9OV9R0Aa1_5alloc3stre12to_uppercase+0x44a (1 samples, 0.51%)_RNvMs3_NtCsjoxaZGNdFP9_7ax_task4taskNtB5_9TaskInner29current_check_preempt_pending (1 samples, 0.51%)_RNvMs3_NtCsjoxaZGNdFP9_7ax_task4taskNtB5_9TaskInner29current_check_preempt_pending+0x18 (1 samples, 0.51%)_RNvMs3_NtCsjoxaZGNdFP9_7ax_task4taskNtB5_9TaskInner29current_check_preempt_pending+0x38 (6 samples, 3.05%)_RNvMs3_Nt.._RNvMs3_NtCsjoxaZGNdFP9_7ax_task4taskNtB5_9TaskInner29current_check_preempt_pending+0x3c (2 samples, 1.02%)_R.._RNvMs3_NtCsjoxaZGNdFP9_7ax_task4taskNtB5_9TaskInner29current_check_preempt_pending+0x4e (3 samples, 1.52%)_RNv.._RNvMs_NtCs9mQrtDfyiSw_23ax_page_table_multiarch6bits64INtB4_11PageTable64INtNtNtB6_4arch5riscv12Sv39MetaDataNtNtCsfSd9zSsLkSz_14ax_memory_addr4addr8VirtAddrENtNtNtCscH7W0PCiXdV_19ax_page_table_entry4arch5riscv7Rv64PTENtNtCs9BjQ6OswnRJ_6ax_hal6paging17PagingHandlerImplE13get_entry_mutCsbgXMhWHegTz_13starry_kernel+0x7e (1 samples, 0.51%)_RNvNtCsjoxaZGNdFP9_7ax_task3api9yield_now (1 samples, 0.51%)_RNvNtCsjoxaZGNdFP9_7ax_task3api9yield_now+0x10 (2 samples, 1.02%)_R.._RNvNtCsjoxaZGNdFP9_7ax_task3api9yield_now+0x14 (1 samples, 0.51%)_RNvNtCsjoxaZGNdFP9_7ax_task3api9yield_now+0x34 (2 samples, 1.02%)_R.._RNvNtCsjoxaZGNdFP9_7ax_task3api9yield_now+0x3e (3 samples, 1.52%)_RNv.._RNvNtCsjoxaZGNdFP9_7ax_task3api9yield_now+0x42 (1 samples, 0.51%)_RNvNtCsjoxaZGNdFP9_7ax_task3api9yield_now+0x50 (1 samples, 0.51%)_RNvNtCsjoxaZGNdFP9_7ax_task3api9yield_now+0x52 (1 samples, 0.51%)_RNvNtCsjoxaZGNdFP9_7ax_task3api9yield_now+0x60 (3 samples, 1.52%)_RNv.._RNvNtCsjoxaZGNdFP9_7ax_task3api9yield_now+0x82 (3 samples, 1.52%)_RNv.._RNvNtCsjoxaZGNdFP9_7ax_task3api9yield_now+0x90 (1 samples, 0.51%)_RNvNtCsjoxaZGNdFP9_7ax_task3api9yield_now+0x92 (1 samples, 0.51%)_RNvNtCsjoxaZGNdFP9_7ax_task3api9yield_now+0xa8 (1 samples, 0.51%)_RNvNtCsjoxaZGNdFP9_7ax_task3api9yield_now+0xac (2 samples, 1.02%)_R.._RNvNtCsjoxaZGNdFP9_7ax_task3api9yield_now+0xb0 (1 samples, 0.51%)_RNvNtCsjoxaZGNdFP9_7ax_task3api9yield_now+0xbe (2 samples, 1.02%)_R.._RNvNtCsjoxaZGNdFP9_7ax_task3api9yield_now+0xc0 (2 samples, 1.02%)_R.._RNvNtCsjoxaZGNdFP9_7ax_task3api9yield_now+0xd0 (2 samples, 1.02%)_R.._RNvXs2_NtNtCse8JQZBARWTK_9ax_driver6virtio5blockINtB5_10BlockQueueNtNtNtCsa9GpAcvErGs_14virtio_drivers9transport3pci12PciTransportENtCsc1APIdyTegp_10rdif_block6IQueue11buff_configB9_ (1 samples, 0.51%)_RNvXs2_NtNtCse8JQZBARWTK_9ax_driver6virtio5blockINtB5_10BlockQueueNtNtNtCsa9GpAcvErGs_14virtio_drivers9transport3pci12PciTransportENtCsc1APIdyTegp_10rdif_block6IQueue14submit_requestB9_+0x1c (2 samples, 1.02%)_R.._RNvXs2_NtNtCse8JQZBARWTK_9ax_driver6virtio5blockINtB5_10BlockQueueNtNtNtCsa9GpAcvErGs_14virtio_drivers9transport3pci12PciTransportENtCsc1APIdyTegp_10rdif_block6IQueue14submit_requestB9_+0x20 (12 samples, 6.09%)_RNvXs2_NtNtCse8JQZBARW.._RNvXs2_NtNtCse8JQZBARWTK_9ax_driver6virtio5blockINtB5_10BlockQueueNtNtNtCsa9GpAcvErGs_14virtio_drivers9transport3pci12PciTransportENtCsc1APIdyTegp_10rdif_block6IQueue14submit_requestB9_+0x3e (2 samples, 1.02%)_R.._head+0x4f8 (5 samples, 2.54%)_head+0x.._head+0x504 (2 samples, 1.02%)_h.._head+0x534 (2 samples, 1.02%)_h.._head+0x53e (2 samples, 1.02%)_h.._head+0x588 (1 samples, 0.51%)_head+0x594 (1 samples, 0.51%)_head+0x59a (3 samples, 1.52%)_hea.._head+0x5ae (3 samples, 1.52%)_hea.._head+0x5b6 (2 samples, 1.02%)_h.._head+0x624 (3 samples, 1.52%)_hea..all (197 samples, 100%)_head+0x62c (2 samples, 1.02%)_h.. \ No newline at end of file diff --git a/docs/flamegraphs/target__qperf-validation__net-container__perf__riscv64__latest__qperf__flamegraph.svg b/docs/flamegraphs/target__qperf-validation__net-container__perf__riscv64__latest__qperf__flamegraph.svg new file mode 100644 index 0000000000..a99b0a0361 --- /dev/null +++ b/docs/flamegraphs/target__qperf-validation__net-container__perf__riscv64__latest__qperf__flamegraph.svg @@ -0,0 +1,491 @@ +StarryOS qperf Flame Graph Reset ZoomSearch _RNvMs2_NtCsjMNVNv9nEZt_8ax_alloc10buddy_slabNtB5_15GlobalAllocator5alloc+0x1fc (3 samples, 0.42%)_RNvMs2_NtCsjMNVNv9nEZt_8ax_alloc10buddy_slabNtB5_15GlobalAllocator5alloc+0x44 (3 samples, 0.42%)_RNvMs2_NtCsjMNVNv9nEZt_8ax_alloc10buddy_slabNtB5_15GlobalAllocator5alloc+0xc2 (4 samples, 0.55%)_RNvMs3_NtCs6cGdyZajV9I_7ax_task4taskNtB5_9TaskInner29current_check_preempt_pending (4 samples, 0.55%)_RNvMs3_NtCs6cGdyZajV9I_7ax_task4taskNtB5_9TaskInner29current_check_preempt_pending+0x18 (4 samples, 0.55%)_RNvMs3_NtCs6cGdyZajV9I_7ax_task4taskNtB5_9TaskInner29current_check_preempt_pending+0x38 (3 samples, 0.42%)_RNvMs3_NtCs6cGdyZajV9I_7ax_task4taskNtB5_9TaskInner29current_check_preempt_pending+0x4e (4 samples, 0.55%)_RNvMs4_NtNtCs9Ip9RJq8yox_9ax_net_ng6device6driverNtB5_11RdNetDriver19prefetch_rx_packets (3 samples, 0.42%)_RNvNtCs9OcUSfjU0zs_17compiler_builtins3mem6memcpy (6 samples, 0.83%)_.._RNvNtCs9OcUSfjU0zs_17compiler_builtins3mem6memcpy+0x10c (61 samples, 8.45%)_RNvNtCs9OcUSfjU0zs_17compiler_bu.._RNvNtCs9OcUSfjU0zs_17compiler_builtins3mem6memcpy+0x4a (113 samples, 15.65%)_RNvNtCs9OcUSfjU0zs_17compiler_builtins3mem6memcpy+0x4a_RNvNtCs9OcUSfjU0zs_17compiler_builtins3mem6memcpy+0x58 (4 samples, 0.55%)_RNvNtCs9OcUSfjU0zs_17compiler_builtins3mem6memcpy+0x66 (3 samples, 0.42%)_RNvNtCs9OcUSfjU0zs_17compiler_builtins3mem6memcpy+0x72 (4 samples, 0.55%)_RNvNtCs9OcUSfjU0zs_17compiler_builtins3mem6memcpy+0x8 (4 samples, 0.55%)_RNvNtCs9OcUSfjU0zs_17compiler_builtins3mem6memcpy+0x82 (9 samples, 1.25%)_RN.._RNvNtCs9OcUSfjU0zs_17compiler_builtins3mem7memmove (3 samples, 0.42%)_RNvNtCs9OcUSfjU0zs_17compiler_builtins3mem7memmove+0x2a4 (42 samples, 5.82%)_RNvNtCs9OcUSfjU0zs_17.._RNvNtCs9OcUSfjU0zs_17compiler_builtins3mem7memmove+0x6c (12 samples, 1.66%)_RNv.._RNvNtCs9OcUSfjU0zs_17compiler_builtins3mem7memmove+0xf0 (6 samples, 0.83%)_.._RNvNtNtNtCs4bLJakJfdhC_7smoltcp4wire2ip8checksum4data+0x22 (9 samples, 1.25%)_RN.._RNvXs8_NtNtCscSq4qA0b9S3_9ax_driver6virtio3netINtB5_10NetTxQueueNtNtNtCsa9GpAcvErGs_14virtio_drivers9transport3pci12PciTransportENtCsfcOzc4h9Az9_8rdif_eth8ITxQueue6submitB9_+0x282 (5 samples, 0.69%)_RNvXs9_NtNtCscSq4qA0b9S3_9ax_driver6virtio3netINtB5_10NetRxQueueNtNtNtCsa9GpAcvErGs_14virtio_drivers9transport3pci12PciTransportENtCsfcOzc4h9Az9_8rdif_eth8IRxQueue6submitB9_+0x22c (30 samples, 4.16%)_RNvXs9_NtNtCsc.._RNvXs_NtCsjMNVNv9nEZt_8ax_alloc10buddy_slabNtB4_10PercpuSlabNtNtCs4fiTdtanek2_20buddy_slab_allocator4slab9SlabTrait5allocB6_+0xfa (18 samples, 2.49%)_RNvXs_N.._RNvXs_NtCsjMNVNv9nEZt_8ax_alloc10buddy_slabNtB4_10PercpuSlabNtNtCs4fiTdtanek2_20buddy_slab_allocator4slab9SlabTrait5allocB6_+0xfc (3 samples, 0.42%)_head+0x1000 (9 samples, 1.25%)_he.._head+0x11a2 (22 samples, 3.05%)_head+0x11.._head+0x11be (3 samples, 0.42%)memcpy (6 samples, 0.83%)m..all (722 samples, 100%)memmove (5 samples, 0.69%) \ No newline at end of file diff --git a/docs/flamegraphs/target__qperf-validation__net__perf__riscv64__latest__qperf__flamegraph.svg b/docs/flamegraphs/target__qperf-validation__net__perf__riscv64__latest__qperf__flamegraph.svg new file mode 100644 index 0000000000..44152e5668 --- /dev/null +++ b/docs/flamegraphs/target__qperf-validation__net__perf__riscv64__latest__qperf__flamegraph.svg @@ -0,0 +1,491 @@ +StarryOS qperf Flame Graph Reset ZoomSearch 0x6015684e (1 samples, 1.79%)0x601..0x60158bbe (1 samples, 1.79%)0x601..0x93d68 (1 samples, 1.79%)0x93d.._RNvMs2_NtCsjMNVNv9nEZt_8ax_alloc10buddy_slabNtB5_15GlobalAllocator5alloc (1 samples, 1.79%)_RNvM.._RNvMs2_NtCsjMNVNv9nEZt_8ax_alloc10buddy_slabNtB5_15GlobalAllocator5alloc+0x1de (1 samples, 1.79%)_RNvM.._RNvMs2_NtCsjMNVNv9nEZt_8ax_alloc10buddy_slabNtB5_15GlobalAllocator5alloc+0x22 (1 samples, 1.79%)_RNvM.._RNvMs2_NtCsjMNVNv9nEZt_8ax_alloc10buddy_slabNtB5_15GlobalAllocator5alloc+0x25c (1 samples, 1.79%)_RNvM.._RNvMs2_NtCsjMNVNv9nEZt_8ax_alloc10buddy_slabNtB5_15GlobalAllocator5alloc+0x26a (1 samples, 1.79%)_RNvM.._RNvMs2_NtCsjMNVNv9nEZt_8ax_alloc10buddy_slabNtB5_15GlobalAllocator5alloc+0x56 (1 samples, 1.79%)_RNvM.._RNvMs2_NtCsjMNVNv9nEZt_8ax_alloc10buddy_slabNtB5_15GlobalAllocator5alloc+0x70 (1 samples, 1.79%)_RNvM.._RNvMs2_NtCsjMNVNv9nEZt_8ax_alloc10buddy_slabNtB5_15GlobalAllocator5alloc+0x98 (2 samples, 3.57%)_RNvMs2_NtCs.._RNvMs2_NtCsjMNVNv9nEZt_8ax_alloc10buddy_slabNtB5_15GlobalAllocator5alloc+0xa2 (1 samples, 1.79%)_RNvM.._RNvMs2_NtCsjMNVNv9nEZt_8ax_alloc10buddy_slabNtB5_15GlobalAllocator7dealloc+0x32a (1 samples, 1.79%)_RNvM.._RNvMs3_NtCs6cGdyZajV9I_7ax_task4taskNtB5_9TaskInner29current_check_preempt_pending (2 samples, 3.57%)_RNvMs3_NtCs.._RNvMs3_NtCs6cGdyZajV9I_7ax_task4taskNtB5_9TaskInner29current_check_preempt_pending+0x38 (2 samples, 3.57%)_RNvMs3_NtCs.._RNvMs_NtCs6cGdyZajV9I_7ax_task10wait_queueNtB4_9WaitQueue10notify_one+0x54 (1 samples, 1.79%)_RNvM.._RNvMs_NtCs9Ip9RJq8yox_9ax_net_ng12listen_tableNtB4_11ListenTable10can_listen+0x74 (1 samples, 1.79%)_RNvM.._RNvMs_NtCs9Ip9RJq8yox_9ax_net_ng12listen_tableNtB4_11ListenTable3new+0x2e (1 samples, 1.79%)_RNvM.._RNvMs_NtCs9Ip9RJq8yox_9ax_net_ng12listen_tableNtB4_11ListenTable3new+0x3e (1 samples, 1.79%)_RNvM.._RNvNtCs9OcUSfjU0zs_17compiler_builtins3mem6memcpy+0x4a (1 samples, 1.79%)_RNvN.._RNvNtCs9OcUSfjU0zs_17compiler_builtins3mem6memset+0x4e (1 samples, 1.79%)_RNvN.._RNvNtNtCscSq4qA0b9S3_9ax_driver3pci3fdt18probe_generic_ecam+0x21a2 (3 samples, 5.36%)_RNvNtNtCscSq4qA0b9S.._RNvXs_NtCsjMNVNv9nEZt_8ax_alloc10buddy_slabNtB4_10PercpuSlabNtNtCs4fiTdtanek2_20buddy_slab_allocator4slab9SlabTrait5allocB6_ (1 samples, 1.79%)_RNvX.._RNvXs_NtCsjMNVNv9nEZt_8ax_alloc10buddy_slabNtB4_10PercpuSlabNtNtCs4fiTdtanek2_20buddy_slab_allocator4slab9SlabTrait5allocB6_+0x1a (1 samples, 1.79%)_RNvX.._RNvXs_NtCsjMNVNv9nEZt_8ax_alloc10buddy_slabNtB4_10PercpuSlabNtNtCs4fiTdtanek2_20buddy_slab_allocator4slab9SlabTrait5allocB6_+0x234 (1 samples, 1.79%)_RNvX.._RNvXs_NtCsjMNVNv9nEZt_8ax_alloc10buddy_slabNtB4_10PercpuSlabNtNtCs4fiTdtanek2_20buddy_slab_allocator4slab9SlabTrait5allocB6_+0x254 (1 samples, 1.79%)_RNvX.._RNvXs_NtCsjMNVNv9nEZt_8ax_alloc10buddy_slabNtB4_10PercpuSlabNtNtCs4fiTdtanek2_20buddy_slab_allocator4slab9SlabTrait5allocB6_+0x264 (1 samples, 1.79%)_RNvX.._RNvXs_NtCsjMNVNv9nEZt_8ax_alloc10buddy_slabNtB4_10PercpuSlabNtNtCs4fiTdtanek2_20buddy_slab_allocator4slab9SlabTrait5allocB6_+0x3c (1 samples, 1.79%)_RNvX.._RNvXs_NtCsjMNVNv9nEZt_8ax_alloc10buddy_slabNtB4_10PercpuSlabNtNtCs4fiTdtanek2_20buddy_slab_allocator4slab9SlabTrait5allocB6_+0x40 (1 samples, 1.79%)_RNvX.._RNvXs_NtCsjMNVNv9nEZt_8ax_alloc10buddy_slabNtB4_10PercpuSlabNtNtCs4fiTdtanek2_20buddy_slab_allocator4slab9SlabTrait5allocB6_+0x4e (1 samples, 1.79%)_RNvX.._RNvXs_NtCsjMNVNv9nEZt_8ax_alloc10buddy_slabNtB4_10PercpuSlabNtNtCs4fiTdtanek2_20buddy_slab_allocator4slab9SlabTrait5allocB6_+0xfa (17 samples, 30.36%)_RNvXs_NtCsjMNVNv9nEZt_8ax_alloc10buddy_slabNtB4_10PercpuSlabNtNtCs4fiTdtanek2_20buddy_slab_allocator4slab9SlabTrait5allocB6..all (56 samples, 100%)_RNvXs_NtCsjMNVNv9nEZt_8ax_alloc10buddy_slabNtB4_10PercpuSlabNtNtCs4fiTdtanek2_20buddy_slab_allocator4slab9SlabTrait5allocB6_+0xfc (4 samples, 7.14%)_RNvXs_NtCsjMNVNv9nEZt_8ax_.. \ No newline at end of file diff --git a/docs/flamegraphs/target__qperf-virtio-drivers__blk-read-focused__perf__riscv64__latest__qperf__flamegraph.svg b/docs/flamegraphs/target__qperf-virtio-drivers__blk-read-focused__perf__riscv64__latest__qperf__flamegraph.svg new file mode 100644 index 0000000000..6e6139b929 --- /dev/null +++ b/docs/flamegraphs/target__qperf-virtio-drivers__blk-read-focused__perf__riscv64__latest__qperf__flamegraph.svg @@ -0,0 +1,491 @@ +StarryOS qperf Flame Graph Reset ZoomSearch _RINvMNtCsa9GpAcvErGs_14virtio_drivers5queueINtB3_9VirtQueueNtNtCse8JQZBARWTK_9ax_driver6virtio13VirtIoHalImplKj10_E19add_notify_wait_popNtNtNtB5_9transport3pci12PciTransportEBZ_+0xc6 (17 samples, 0.69%)_RINvMNtCsa9GpAcvErGs_14virtio_drivers5queueINtB3_9VirtQueueNtNtCse8JQZBARWTK_9ax_driver6virtio13VirtIoHalImplKj10_E19add_notify_wait_popNtNtNtB5_9transport3pci12PciTransportEBZ_+0xc8 (65 samples, 2.63%)_RINvMNt.._RINvMNtCsa9GpAcvErGs_14virtio_drivers5queueINtB3_9VirtQueueNtNtCse8JQZBARWTK_9ax_driver6virtio13VirtIoHalImplKj10_E19add_notify_wait_popNtNtNtB5_9transport3pci12PciTransportEBZ_+0xcc (76 samples, 3.07%)_RINvMNtCs.._RINvMs10_NtNtNtCs2W9OV9R0Aa1_5alloc11collections5btree4nodeINtB7_16BalancingContexttNtNtNtCse8JQZBARWTK_9ax_driver6virtio3net10RxInflightE8do_mergeNCINvB2_20merge_tracking_childNtNtBd_5alloc6GlobalE0INtB7_7NodeRefNtNtB7_6marker3MuttB1k_NtB3r_14LeafOrInternalEB2P_EB1q_+0x92 (14 samples, 0.57%)_RINvMsW_NtNtNtCs2W9OV9R0Aa1_5alloc11collections5btree4nodeINtB6_6HandleINtB6_7NodeRefNtNtB6_6marker3MuttNtNtNtCse8JQZBARWTK_9ax_driver6virtio3net10RxInflightNtB1n_8InternalENtB1n_2KVE5splitNtNtBc_5alloc6GlobalEB1K_+0x110 (11 samples, 0.44%)_RINvMsW_NtNtNtCs2W9OV9R0Aa1_5alloc11collections5btree4nodeINtB6_6HandleINtB6_7NodeRefNtNtB6_6marker3MuttNtNtNtCse8JQZBARWTK_9ax_driver6virtio3net10RxInflightNtB1n_8InternalENtB1n_2KVE5splitNtNtBc_5alloc6GlobalEB1K_+0x11e (10 samples, 0.40%)_RINvMs_NtCsjoxaZGNdFP9_7ax_task10wait_queueNtB5_9WaitQueue10wait_untilNCNvMs2_NtCs2x05nxSvmHt_7ax_sync5mutexNtB1e_8RawMutex18lock_after_prepare0ECs41CxRoq78v7_10ax_display+0x434 (13 samples, 0.53%)_RINvMs_NtCsjoxaZGNdFP9_7ax_task10wait_queueNtB5_9WaitQueue10wait_untilNCNvMs2_NtCs2x05nxSvmHt_7ax_sync5mutexNtB1e_8RawMutex18lock_after_prepare0ECs41CxRoq78v7_10ax_display+0x45a (69 samples, 2.79%)_RINvMs_N.._RINvMs_NtCsjoxaZGNdFP9_7ax_task10wait_queueNtB5_9WaitQueue10wait_untilNCNvMs2_NtCs2x05nxSvmHt_7ax_sync5mutexNtB1e_8RawMutex18lock_after_prepare0ECs41CxRoq78v7_10ax_display+0x466 (68 samples, 2.75%)_RINvMs_N.._RINvMs_NtCsjoxaZGNdFP9_7ax_task10wait_queueNtB5_9WaitQueue10wait_untilNCNvMs2_NtCs2x05nxSvmHt_7ax_sync5mutexNtB1e_8RawMutex18lock_after_prepare0ECs41CxRoq78v7_10ax_display+0x490 (10 samples, 0.40%)_RNSNvYNCNvMs1_NtNtNtNtNtCsbgXMhWHegTz_13starry_kernel8pseudofs3dev3tty8terminal5ldiscINtBc_14LineDisciplineNtNtBg_4ntty7ConsoleB1H_E20spawn_polling_reader0INtNtNtCsgiRWr7r9Nzy_4core3ops8function6FnOnceuE9call_once6vtableBm_+0x108 (16 samples, 0.65%)_RNSNvYNCNvMs1_NtNtNtNtNtCsbgXMhWHegTz_13starry_kernel8pseudofs3dev3tty8terminal5ldiscINtBc_14LineDisciplineNtNtBg_4ntty7ConsoleB1H_E20spawn_polling_reader0INtNtNtCsgiRWr7r9Nzy_4core3ops8function6FnOnceuE9call_once6vtableBm_+0x134 (12 samples, 0.49%)_RNSNvYNCNvMs1_NtNtNtNtNtCsbgXMhWHegTz_13starry_kernel8pseudofs3dev3tty8terminal5ldiscINtBc_14LineDisciplineNtNtBg_4ntty7ConsoleB1H_E20spawn_polling_reader0INtNtNtCsgiRWr7r9Nzy_4core3ops8function6FnOnceuE9call_once6vtableBm_+0x150 (12 samples, 0.49%)_RNSNvYNCNvMs1_NtNtNtNtNtCsbgXMhWHegTz_13starry_kernel8pseudofs3dev3tty8terminal5ldiscINtBc_14LineDisciplineNtNtBg_4ntty7ConsoleB1H_E20spawn_polling_reader0INtNtNtCsgiRWr7r9Nzy_4core3ops8function6FnOnceuE9call_once6vtableBm_+0x162 (12 samples, 0.49%)_RNSNvYNCNvMs1_NtNtNtNtNtCsbgXMhWHegTz_13starry_kernel8pseudofs3dev3tty8terminal5ldiscINtBc_14LineDisciplineNtNtBg_4ntty7ConsoleB1H_E20spawn_polling_reader0INtNtNtCsgiRWr7r9Nzy_4core3ops8function6FnOnceuE9call_once6vtableBm_+0x166 (16 samples, 0.65%)_RNSNvYNCNvMs1_NtNtNtNtNtCsbgXMhWHegTz_13starry_kernel8pseudofs3dev3tty8terminal5ldiscINtBc_14LineDisciplineNtNtBg_4ntty7ConsoleB1H_E20spawn_polling_reader0INtNtNtCsgiRWr7r9Nzy_4core3ops8function6FnOnceuE9call_once6vtableBm_+0x174 (12 samples, 0.49%)_RNSNvYNCNvMs1_NtNtNtNtNtCsbgXMhWHegTz_13starry_kernel8pseudofs3dev3tty8terminal5ldiscINtBc_14LineDisciplineNtNtBg_4ntty7ConsoleB1H_E20spawn_polling_reader0INtNtNtCsgiRWr7r9Nzy_4core3ops8function6FnOnceuE9call_once6vtableBm_+0x18a (12 samples, 0.49%)_RNSNvYNCNvMs1_NtNtNtNtNtCsbgXMhWHegTz_13starry_kernel8pseudofs3dev3tty8terminal5ldiscINtBc_14LineDisciplineNtNtBg_4ntty7ConsoleB1H_E20spawn_polling_reader0INtNtNtCsgiRWr7r9Nzy_4core3ops8function6FnOnceuE9call_once6vtableBm_+0x1c4 (17 samples, 0.69%)_RNSNvYNCNvMs1_NtNtNtNtNtCsbgXMhWHegTz_13starry_kernel8pseudofs3dev3tty8terminal5ldiscINtBc_14LineDisciplineNtNtBg_4ntty7ConsoleB1H_E20spawn_polling_reader0INtNtNtCsgiRWr7r9Nzy_4core3ops8function6FnOnceuE9call_once6vtableBm_+0x5c (13 samples, 0.53%)_RNSNvYNCNvMs1_NtNtNtNtNtCsbgXMhWHegTz_13starry_kernel8pseudofs3dev3tty8terminal5ldiscINtBc_14LineDisciplineNtNtBg_4ntty7ConsoleB1H_E20spawn_polling_reader0INtNtNtCsgiRWr7r9Nzy_4core3ops8function6FnOnceuE9call_once6vtableBm_+0x890 (11 samples, 0.44%)_RNSNvYNCNvMs1_NtNtNtNtNtCsbgXMhWHegTz_13starry_kernel8pseudofs3dev3tty8terminal5ldiscINtBc_14LineDisciplineNtNtBg_4ntty7ConsoleB1H_E20spawn_polling_reader0INtNtNtCsgiRWr7r9Nzy_4core3ops8function6FnOnceuE9call_once6vtableBm_+0x8c8 (9 samples, 0.36%)_RNSNvYNCNvMs1_NtNtNtNtNtCsbgXMhWHegTz_13starry_kernel8pseudofs3dev3tty8terminal5ldiscINtBc_14LineDisciplineNtNtBg_4ntty7ConsoleB1H_E20spawn_polling_reader0INtNtNtCsgiRWr7r9Nzy_4core3ops8function6FnOnceuE9call_once6vtableBm_+0x8e0 (14 samples, 0.57%)_RNSNvYNCNvMs1_NtNtNtNtNtCsbgXMhWHegTz_13starry_kernel8pseudofs3dev3tty8terminal5ldiscINtBc_14LineDisciplineNtNtBg_4ntty7ConsoleB1H_E20spawn_polling_reader0INtNtNtCsgiRWr7r9Nzy_4core3ops8function6FnOnceuE9call_once6vtableBm_+0xb8 (9 samples, 0.36%)_RNSNvYNCNvMs1_NtNtNtNtNtCsbgXMhWHegTz_13starry_kernel8pseudofs3dev3tty8terminal5ldiscINtBc_14LineDisciplineNtNtBg_4ntty7ConsoleB1H_E20spawn_polling_reader0INtNtNtCsgiRWr7r9Nzy_4core3ops8function6FnOnceuE9call_once6vtableBm_+0xbe (11 samples, 0.44%)_RNSNvYNCNvMs1_NtNtNtNtNtCsbgXMhWHegTz_13starry_kernel8pseudofs3dev3tty8terminal5ldiscINtBc_14LineDisciplineNtNtBg_4ntty7ConsoleB1H_E20spawn_polling_reader0INtNtNtCsgiRWr7r9Nzy_4core3ops8function6FnOnceuE9call_once6vtableBm_+0xc2 (9 samples, 0.36%)_RNSNvYNCNvMs1_NtNtNtNtNtCsbgXMhWHegTz_13starry_kernel8pseudofs3dev3tty8terminal5ldiscINtBc_14LineDisciplineNtNtBg_4ntty7ConsoleB1H_E20spawn_polling_reader0INtNtNtCsgiRWr7r9Nzy_4core3ops8function6FnOnceuE9call_once6vtableBm_+0xfa (14 samples, 0.57%)_RNvCs41CxRoq78v7_10ax_display17framebuffer_flush+0x32 (16 samples, 0.65%)_RNvMs10_NtNtNtCs2W9OV9R0Aa1_5alloc11collections5btree4nodeINtB6_16BalancingContexttNtNtNtCse8JQZBARWTK_9ax_driver6virtio3net10RxInflightE15bulk_steal_leftB1p_+0x1a6 (13 samples, 0.53%)_RNvMs10_NtNtNtCs2W9OV9R0Aa1_5alloc11collections5btree4nodeINtB6_16BalancingContexttNtNtNtCse8JQZBARWTK_9ax_driver6virtio3net10RxInflightE15bulk_steal_leftB1p_+0x1c8 (10 samples, 0.40%)_RNvMs1_NtCsjoxaZGNdFP9_7ax_task9run_queueINtB5_18CurrentRunQueueRefNtCs9J4N2FZfJib_15ax_kernel_guard16NoPreemptIrqSaveE13yield_currentB7_+0x116 (11 samples, 0.44%)_RNvMs1_NtCsjoxaZGNdFP9_7ax_task9run_queueINtB5_18CurrentRunQueueRefNtCs9J4N2FZfJib_15ax_kernel_guard16NoPreemptIrqSaveE13yield_currentB7_+0x11c (9 samples, 0.36%)_RNvMs1_NtCsjoxaZGNdFP9_7ax_task9run_queueINtB5_18CurrentRunQueueRefNtCs9J4N2FZfJib_15ax_kernel_guard16NoPreemptIrqSaveE13yield_currentB7_+0x12a (9 samples, 0.36%)_RNvMs1_NtCsjoxaZGNdFP9_7ax_task9run_queueINtB5_18CurrentRunQueueRefNtCs9J4N2FZfJib_15ax_kernel_guard16NoPreemptIrqSaveE13yield_currentB7_+0x148 (9 samples, 0.36%)_RNvMs1_NtCsjoxaZGNdFP9_7ax_task9run_queueINtB5_18CurrentRunQueueRefNtCs9J4N2FZfJib_15ax_kernel_guard16NoPreemptIrqSaveE13yield_currentB7_+0x176 (13 samples, 0.53%)_RNvMs1_NtCsjoxaZGNdFP9_7ax_task9run_queueINtB5_18CurrentRunQueueRefNtCs9J4N2FZfJib_15ax_kernel_guard16NoPreemptIrqSaveE13yield_currentB7_+0x188 (11 samples, 0.44%)_RNvMs1_NtCsjoxaZGNdFP9_7ax_task9run_queueINtB5_18CurrentRunQueueRefNtCs9J4N2FZfJib_15ax_kernel_guard16NoPreemptIrqSaveE13yield_currentB7_+0x1a0 (9 samples, 0.36%)_RNvMs1_NtCsjoxaZGNdFP9_7ax_task9run_queueINtB5_18CurrentRunQueueRefNtCs9J4N2FZfJib_15ax_kernel_guard16NoPreemptIrqSaveE13yield_currentB7_+0x1b0 (12 samples, 0.49%)_RNvMs1_NtCsjoxaZGNdFP9_7ax_task9run_queueINtB5_18CurrentRunQueueRefNtCs9J4N2FZfJib_15ax_kernel_guard16NoPreemptIrqSaveE13yield_currentB7_+0x1ba (10 samples, 0.40%)_RNvMs1_NtCsjoxaZGNdFP9_7ax_task9run_queueINtB5_18CurrentRunQueueRefNtCs9J4N2FZfJib_15ax_kernel_guard16NoPreemptIrqSaveE13yield_currentB7_+0x1f2 (11 samples, 0.44%)_RNvMs1_NtCsjoxaZGNdFP9_7ax_task9run_queueINtB5_18CurrentRunQueueRefNtCs9J4N2FZfJib_15ax_kernel_guard16NoPreemptIrqSaveE13yield_currentB7_+0x2e4 (9 samples, 0.36%)_RNvMs1_NtCsjoxaZGNdFP9_7ax_task9run_queueINtB5_18CurrentRunQueueRefNtCs9J4N2FZfJib_15ax_kernel_guard16NoPreemptIrqSaveE13yield_currentB7_+0xda (9 samples, 0.36%)_RNvMs1_NtCsjoxaZGNdFP9_7ax_task9run_queueINtB5_18CurrentRunQueueRefNtCs9J4N2FZfJib_15ax_kernel_guard16NoPreemptIrqSaveE13yield_currentB7_+0xec (9 samples, 0.36%)_RNvMs1_NtCsjoxaZGNdFP9_7ax_task9run_queueINtB5_18CurrentRunQueueRefNtCs9J4N2FZfJib_15ax_kernel_guard16NoPreemptIrqSaveE13yield_currentB7_+0xf2 (9 samples, 0.36%)_RNvMs1_NtCsjoxaZGNdFP9_7ax_task9run_queueINtB5_18CurrentRunQueueRefNtCs9J4N2FZfJib_15ax_kernel_guard16NoPreemptIrqSaveE13yield_currentB7_+0xf6 (14 samples, 0.57%)_RNvMs2_NtCsjMNVNv9nEZt_8ax_alloc10buddy_slabNtB5_15GlobalAllocator11alloc_pages+0x70 (13 samples, 0.53%)_RNvMs2_NtCsjMNVNv9nEZt_8ax_alloc10buddy_slabNtB5_15GlobalAllocator11alloc_pages+0x80 (12 samples, 0.49%)_RNvMs2_NtCsjMNVNv9nEZt_8ax_alloc10buddy_slabNtB5_15GlobalAllocator11alloc_pages+0x98 (9 samples, 0.36%)_RNvMs2_NtCsjMNVNv9nEZt_8ax_alloc10buddy_slabNtB5_15GlobalAllocator11alloc_pages+0xc8 (9 samples, 0.36%)_RNvMs2_NtCsjMNVNv9nEZt_8ax_alloc10buddy_slabNtB5_15GlobalAllocator11alloc_pages+0xdc (9 samples, 0.36%)_RNvMs2_NtCsjMNVNv9nEZt_8ax_alloc10buddy_slabNtB5_15GlobalAllocator11alloc_pages+0xf2 (9 samples, 0.36%)_RNvMs2_NtCsjMNVNv9nEZt_8ax_alloc10buddy_slabNtB5_15GlobalAllocator11alloc_pages+0xf8 (13 samples, 0.53%)_RNvMs2_NtCsjoxaZGNdFP9_7ax_task9run_queueNtB5_10AxRunQueue7resched (10 samples, 0.40%)_RNvMs2_NtCsjoxaZGNdFP9_7ax_task9run_queueNtB5_10AxRunQueue7resched+0x18 (9 samples, 0.36%)_RNvMs2_NtCsjoxaZGNdFP9_7ax_task9run_queueNtB5_10AxRunQueue7resched+0x2a (11 samples, 0.44%)_RNvMs2_NtCsjoxaZGNdFP9_7ax_task9run_queueNtB5_10AxRunQueue7resched+0xa8 (16 samples, 0.65%)_RNvMs2_NtCsjoxaZGNdFP9_7ax_task9run_queueNtB5_10AxRunQueue7resched+0xd2 (12 samples, 0.49%)_RNvMs2_NtCsjoxaZGNdFP9_7ax_task9run_queueNtB5_10AxRunQueue9switch_to (15 samples, 0.61%)_RNvMs2_NtCsjoxaZGNdFP9_7ax_task9run_queueNtB5_10AxRunQueue9switch_to+0x110 (9 samples, 0.36%)_RNvMs2_NtCsjoxaZGNdFP9_7ax_task9run_queueNtB5_10AxRunQueue9switch_to+0x1e (14 samples, 0.57%)_RNvMs2_NtCsjoxaZGNdFP9_7ax_task9run_queueNtB5_10AxRunQueue9switch_to+0x21c (9 samples, 0.36%)_RNvMs2_NtCsjoxaZGNdFP9_7ax_task9run_queueNtB5_10AxRunQueue9switch_to+0x24 (9 samples, 0.36%)_RNvMs3_NtCs2W9OV9R0Aa1_5alloc3stre12to_uppercase+0x434 (9 samples, 0.36%)_RNvMs3_NtCs2W9OV9R0Aa1_5alloc3stre12to_uppercase+0x440 (16 samples, 0.65%)_RNvMs3_NtCsjoxaZGNdFP9_7ax_task4taskNtB5_9TaskInner29current_check_preempt_pending (28 samples, 1.13%)_R.._RNvMs3_NtCsjoxaZGNdFP9_7ax_task4taskNtB5_9TaskInner29current_check_preempt_pending+0x18 (25 samples, 1.01%)_R.._RNvMs3_NtCsjoxaZGNdFP9_7ax_task4taskNtB5_9TaskInner29current_check_preempt_pending+0x38 (23 samples, 0.93%)_.._RNvMs3_NtCsjoxaZGNdFP9_7ax_task4taskNtB5_9TaskInner29current_check_preempt_pending+0x3c (12 samples, 0.49%)_RNvMs3_NtCsjoxaZGNdFP9_7ax_task4taskNtB5_9TaskInner29current_check_preempt_pending+0x4e (13 samples, 0.53%)_RNvNtCs9OcUSfjU0zs_17compiler_builtins3mem6memcpy+0x4a (165 samples, 6.67%)_RNvNtCs9OcUSfjU0zs_17com.._RNvNtCsjoxaZGNdFP9_7ax_task3api9yield_now (13 samples, 0.53%)_RNvNtCsjoxaZGNdFP9_7ax_task3api9yield_now+0x10 (9 samples, 0.36%)_RNvNtCsjoxaZGNdFP9_7ax_task3api9yield_now+0x14 (14 samples, 0.57%)_RNvNtCsjoxaZGNdFP9_7ax_task3api9yield_now+0x34 (11 samples, 0.44%)_RNvNtCsjoxaZGNdFP9_7ax_task3api9yield_now+0x42 (11 samples, 0.44%)_RNvNtCsjoxaZGNdFP9_7ax_task3api9yield_now+0x50 (13 samples, 0.53%)_RNvNtCsjoxaZGNdFP9_7ax_task3api9yield_now+0x52 (12 samples, 0.49%)_RNvNtCsjoxaZGNdFP9_7ax_task3api9yield_now+0x60 (11 samples, 0.44%)_RNvNtCsjoxaZGNdFP9_7ax_task3api9yield_now+0x82 (19 samples, 0.77%)_.._RNvNtCsjoxaZGNdFP9_7ax_task3api9yield_now+0x90 (14 samples, 0.57%)_RNvNtCsjoxaZGNdFP9_7ax_task3api9yield_now+0xb0 (15 samples, 0.61%)_RNvNtCsjoxaZGNdFP9_7ax_task3api9yield_now+0xc (13 samples, 0.53%)_RNvNtCsjoxaZGNdFP9_7ax_task3api9yield_now+0xc0 (16 samples, 0.65%)_RNvNtNtCse8JQZBARWTK_9ax_driver3pci3fdt18probe_generic_ecam+0x680 (14 samples, 0.57%)_RNvNtNtCse8JQZBARWTK_9ax_driver3pci3fdt18probe_generic_ecam+0x70c (10 samples, 0.40%)_RNvNtNtCse8JQZBARWTK_9ax_driver3pci3fdt18probe_generic_ecam+0x710 (72 samples, 2.91%)_RNvNtNtCs.._RNvXsk_NtNtNtCs2W9OV9R0Aa1_5alloc11collections5btree3mapINtB5_4IterNtNtCsi9Y2sIRgCK0_6rsext47bmalloc10AbsoluteBNNtNtNtB17_5cache10data_block11CachedBlockENtNtNtNtCsgiRWr7r9Nzy_4core4iter6traits8iterator8Iterator4nextCseWxrHIpmU4v_8ax_fs_ng (10 samples, 0.40%)_head+0x4f8 (34 samples, 1.37%)_he.._head+0x4fc (10 samples, 0.40%)_head+0x504 (10 samples, 0.40%)_head+0x534 (20 samples, 0.81%)_.._head+0x538 (13 samples, 0.53%)_head+0x53e (21 samples, 0.85%)_.._head+0x58e (13 samples, 0.53%)_head+0x594 (15 samples, 0.61%)_head+0x59a (9 samples, 0.36%)_head+0x5ae (14 samples, 0.57%)_head+0x5b6 (23 samples, 0.93%)_.._head+0x624 (24 samples, 0.97%)_h.._head+0x62c (10 samples, 0.40%)all (2,474 samples, 100%) \ No newline at end of file diff --git a/docs/flamegraphs/target__qperf-virtio-drivers__blk-read__perf__riscv64__latest__qperf__flamegraph.svg b/docs/flamegraphs/target__qperf-virtio-drivers__blk-read__perf__riscv64__latest__qperf__flamegraph.svg new file mode 100644 index 0000000000..71d46c0183 --- /dev/null +++ b/docs/flamegraphs/target__qperf-virtio-drivers__blk-read__perf__riscv64__latest__qperf__flamegraph.svg @@ -0,0 +1,491 @@ +StarryOS qperf Flame Graph Reset ZoomSearch _RINvMNtCsa9GpAcvErGs_14virtio_drivers5queueINtB3_9VirtQueueNtNtCse8JQZBARWTK_9ax_driver6virtio13VirtIoHalImplKj10_E19add_notify_wait_popNtNtNtB5_9transport3pci12PciTransportEBZ_+0xc8 (61 samples, 1.37%)_RI.._RINvMNtCsa9GpAcvErGs_14virtio_drivers5queueINtB3_9VirtQueueNtNtCse8JQZBARWTK_9ax_driver6virtio13VirtIoHalImplKj10_E19add_notify_wait_popNtNtNtB5_9transport3pci12PciTransportEBZ_+0xcc (73 samples, 1.64%)_RIN.._RINvMs10_NtNtNtCs2W9OV9R0Aa1_5alloc11collections5btree4nodeINtB7_16BalancingContexttNtNtNtCse8JQZBARWTK_9ax_driver6virtio3net10RxInflightE8do_mergeNCINvB2_20merge_tracking_childNtNtBd_5alloc6GlobalE0INtB7_7NodeRefNtNtB7_6marker3MuttB1k_NtB3r_14LeafOrInternalEB2P_EB1q_+0x92 (25 samples, 0.56%)_RINvMs10_NtNtNtCs2W9OV9R0Aa1_5alloc11collections5btree4nodeINtB7_16BalancingContexttNtNtNtCse8JQZBARWTK_9ax_driver6virtio3net10RxInflightE8do_mergeNCINvB2_20merge_tracking_childNtNtBd_5alloc6GlobalE0INtB7_7NodeRefNtNtB7_6marker3MuttB1k_NtB3r_14LeafOrInternalEB2P_EB1q_+0x96 (21 samples, 0.47%)_RINvMsW_NtNtNtCs2W9OV9R0Aa1_5alloc11collections5btree4nodeINtB6_6HandleINtB6_7NodeRefNtNtB6_6marker3MuttNtNtNtCse8JQZBARWTK_9ax_driver6virtio3net10RxInflightNtB1n_8InternalENtB1n_2KVE5splitNtNtBc_5alloc6GlobalEB1K_+0x11a (16 samples, 0.36%)_RINvMsW_NtNtNtCs2W9OV9R0Aa1_5alloc11collections5btree4nodeINtB6_6HandleINtB6_7NodeRefNtNtB6_6marker3MuttNtNtNtCse8JQZBARWTK_9ax_driver6virtio3net10RxInflightNtB1n_8InternalENtB1n_2KVE5splitNtNtBc_5alloc6GlobalEB1K_+0x128 (21 samples, 0.47%)_RINvMs_NtCsjoxaZGNdFP9_7ax_task10wait_queueNtB5_9WaitQueue10wait_untilNCNvMs2_NtCs2x05nxSvmHt_7ax_sync5mutexNtB1e_8RawMutex18lock_after_prepare0ECs41CxRoq78v7_10ax_display+0x45a (145 samples, 3.26%)_RINvMs_NtC.._RINvMs_NtCsjoxaZGNdFP9_7ax_task10wait_queueNtB5_9WaitQueue10wait_untilNCNvMs2_NtCs2x05nxSvmHt_7ax_sync5mutexNtB1e_8RawMutex18lock_after_prepare0ECs41CxRoq78v7_10ax_display+0x466 (130 samples, 2.92%)_RINvMs_Nt.._RINvMs_NtCsjoxaZGNdFP9_7ax_task10wait_queueNtB5_9WaitQueue10wait_untilNCNvMs2_NtCs2x05nxSvmHt_7ax_sync5mutexNtB1e_8RawMutex18lock_after_prepare0ECs41CxRoq78v7_10ax_display+0x482 (18 samples, 0.40%)_RINvMs_NtCsjoxaZGNdFP9_7ax_task10wait_queueNtB5_9WaitQueue10wait_untilNCNvMs2_NtCs2x05nxSvmHt_7ax_sync5mutexNtB1e_8RawMutex18lock_after_prepare0ECs41CxRoq78v7_10ax_display+0x490 (19 samples, 0.43%)_RNSNvYNCNvMs1_NtNtNtNtNtCsbgXMhWHegTz_13starry_kernel8pseudofs3dev3tty8terminal5ldiscINtBc_14LineDisciplineNtNtBg_4ntty7ConsoleB1H_E20spawn_polling_reader0INtNtNtCsgiRWr7r9Nzy_4core3ops8function6FnOnceuE9call_once6vtableBm_+0x108 (27 samples, 0.61%)_RNSNvYNCNvMs1_NtNtNtNtNtCsbgXMhWHegTz_13starry_kernel8pseudofs3dev3tty8terminal5ldiscINtBc_14LineDisciplineNtNtBg_4ntty7ConsoleB1H_E20spawn_polling_reader0INtNtNtCsgiRWr7r9Nzy_4core3ops8function6FnOnceuE9call_once6vtableBm_+0x10a (19 samples, 0.43%)_RNSNvYNCNvMs1_NtNtNtNtNtCsbgXMhWHegTz_13starry_kernel8pseudofs3dev3tty8terminal5ldiscINtBc_14LineDisciplineNtNtBg_4ntty7ConsoleB1H_E20spawn_polling_reader0INtNtNtCsgiRWr7r9Nzy_4core3ops8function6FnOnceuE9call_once6vtableBm_+0x11a (18 samples, 0.40%)_RNSNvYNCNvMs1_NtNtNtNtNtCsbgXMhWHegTz_13starry_kernel8pseudofs3dev3tty8terminal5ldiscINtBc_14LineDisciplineNtNtBg_4ntty7ConsoleB1H_E20spawn_polling_reader0INtNtNtCsgiRWr7r9Nzy_4core3ops8function6FnOnceuE9call_once6vtableBm_+0x146 (18 samples, 0.40%)_RNSNvYNCNvMs1_NtNtNtNtNtCsbgXMhWHegTz_13starry_kernel8pseudofs3dev3tty8terminal5ldiscINtBc_14LineDisciplineNtNtBg_4ntty7ConsoleB1H_E20spawn_polling_reader0INtNtNtCsgiRWr7r9Nzy_4core3ops8function6FnOnceuE9call_once6vtableBm_+0x150 (18 samples, 0.40%)_RNSNvYNCNvMs1_NtNtNtNtNtCsbgXMhWHegTz_13starry_kernel8pseudofs3dev3tty8terminal5ldiscINtBc_14LineDisciplineNtNtBg_4ntty7ConsoleB1H_E20spawn_polling_reader0INtNtNtCsgiRWr7r9Nzy_4core3ops8function6FnOnceuE9call_once6vtableBm_+0x162 (34 samples, 0.76%)_.._RNSNvYNCNvMs1_NtNtNtNtNtCsbgXMhWHegTz_13starry_kernel8pseudofs3dev3tty8terminal5ldiscINtBc_14LineDisciplineNtNtBg_4ntty7ConsoleB1H_E20spawn_polling_reader0INtNtNtCsgiRWr7r9Nzy_4core3ops8function6FnOnceuE9call_once6vtableBm_+0x166 (26 samples, 0.58%)_RNSNvYNCNvMs1_NtNtNtNtNtCsbgXMhWHegTz_13starry_kernel8pseudofs3dev3tty8terminal5ldiscINtBc_14LineDisciplineNtNtBg_4ntty7ConsoleB1H_E20spawn_polling_reader0INtNtNtCsgiRWr7r9Nzy_4core3ops8function6FnOnceuE9call_once6vtableBm_+0x174 (24 samples, 0.54%)_RNSNvYNCNvMs1_NtNtNtNtNtCsbgXMhWHegTz_13starry_kernel8pseudofs3dev3tty8terminal5ldiscINtBc_14LineDisciplineNtNtBg_4ntty7ConsoleB1H_E20spawn_polling_reader0INtNtNtCsgiRWr7r9Nzy_4core3ops8function6FnOnceuE9call_once6vtableBm_+0x182 (16 samples, 0.36%)_RNSNvYNCNvMs1_NtNtNtNtNtCsbgXMhWHegTz_13starry_kernel8pseudofs3dev3tty8terminal5ldiscINtBc_14LineDisciplineNtNtBg_4ntty7ConsoleB1H_E20spawn_polling_reader0INtNtNtCsgiRWr7r9Nzy_4core3ops8function6FnOnceuE9call_once6vtableBm_+0x18a (31 samples, 0.70%)_RNSNvYNCNvMs1_NtNtNtNtNtCsbgXMhWHegTz_13starry_kernel8pseudofs3dev3tty8terminal5ldiscINtBc_14LineDisciplineNtNtBg_4ntty7ConsoleB1H_E20spawn_polling_reader0INtNtNtCsgiRWr7r9Nzy_4core3ops8function6FnOnceuE9call_once6vtableBm_+0x5c (19 samples, 0.43%)_RNSNvYNCNvMs1_NtNtNtNtNtCsbgXMhWHegTz_13starry_kernel8pseudofs3dev3tty8terminal5ldiscINtBc_14LineDisciplineNtNtBg_4ntty7ConsoleB1H_E20spawn_polling_reader0INtNtNtCsgiRWr7r9Nzy_4core3ops8function6FnOnceuE9call_once6vtableBm_+0x890 (23 samples, 0.52%)_RNSNvYNCNvMs1_NtNtNtNtNtCsbgXMhWHegTz_13starry_kernel8pseudofs3dev3tty8terminal5ldiscINtBc_14LineDisciplineNtNtBg_4ntty7ConsoleB1H_E20spawn_polling_reader0INtNtNtCsgiRWr7r9Nzy_4core3ops8function6FnOnceuE9call_once6vtableBm_+0x8d0 (17 samples, 0.38%)_RNSNvYNCNvMs1_NtNtNtNtNtCsbgXMhWHegTz_13starry_kernel8pseudofs3dev3tty8terminal5ldiscINtBc_14LineDisciplineNtNtBg_4ntty7ConsoleB1H_E20spawn_polling_reader0INtNtNtCsgiRWr7r9Nzy_4core3ops8function6FnOnceuE9call_once6vtableBm_+0x8e0 (35 samples, 0.79%)_.._RNSNvYNCNvMs1_NtNtNtNtNtCsbgXMhWHegTz_13starry_kernel8pseudofs3dev3tty8terminal5ldiscINtBc_14LineDisciplineNtNtBg_4ntty7ConsoleB1H_E20spawn_polling_reader0INtNtNtCsgiRWr7r9Nzy_4core3ops8function6FnOnceuE9call_once6vtableBm_+0xb8 (25 samples, 0.56%)_RNSNvYNCNvMs1_NtNtNtNtNtCsbgXMhWHegTz_13starry_kernel8pseudofs3dev3tty8terminal5ldiscINtBc_14LineDisciplineNtNtBg_4ntty7ConsoleB1H_E20spawn_polling_reader0INtNtNtCsgiRWr7r9Nzy_4core3ops8function6FnOnceuE9call_once6vtableBm_+0xbe (37 samples, 0.83%)_.._RNSNvYNCNvMs1_NtNtNtNtNtCsbgXMhWHegTz_13starry_kernel8pseudofs3dev3tty8terminal5ldiscINtBc_14LineDisciplineNtNtBg_4ntty7ConsoleB1H_E20spawn_polling_reader0INtNtNtCsgiRWr7r9Nzy_4core3ops8function6FnOnceuE9call_once6vtableBm_+0xc2 (16 samples, 0.36%)_RNSNvYNCNvMs1_NtNtNtNtNtCsbgXMhWHegTz_13starry_kernel8pseudofs3dev3tty8terminal5ldiscINtBc_14LineDisciplineNtNtBg_4ntty7ConsoleB1H_E20spawn_polling_reader0INtNtNtCsgiRWr7r9Nzy_4core3ops8function6FnOnceuE9call_once6vtableBm_+0xfa (31 samples, 0.70%)_RNvCs41CxRoq78v7_10ax_display17framebuffer_flush+0x18 (17 samples, 0.38%)_RNvMs0_Cse38cudTX6ZT_11ax_lazyinitINtB5_8LazyInitINtNtCs4iPnrq9U4Rv_8lock_api5mutex5MutexNtNtCs2x05nxSvmHt_7ax_sync5mutex8RawMutexNtNtCs41CxRoq78v7_10ax_display6device19ErasedDisplayDeviceEE13panic_messageB28_+0x10 (21 samples, 0.47%)_RNvMs10_NtNtNtCs2W9OV9R0Aa1_5alloc11collections5btree4nodeINtB6_16BalancingContexttNtNtNtCse8JQZBARWTK_9ax_driver6virtio3net10RxInflightE15bulk_steal_leftB1p_+0x1a6 (19 samples, 0.43%)_RNvMs10_NtNtNtCs2W9OV9R0Aa1_5alloc11collections5btree4nodeINtB6_16BalancingContexttNtNtNtCse8JQZBARWTK_9ax_driver6virtio3net10RxInflightE15bulk_steal_leftB1p_+0x1c8 (24 samples, 0.54%)_RNvMs1_NtCsjoxaZGNdFP9_7ax_task9run_queueINtB5_18CurrentRunQueueRefNtCs9J4N2FZfJib_15ax_kernel_guard16NoPreemptIrqSaveE13yield_currentB7_ (16 samples, 0.36%)_RNvMs1_NtCsjoxaZGNdFP9_7ax_task9run_queueINtB5_18CurrentRunQueueRefNtCs9J4N2FZfJib_15ax_kernel_guard16NoPreemptIrqSaveE13yield_currentB7_+0x116 (29 samples, 0.65%)_RNvMs1_NtCsjoxaZGNdFP9_7ax_task9run_queueINtB5_18CurrentRunQueueRefNtCs9J4N2FZfJib_15ax_kernel_guard16NoPreemptIrqSaveE13yield_currentB7_+0x12a (34 samples, 0.76%)_.._RNvMs1_NtCsjoxaZGNdFP9_7ax_task9run_queueINtB5_18CurrentRunQueueRefNtCs9J4N2FZfJib_15ax_kernel_guard16NoPreemptIrqSaveE13yield_currentB7_+0x148 (16 samples, 0.36%)_RNvMs1_NtCsjoxaZGNdFP9_7ax_task9run_queueINtB5_18CurrentRunQueueRefNtCs9J4N2FZfJib_15ax_kernel_guard16NoPreemptIrqSaveE13yield_currentB7_+0x176 (27 samples, 0.61%)_RNvMs1_NtCsjoxaZGNdFP9_7ax_task9run_queueINtB5_18CurrentRunQueueRefNtCs9J4N2FZfJib_15ax_kernel_guard16NoPreemptIrqSaveE13yield_currentB7_+0x17a (23 samples, 0.52%)_RNvMs1_NtCsjoxaZGNdFP9_7ax_task9run_queueINtB5_18CurrentRunQueueRefNtCs9J4N2FZfJib_15ax_kernel_guard16NoPreemptIrqSaveE13yield_currentB7_+0x186 (16 samples, 0.36%)_RNvMs1_NtCsjoxaZGNdFP9_7ax_task9run_queueINtB5_18CurrentRunQueueRefNtCs9J4N2FZfJib_15ax_kernel_guard16NoPreemptIrqSaveE13yield_currentB7_+0x1ba (19 samples, 0.43%)_RNvMs1_NtCsjoxaZGNdFP9_7ax_task9run_queueINtB5_18CurrentRunQueueRefNtCs9J4N2FZfJib_15ax_kernel_guard16NoPreemptIrqSaveE13yield_currentB7_+0x1e4 (19 samples, 0.43%)_RNvMs1_NtCsjoxaZGNdFP9_7ax_task9run_queueINtB5_18CurrentRunQueueRefNtCs9J4N2FZfJib_15ax_kernel_guard16NoPreemptIrqSaveE13yield_currentB7_+0x254 (16 samples, 0.36%)_RNvMs1_NtCsjoxaZGNdFP9_7ax_task9run_queueINtB5_18CurrentRunQueueRefNtCs9J4N2FZfJib_15ax_kernel_guard16NoPreemptIrqSaveE13yield_currentB7_+0x2c8 (17 samples, 0.38%)_RNvMs1_NtCsjoxaZGNdFP9_7ax_task9run_queueINtB5_18CurrentRunQueueRefNtCs9J4N2FZfJib_15ax_kernel_guard16NoPreemptIrqSaveE13yield_currentB7_+0x2e4 (28 samples, 0.63%)_RNvMs1_NtCsjoxaZGNdFP9_7ax_task9run_queueINtB5_18CurrentRunQueueRefNtCs9J4N2FZfJib_15ax_kernel_guard16NoPreemptIrqSaveE13yield_currentB7_+0xb0 (26 samples, 0.58%)_RNvMs1_NtCsjoxaZGNdFP9_7ax_task9run_queueINtB5_18CurrentRunQueueRefNtCs9J4N2FZfJib_15ax_kernel_guard16NoPreemptIrqSaveE13yield_currentB7_+0xda (22 samples, 0.49%)_RNvMs1_NtCsjoxaZGNdFP9_7ax_task9run_queueINtB5_18CurrentRunQueueRefNtCs9J4N2FZfJib_15ax_kernel_guard16NoPreemptIrqSaveE13yield_currentB7_+0xec (19 samples, 0.43%)_RNvMs1_NtCsjoxaZGNdFP9_7ax_task9run_queueINtB5_18CurrentRunQueueRefNtCs9J4N2FZfJib_15ax_kernel_guard16NoPreemptIrqSaveE13yield_currentB7_+0xf6 (29 samples, 0.65%)_RNvMs2_NtCsjMNVNv9nEZt_8ax_alloc10buddy_slabNtB5_15GlobalAllocator11alloc_pages+0x70 (32 samples, 0.72%)_RNvMs2_NtCsjMNVNv9nEZt_8ax_alloc10buddy_slabNtB5_15GlobalAllocator11alloc_pages+0x80 (30 samples, 0.67%)_RNvMs2_NtCsjMNVNv9nEZt_8ax_alloc10buddy_slabNtB5_15GlobalAllocator11alloc_pages+0x8a (23 samples, 0.52%)_RNvMs2_NtCsjMNVNv9nEZt_8ax_alloc10buddy_slabNtB5_15GlobalAllocator11alloc_pages+0x98 (16 samples, 0.36%)_RNvMs2_NtCsjMNVNv9nEZt_8ax_alloc10buddy_slabNtB5_15GlobalAllocator11alloc_pages+0xc8 (20 samples, 0.45%)_RNvMs2_NtCsjMNVNv9nEZt_8ax_alloc10buddy_slabNtB5_15GlobalAllocator11alloc_pages+0xdc (27 samples, 0.61%)_RNvMs2_NtCsjMNVNv9nEZt_8ax_alloc10buddy_slabNtB5_15GlobalAllocator11alloc_pages+0xf8 (24 samples, 0.54%)_RNvMs2_NtCsjoxaZGNdFP9_7ax_task9run_queueNtB5_10AxRunQueue7resched (28 samples, 0.63%)_RNvMs2_NtCsjoxaZGNdFP9_7ax_task9run_queueNtB5_10AxRunQueue7resched+0x18 (17 samples, 0.38%)_RNvMs2_NtCsjoxaZGNdFP9_7ax_task9run_queueNtB5_10AxRunQueue7resched+0x2e (19 samples, 0.43%)_RNvMs2_NtCsjoxaZGNdFP9_7ax_task9run_queueNtB5_10AxRunQueue7resched+0x34 (16 samples, 0.36%)_RNvMs2_NtCsjoxaZGNdFP9_7ax_task9run_queueNtB5_10AxRunQueue7resched+0xa8 (20 samples, 0.45%)_RNvMs2_NtCsjoxaZGNdFP9_7ax_task9run_queueNtB5_10AxRunQueue7resched+0xb2 (34 samples, 0.76%)_.._RNvMs2_NtCsjoxaZGNdFP9_7ax_task9run_queueNtB5_10AxRunQueue7resched+0xd2 (30 samples, 0.67%)_RNvMs2_NtCsjoxaZGNdFP9_7ax_task9run_queueNtB5_10AxRunQueue9switch_to (19 samples, 0.43%)_RNvMs2_NtCsjoxaZGNdFP9_7ax_task9run_queueNtB5_10AxRunQueue9switch_to+0x1e (19 samples, 0.43%)_RNvMs2_NtCsjoxaZGNdFP9_7ax_task9run_queueNtB5_10AxRunQueue9switch_to+0x21c (16 samples, 0.36%)_RNvMs2_NtCsjoxaZGNdFP9_7ax_task9run_queueNtB5_10AxRunQueue9switch_to+0x24 (22 samples, 0.49%)_RNvMs2_NtCsjoxaZGNdFP9_7ax_task9run_queueNtB5_10AxRunQueue9switch_to+0x43e (23 samples, 0.52%)_RNvMs3_NtCs2W9OV9R0Aa1_5alloc3stre12to_uppercase+0x440 (34 samples, 0.76%)_.._RNvMs3_NtCsjoxaZGNdFP9_7ax_task4taskNtB5_9TaskInner29current_check_preempt_pending (55 samples, 1.23%)_RN.._RNvMs3_NtCsjoxaZGNdFP9_7ax_task4taskNtB5_9TaskInner29current_check_preempt_pending+0x18 (58 samples, 1.30%)_RN.._RNvMs3_NtCsjoxaZGNdFP9_7ax_task4taskNtB5_9TaskInner29current_check_preempt_pending+0x38 (63 samples, 1.41%)_RN.._RNvMs3_NtCsjoxaZGNdFP9_7ax_task4taskNtB5_9TaskInner29current_check_preempt_pending+0x3c (28 samples, 0.63%)_RNvMs3_NtCsjoxaZGNdFP9_7ax_task4taskNtB5_9TaskInner29current_check_preempt_pending+0x4e (36 samples, 0.81%)_.._RNvNtCs9OcUSfjU0zs_17compiler_builtins3mem6memcpy+0x4a (168 samples, 3.77%)_RNvNtCs9OcUS.._RNvNtCsjoxaZGNdFP9_7ax_task3api9yield_now (31 samples, 0.70%)_RNvNtCsjoxaZGNdFP9_7ax_task3api9yield_now+0x14 (26 samples, 0.58%)_RNvNtCsjoxaZGNdFP9_7ax_task3api9yield_now+0x34 (29 samples, 0.65%)_RNvNtCsjoxaZGNdFP9_7ax_task3api9yield_now+0x36 (18 samples, 0.40%)_RNvNtCsjoxaZGNdFP9_7ax_task3api9yield_now+0x3e (20 samples, 0.45%)_RNvNtCsjoxaZGNdFP9_7ax_task3api9yield_now+0x42 (28 samples, 0.63%)_RNvNtCsjoxaZGNdFP9_7ax_task3api9yield_now+0x50 (26 samples, 0.58%)_RNvNtCsjoxaZGNdFP9_7ax_task3api9yield_now+0x60 (33 samples, 0.74%)_.._RNvNtCsjoxaZGNdFP9_7ax_task3api9yield_now+0x7e (16 samples, 0.36%)_RNvNtCsjoxaZGNdFP9_7ax_task3api9yield_now+0x82 (33 samples, 0.74%)_.._RNvNtCsjoxaZGNdFP9_7ax_task3api9yield_now+0x90 (25 samples, 0.56%)_RNvNtCsjoxaZGNdFP9_7ax_task3api9yield_now+0x92 (21 samples, 0.47%)_RNvNtCsjoxaZGNdFP9_7ax_task3api9yield_now+0xa8 (25 samples, 0.56%)_RNvNtCsjoxaZGNdFP9_7ax_task3api9yield_now+0xac (24 samples, 0.54%)_RNvNtCsjoxaZGNdFP9_7ax_task3api9yield_now+0xb0 (34 samples, 0.76%)_.._RNvNtCsjoxaZGNdFP9_7ax_task3api9yield_now+0xbe (26 samples, 0.58%)_RNvNtCsjoxaZGNdFP9_7ax_task3api9yield_now+0xc (35 samples, 0.79%)_.._RNvNtCsjoxaZGNdFP9_7ax_task3api9yield_now+0xd0 (21 samples, 0.47%)_RNvNtNtCse8JQZBARWTK_9ax_driver3pci3fdt18probe_generic_ecam+0x680 (23 samples, 0.52%)_RNvNtNtCse8JQZBARWTK_9ax_driver3pci3fdt18probe_generic_ecam+0x6c0 (19 samples, 0.43%)_RNvNtNtCse8JQZBARWTK_9ax_driver3pci3fdt18probe_generic_ecam+0x70c (17 samples, 0.38%)_RNvNtNtCse8JQZBARWTK_9ax_driver3pci3fdt18probe_generic_ecam+0x710 (161 samples, 3.61%)_RNvNtNtCse8J.._head+0x4f8 (58 samples, 1.30%)_he.._head+0x4fc (28 samples, 0.63%)_head+0x504 (38 samples, 0.85%)_.._head+0x534 (42 samples, 0.94%)_.._head+0x538 (30 samples, 0.67%)_head+0x53e (22 samples, 0.49%)_head+0x582 (35 samples, 0.79%)_.._head+0x588 (22 samples, 0.49%)_head+0x58e (28 samples, 0.63%)_head+0x594 (30 samples, 0.67%)_head+0x59a (24 samples, 0.54%)_head+0x5ae (37 samples, 0.83%)_.._head+0x5b6 (49 samples, 1.10%)_h.._head+0x624 (31 samples, 0.70%)_head+0x62c (35 samples, 0.79%)_..all (4,454 samples, 100%) \ No newline at end of file diff --git a/docs/flamegraphs/target__qperf-virtio-drivers__boot__perf__riscv64__latest__qperf__flamegraph.svg b/docs/flamegraphs/target__qperf-virtio-drivers__boot__perf__riscv64__latest__qperf__flamegraph.svg new file mode 100644 index 0000000000..703010e7a9 --- /dev/null +++ b/docs/flamegraphs/target__qperf-virtio-drivers__boot__perf__riscv64__latest__qperf__flamegraph.svg @@ -0,0 +1,491 @@ +StarryOS qperf Flame Graph Reset ZoomSearch _RINvMs10_NtNtNtCs2W9OV9R0Aa1_5alloc11collections5btree4nodeINtB7_16BalancingContexttNtNtNtCse8JQZBARWTK_9ax_driver6virtio3net10RxInflightE8do_mergeNCINvB2_20merge_tracking_childNtNtBd_5alloc6GlobalE0INtB7_7NodeRefNtNtB7_6marker3MuttB1k_NtB3r_14LeafOrInternalEB2P_EB1q_+0x92 (7 samples, 0.35%)_RINvMsW_NtNtNtCs2W9OV9R0Aa1_5alloc11collections5btree4nodeINtB6_6HandleINtB6_7NodeRefNtNtB6_6marker3MuttNtNtNtCse8JQZBARWTK_9ax_driver6virtio3net10RxInflightNtB1n_8InternalENtB1n_2KVE5splitNtNtBc_5alloc6GlobalEB1K_+0x110 (16 samples, 0.81%)_.._RINvMsW_NtNtNtCs2W9OV9R0Aa1_5alloc11collections5btree4nodeINtB6_6HandleINtB6_7NodeRefNtNtB6_6marker3MuttNtNtNtCse8JQZBARWTK_9ax_driver6virtio3net10RxInflightNtB1n_8InternalENtB1n_2KVE5splitNtNtBc_5alloc6GlobalEB1K_+0x11a (9 samples, 0.46%)_RINvMsW_NtNtNtCs2W9OV9R0Aa1_5alloc11collections5btree4nodeINtB6_6HandleINtB6_7NodeRefNtNtB6_6marker3MuttNtNtNtCse8JQZBARWTK_9ax_driver6virtio3net10RxInflightNtB1n_8InternalENtB1n_2KVE5splitNtNtBc_5alloc6GlobalEB1K_+0x11e (8 samples, 0.40%)_RINvMsW_NtNtNtCs2W9OV9R0Aa1_5alloc11collections5btree4nodeINtB6_6HandleINtB6_7NodeRefNtNtB6_6marker3MuttNtNtNtCse8JQZBARWTK_9ax_driver6virtio3net10RxInflightNtB1n_8InternalENtB1n_2KVE5splitNtNtBc_5alloc6GlobalEB1K_+0x128 (10 samples, 0.51%)_RINvMs_NtCsjoxaZGNdFP9_7ax_task10wait_queueNtB5_9WaitQueue10wait_untilNCNvMs2_NtCs2x05nxSvmHt_7ax_sync5mutexNtB1e_8RawMutex18lock_after_prepare0ECs41CxRoq78v7_10ax_display+0x434 (8 samples, 0.40%)_RINvMs_NtCsjoxaZGNdFP9_7ax_task10wait_queueNtB5_9WaitQueue10wait_untilNCNvMs2_NtCs2x05nxSvmHt_7ax_sync5mutexNtB1e_8RawMutex18lock_after_prepare0ECs41CxRoq78v7_10ax_display+0x45a (44 samples, 2.23%)_RINvMs.._RINvMs_NtCsjoxaZGNdFP9_7ax_task10wait_queueNtB5_9WaitQueue10wait_untilNCNvMs2_NtCs2x05nxSvmHt_7ax_sync5mutexNtB1e_8RawMutex18lock_after_prepare0ECs41CxRoq78v7_10ax_display+0x460 (9 samples, 0.46%)_RINvMs_NtCsjoxaZGNdFP9_7ax_task10wait_queueNtB5_9WaitQueue10wait_untilNCNvMs2_NtCs2x05nxSvmHt_7ax_sync5mutexNtB1e_8RawMutex18lock_after_prepare0ECs41CxRoq78v7_10ax_display+0x466 (69 samples, 3.49%)_RINvMs_NtCs.._RINvMs_NtCsjoxaZGNdFP9_7ax_task10wait_queueNtB5_9WaitQueue10wait_untilNCNvMs2_NtCs2x05nxSvmHt_7ax_sync5mutexNtB1e_8RawMutex18lock_after_prepare0ECs41CxRoq78v7_10ax_display+0x48c (7 samples, 0.35%)_RINvMs_NtCsjoxaZGNdFP9_7ax_task10wait_queueNtB5_9WaitQueue10wait_untilNCNvMs2_NtCs2x05nxSvmHt_7ax_sync5mutexNtB1e_8RawMutex18lock_after_prepare0ECs41CxRoq78v7_10ax_display+0x490 (8 samples, 0.40%)_RNSNvYNCNvMs1_NtNtNtNtNtCsbgXMhWHegTz_13starry_kernel8pseudofs3dev3tty8terminal5ldiscINtBc_14LineDisciplineNtNtBg_4ntty7ConsoleB1H_E20spawn_polling_reader0INtNtNtCsgiRWr7r9Nzy_4core3ops8function6FnOnceuE9call_once6vtableBm_+0x108 (19 samples, 0.96%)_R.._RNSNvYNCNvMs1_NtNtNtNtNtCsbgXMhWHegTz_13starry_kernel8pseudofs3dev3tty8terminal5ldiscINtBc_14LineDisciplineNtNtBg_4ntty7ConsoleB1H_E20spawn_polling_reader0INtNtNtCsgiRWr7r9Nzy_4core3ops8function6FnOnceuE9call_once6vtableBm_+0x11a (10 samples, 0.51%)_RNSNvYNCNvMs1_NtNtNtNtNtCsbgXMhWHegTz_13starry_kernel8pseudofs3dev3tty8terminal5ldiscINtBc_14LineDisciplineNtNtBg_4ntty7ConsoleB1H_E20spawn_polling_reader0INtNtNtCsgiRWr7r9Nzy_4core3ops8function6FnOnceuE9call_once6vtableBm_+0x134 (10 samples, 0.51%)_RNSNvYNCNvMs1_NtNtNtNtNtCsbgXMhWHegTz_13starry_kernel8pseudofs3dev3tty8terminal5ldiscINtBc_14LineDisciplineNtNtBg_4ntty7ConsoleB1H_E20spawn_polling_reader0INtNtNtCsgiRWr7r9Nzy_4core3ops8function6FnOnceuE9call_once6vtableBm_+0x146 (9 samples, 0.46%)_RNSNvYNCNvMs1_NtNtNtNtNtCsbgXMhWHegTz_13starry_kernel8pseudofs3dev3tty8terminal5ldiscINtBc_14LineDisciplineNtNtBg_4ntty7ConsoleB1H_E20spawn_polling_reader0INtNtNtCsgiRWr7r9Nzy_4core3ops8function6FnOnceuE9call_once6vtableBm_+0x150 (7 samples, 0.35%)_RNSNvYNCNvMs1_NtNtNtNtNtCsbgXMhWHegTz_13starry_kernel8pseudofs3dev3tty8terminal5ldiscINtBc_14LineDisciplineNtNtBg_4ntty7ConsoleB1H_E20spawn_polling_reader0INtNtNtCsgiRWr7r9Nzy_4core3ops8function6FnOnceuE9call_once6vtableBm_+0x162 (14 samples, 0.71%)_RNSNvYNCNvMs1_NtNtNtNtNtCsbgXMhWHegTz_13starry_kernel8pseudofs3dev3tty8terminal5ldiscINtBc_14LineDisciplineNtNtBg_4ntty7ConsoleB1H_E20spawn_polling_reader0INtNtNtCsgiRWr7r9Nzy_4core3ops8function6FnOnceuE9call_once6vtableBm_+0x166 (8 samples, 0.40%)_RNSNvYNCNvMs1_NtNtNtNtNtCsbgXMhWHegTz_13starry_kernel8pseudofs3dev3tty8terminal5ldiscINtBc_14LineDisciplineNtNtBg_4ntty7ConsoleB1H_E20spawn_polling_reader0INtNtNtCsgiRWr7r9Nzy_4core3ops8function6FnOnceuE9call_once6vtableBm_+0x174 (14 samples, 0.71%)_RNSNvYNCNvMs1_NtNtNtNtNtCsbgXMhWHegTz_13starry_kernel8pseudofs3dev3tty8terminal5ldiscINtBc_14LineDisciplineNtNtBg_4ntty7ConsoleB1H_E20spawn_polling_reader0INtNtNtCsgiRWr7r9Nzy_4core3ops8function6FnOnceuE9call_once6vtableBm_+0x176 (8 samples, 0.40%)_RNSNvYNCNvMs1_NtNtNtNtNtCsbgXMhWHegTz_13starry_kernel8pseudofs3dev3tty8terminal5ldiscINtBc_14LineDisciplineNtNtBg_4ntty7ConsoleB1H_E20spawn_polling_reader0INtNtNtCsgiRWr7r9Nzy_4core3ops8function6FnOnceuE9call_once6vtableBm_+0x182 (9 samples, 0.46%)_RNSNvYNCNvMs1_NtNtNtNtNtCsbgXMhWHegTz_13starry_kernel8pseudofs3dev3tty8terminal5ldiscINtBc_14LineDisciplineNtNtBg_4ntty7ConsoleB1H_E20spawn_polling_reader0INtNtNtCsgiRWr7r9Nzy_4core3ops8function6FnOnceuE9call_once6vtableBm_+0x18a (13 samples, 0.66%)_RNSNvYNCNvMs1_NtNtNtNtNtCsbgXMhWHegTz_13starry_kernel8pseudofs3dev3tty8terminal5ldiscINtBc_14LineDisciplineNtNtBg_4ntty7ConsoleB1H_E20spawn_polling_reader0INtNtNtCsgiRWr7r9Nzy_4core3ops8function6FnOnceuE9call_once6vtableBm_+0x194 (10 samples, 0.51%)_RNSNvYNCNvMs1_NtNtNtNtNtCsbgXMhWHegTz_13starry_kernel8pseudofs3dev3tty8terminal5ldiscINtBc_14LineDisciplineNtNtBg_4ntty7ConsoleB1H_E20spawn_polling_reader0INtNtNtCsgiRWr7r9Nzy_4core3ops8function6FnOnceuE9call_once6vtableBm_+0x1c4 (13 samples, 0.66%)_RNSNvYNCNvMs1_NtNtNtNtNtCsbgXMhWHegTz_13starry_kernel8pseudofs3dev3tty8terminal5ldiscINtBc_14LineDisciplineNtNtBg_4ntty7ConsoleB1H_E20spawn_polling_reader0INtNtNtCsgiRWr7r9Nzy_4core3ops8function6FnOnceuE9call_once6vtableBm_+0x5c (13 samples, 0.66%)_RNSNvYNCNvMs1_NtNtNtNtNtCsbgXMhWHegTz_13starry_kernel8pseudofs3dev3tty8terminal5ldiscINtBc_14LineDisciplineNtNtBg_4ntty7ConsoleB1H_E20spawn_polling_reader0INtNtNtCsgiRWr7r9Nzy_4core3ops8function6FnOnceuE9call_once6vtableBm_+0x890 (8 samples, 0.40%)_RNSNvYNCNvMs1_NtNtNtNtNtCsbgXMhWHegTz_13starry_kernel8pseudofs3dev3tty8terminal5ldiscINtBc_14LineDisciplineNtNtBg_4ntty7ConsoleB1H_E20spawn_polling_reader0INtNtNtCsgiRWr7r9Nzy_4core3ops8function6FnOnceuE9call_once6vtableBm_+0x8c8 (12 samples, 0.61%)_RNSNvYNCNvMs1_NtNtNtNtNtCsbgXMhWHegTz_13starry_kernel8pseudofs3dev3tty8terminal5ldiscINtBc_14LineDisciplineNtNtBg_4ntty7ConsoleB1H_E20spawn_polling_reader0INtNtNtCsgiRWr7r9Nzy_4core3ops8function6FnOnceuE9call_once6vtableBm_+0x8d0 (8 samples, 0.40%)_RNSNvYNCNvMs1_NtNtNtNtNtCsbgXMhWHegTz_13starry_kernel8pseudofs3dev3tty8terminal5ldiscINtBc_14LineDisciplineNtNtBg_4ntty7ConsoleB1H_E20spawn_polling_reader0INtNtNtCsgiRWr7r9Nzy_4core3ops8function6FnOnceuE9call_once6vtableBm_+0x8e (11 samples, 0.56%)_RNSNvYNCNvMs1_NtNtNtNtNtCsbgXMhWHegTz_13starry_kernel8pseudofs3dev3tty8terminal5ldiscINtBc_14LineDisciplineNtNtBg_4ntty7ConsoleB1H_E20spawn_polling_reader0INtNtNtCsgiRWr7r9Nzy_4core3ops8function6FnOnceuE9call_once6vtableBm_+0x8e0 (8 samples, 0.40%)_RNSNvYNCNvMs1_NtNtNtNtNtCsbgXMhWHegTz_13starry_kernel8pseudofs3dev3tty8terminal5ldiscINtBc_14LineDisciplineNtNtBg_4ntty7ConsoleB1H_E20spawn_polling_reader0INtNtNtCsgiRWr7r9Nzy_4core3ops8function6FnOnceuE9call_once6vtableBm_+0xb8 (14 samples, 0.71%)_RNSNvYNCNvMs1_NtNtNtNtNtCsbgXMhWHegTz_13starry_kernel8pseudofs3dev3tty8terminal5ldiscINtBc_14LineDisciplineNtNtBg_4ntty7ConsoleB1H_E20spawn_polling_reader0INtNtNtCsgiRWr7r9Nzy_4core3ops8function6FnOnceuE9call_once6vtableBm_+0xbe (16 samples, 0.81%)_.._RNSNvYNCNvMs1_NtNtNtNtNtCsbgXMhWHegTz_13starry_kernel8pseudofs3dev3tty8terminal5ldiscINtBc_14LineDisciplineNtNtBg_4ntty7ConsoleB1H_E20spawn_polling_reader0INtNtNtCsgiRWr7r9Nzy_4core3ops8function6FnOnceuE9call_once6vtableBm_+0xe4 (8 samples, 0.40%)_RNSNvYNCNvMs1_NtNtNtNtNtCsbgXMhWHegTz_13starry_kernel8pseudofs3dev3tty8terminal5ldiscINtBc_14LineDisciplineNtNtBg_4ntty7ConsoleB1H_E20spawn_polling_reader0INtNtNtCsgiRWr7r9Nzy_4core3ops8function6FnOnceuE9call_once6vtableBm_+0xfa (16 samples, 0.81%)_.._RNvMs0_Cse38cudTX6ZT_11ax_lazyinitINtB5_8LazyInitINtNtCs4iPnrq9U4Rv_8lock_api5mutex5MutexNtNtCs2x05nxSvmHt_7ax_sync5mutex8RawMutexNtNtCs41CxRoq78v7_10ax_display6device19ErasedDisplayDeviceEE13panic_messageB28_+0x16 (11 samples, 0.56%)_RNvMs10_NtNtNtCs2W9OV9R0Aa1_5alloc11collections5btree4nodeINtB6_16BalancingContexttNtNtNtCse8JQZBARWTK_9ax_driver6virtio3net10RxInflightE15bulk_steal_leftB1p_+0x1a6 (9 samples, 0.46%)_RNvMs10_NtNtNtCs2W9OV9R0Aa1_5alloc11collections5btree4nodeINtB6_16BalancingContexttNtNtNtCse8JQZBARWTK_9ax_driver6virtio3net10RxInflightE15bulk_steal_leftB1p_+0x1c8 (12 samples, 0.61%)_RNvMs10_NtNtNtCs2W9OV9R0Aa1_5alloc11collections5btree4nodeINtB6_16BalancingContexttNtNtNtCse8JQZBARWTK_9ax_driver6virtio3net10RxInflightE15bulk_steal_leftB1p_+0x1cc (13 samples, 0.66%)_RNvMs1_NtCsjoxaZGNdFP9_7ax_task9run_queueINtB5_18CurrentRunQueueRefNtCs9J4N2FZfJib_15ax_kernel_guard16NoPreemptIrqSaveE13yield_currentB7_ (11 samples, 0.56%)_RNvMs1_NtCsjoxaZGNdFP9_7ax_task9run_queueINtB5_18CurrentRunQueueRefNtCs9J4N2FZfJib_15ax_kernel_guard16NoPreemptIrqSaveE13yield_currentB7_+0x116 (13 samples, 0.66%)_RNvMs1_NtCsjoxaZGNdFP9_7ax_task9run_queueINtB5_18CurrentRunQueueRefNtCs9J4N2FZfJib_15ax_kernel_guard16NoPreemptIrqSaveE13yield_currentB7_+0x11c (11 samples, 0.56%)_RNvMs1_NtCsjoxaZGNdFP9_7ax_task9run_queueINtB5_18CurrentRunQueueRefNtCs9J4N2FZfJib_15ax_kernel_guard16NoPreemptIrqSaveE13yield_currentB7_+0x12a (14 samples, 0.71%)_RNvMs1_NtCsjoxaZGNdFP9_7ax_task9run_queueINtB5_18CurrentRunQueueRefNtCs9J4N2FZfJib_15ax_kernel_guard16NoPreemptIrqSaveE13yield_currentB7_+0x148 (10 samples, 0.51%)_RNvMs1_NtCsjoxaZGNdFP9_7ax_task9run_queueINtB5_18CurrentRunQueueRefNtCs9J4N2FZfJib_15ax_kernel_guard16NoPreemptIrqSaveE13yield_currentB7_+0x166 (9 samples, 0.46%)_RNvMs1_NtCsjoxaZGNdFP9_7ax_task9run_queueINtB5_18CurrentRunQueueRefNtCs9J4N2FZfJib_15ax_kernel_guard16NoPreemptIrqSaveE13yield_currentB7_+0x176 (13 samples, 0.66%)_RNvMs1_NtCsjoxaZGNdFP9_7ax_task9run_queueINtB5_18CurrentRunQueueRefNtCs9J4N2FZfJib_15ax_kernel_guard16NoPreemptIrqSaveE13yield_currentB7_+0x17a (16 samples, 0.81%)_.._RNvMs1_NtCsjoxaZGNdFP9_7ax_task9run_queueINtB5_18CurrentRunQueueRefNtCs9J4N2FZfJib_15ax_kernel_guard16NoPreemptIrqSaveE13yield_currentB7_+0x186 (11 samples, 0.56%)_RNvMs1_NtCsjoxaZGNdFP9_7ax_task9run_queueINtB5_18CurrentRunQueueRefNtCs9J4N2FZfJib_15ax_kernel_guard16NoPreemptIrqSaveE13yield_currentB7_+0x1a0 (8 samples, 0.40%)_RNvMs1_NtCsjoxaZGNdFP9_7ax_task9run_queueINtB5_18CurrentRunQueueRefNtCs9J4N2FZfJib_15ax_kernel_guard16NoPreemptIrqSaveE13yield_currentB7_+0x1b0 (7 samples, 0.35%)_RNvMs1_NtCsjoxaZGNdFP9_7ax_task9run_queueINtB5_18CurrentRunQueueRefNtCs9J4N2FZfJib_15ax_kernel_guard16NoPreemptIrqSaveE13yield_currentB7_+0x1ba (8 samples, 0.40%)_RNvMs1_NtCsjoxaZGNdFP9_7ax_task9run_queueINtB5_18CurrentRunQueueRefNtCs9J4N2FZfJib_15ax_kernel_guard16NoPreemptIrqSaveE13yield_currentB7_+0x1e4 (10 samples, 0.51%)_RNvMs1_NtCsjoxaZGNdFP9_7ax_task9run_queueINtB5_18CurrentRunQueueRefNtCs9J4N2FZfJib_15ax_kernel_guard16NoPreemptIrqSaveE13yield_currentB7_+0x220 (10 samples, 0.51%)_RNvMs1_NtCsjoxaZGNdFP9_7ax_task9run_queueINtB5_18CurrentRunQueueRefNtCs9J4N2FZfJib_15ax_kernel_guard16NoPreemptIrqSaveE13yield_currentB7_+0x254 (14 samples, 0.71%)_RNvMs1_NtCsjoxaZGNdFP9_7ax_task9run_queueINtB5_18CurrentRunQueueRefNtCs9J4N2FZfJib_15ax_kernel_guard16NoPreemptIrqSaveE13yield_currentB7_+0x2a2 (9 samples, 0.46%)_RNvMs1_NtCsjoxaZGNdFP9_7ax_task9run_queueINtB5_18CurrentRunQueueRefNtCs9J4N2FZfJib_15ax_kernel_guard16NoPreemptIrqSaveE13yield_currentB7_+0x2e4 (15 samples, 0.76%)_.._RNvMs1_NtCsjoxaZGNdFP9_7ax_task9run_queueINtB5_18CurrentRunQueueRefNtCs9J4N2FZfJib_15ax_kernel_guard16NoPreemptIrqSaveE13yield_currentB7_+0xb0 (7 samples, 0.35%)_RNvMs1_NtCsjoxaZGNdFP9_7ax_task9run_queueINtB5_18CurrentRunQueueRefNtCs9J4N2FZfJib_15ax_kernel_guard16NoPreemptIrqSaveE13yield_currentB7_+0xda (11 samples, 0.56%)_RNvMs1_NtCsjoxaZGNdFP9_7ax_task9run_queueINtB5_18CurrentRunQueueRefNtCs9J4N2FZfJib_15ax_kernel_guard16NoPreemptIrqSaveE13yield_currentB7_+0xec (9 samples, 0.46%)_RNvMs1_NtCsjoxaZGNdFP9_7ax_task9run_queueINtB5_18CurrentRunQueueRefNtCs9J4N2FZfJib_15ax_kernel_guard16NoPreemptIrqSaveE13yield_currentB7_+0xf6 (11 samples, 0.56%)_RNvMs2_NtCsjMNVNv9nEZt_8ax_alloc10buddy_slabNtB5_15GlobalAllocator11alloc_pages+0x70 (14 samples, 0.71%)_RNvMs2_NtCsjMNVNv9nEZt_8ax_alloc10buddy_slabNtB5_15GlobalAllocator11alloc_pages+0x80 (11 samples, 0.56%)_RNvMs2_NtCsjMNVNv9nEZt_8ax_alloc10buddy_slabNtB5_15GlobalAllocator11alloc_pages+0x8a (12 samples, 0.61%)_RNvMs2_NtCsjMNVNv9nEZt_8ax_alloc10buddy_slabNtB5_15GlobalAllocator11alloc_pages+0x98 (13 samples, 0.66%)_RNvMs2_NtCsjMNVNv9nEZt_8ax_alloc10buddy_slabNtB5_15GlobalAllocator11alloc_pages+0x9e (9 samples, 0.46%)_RNvMs2_NtCsjMNVNv9nEZt_8ax_alloc10buddy_slabNtB5_15GlobalAllocator11alloc_pages+0xc8 (8 samples, 0.40%)_RNvMs2_NtCsjMNVNv9nEZt_8ax_alloc10buddy_slabNtB5_15GlobalAllocator11alloc_pages+0xd6 (7 samples, 0.35%)_RNvMs2_NtCsjMNVNv9nEZt_8ax_alloc10buddy_slabNtB5_15GlobalAllocator11alloc_pages+0xf2 (12 samples, 0.61%)_RNvMs2_NtCsjMNVNv9nEZt_8ax_alloc10buddy_slabNtB5_15GlobalAllocator11alloc_pages+0xf8 (15 samples, 0.76%)_.._RNvMs2_NtCsjoxaZGNdFP9_7ax_task9run_queueNtB5_10AxRunQueue7resched (16 samples, 0.81%)_.._RNvMs2_NtCsjoxaZGNdFP9_7ax_task9run_queueNtB5_10AxRunQueue7resched+0x18 (9 samples, 0.46%)_RNvMs2_NtCsjoxaZGNdFP9_7ax_task9run_queueNtB5_10AxRunQueue7resched+0x2a (9 samples, 0.46%)_RNvMs2_NtCsjoxaZGNdFP9_7ax_task9run_queueNtB5_10AxRunQueue7resched+0x34 (8 samples, 0.40%)_RNvMs2_NtCsjoxaZGNdFP9_7ax_task9run_queueNtB5_10AxRunQueue7resched+0x78 (8 samples, 0.40%)_RNvMs2_NtCsjoxaZGNdFP9_7ax_task9run_queueNtB5_10AxRunQueue7resched+0xa8 (12 samples, 0.61%)_RNvMs2_NtCsjoxaZGNdFP9_7ax_task9run_queueNtB5_10AxRunQueue7resched+0xae (12 samples, 0.61%)_RNvMs2_NtCsjoxaZGNdFP9_7ax_task9run_queueNtB5_10AxRunQueue7resched+0xb2 (16 samples, 0.81%)_.._RNvMs2_NtCsjoxaZGNdFP9_7ax_task9run_queueNtB5_10AxRunQueue7resched+0xd2 (17 samples, 0.86%)_.._RNvMs2_NtCsjoxaZGNdFP9_7ax_task9run_queueNtB5_10AxRunQueue9switch_to (13 samples, 0.66%)_RNvMs2_NtCsjoxaZGNdFP9_7ax_task9run_queueNtB5_10AxRunQueue9switch_to+0x110 (11 samples, 0.56%)_RNvMs2_NtCsjoxaZGNdFP9_7ax_task9run_queueNtB5_10AxRunQueue9switch_to+0x128 (7 samples, 0.35%)_RNvMs2_NtCsjoxaZGNdFP9_7ax_task9run_queueNtB5_10AxRunQueue9switch_to+0x1e (10 samples, 0.51%)_RNvMs2_NtCsjoxaZGNdFP9_7ax_task9run_queueNtB5_10AxRunQueue9switch_to+0x21c (14 samples, 0.71%)_RNvMs2_NtCsjoxaZGNdFP9_7ax_task9run_queueNtB5_10AxRunQueue9switch_to+0x43e (11 samples, 0.56%)_RNvMs3_NtCs2W9OV9R0Aa1_5alloc3stre12to_uppercase+0x434 (10 samples, 0.51%)_RNvMs3_NtCs2W9OV9R0Aa1_5alloc3stre12to_uppercase+0x440 (13 samples, 0.66%)_RNvMs3_NtCsjoxaZGNdFP9_7ax_task4taskNtB5_9TaskInner29current_check_preempt_pending (22 samples, 1.11%)_R.._RNvMs3_NtCsjoxaZGNdFP9_7ax_task4taskNtB5_9TaskInner29current_check_preempt_pending+0x18 (28 samples, 1.42%)_RN.._RNvMs3_NtCsjoxaZGNdFP9_7ax_task4taskNtB5_9TaskInner29current_check_preempt_pending+0x38 (31 samples, 1.57%)_RNv.._RNvMs3_NtCsjoxaZGNdFP9_7ax_task4taskNtB5_9TaskInner29current_check_preempt_pending+0x3c (8 samples, 0.40%)_RNvMs3_NtCsjoxaZGNdFP9_7ax_task4taskNtB5_9TaskInner29current_check_preempt_pending+0x4e (18 samples, 0.91%)_.._RNvNtCsjoxaZGNdFP9_7ax_task3api9yield_now (16 samples, 0.81%)_.._RNvNtCsjoxaZGNdFP9_7ax_task3api9yield_now+0x10 (8 samples, 0.40%)_RNvNtCsjoxaZGNdFP9_7ax_task3api9yield_now+0x14 (7 samples, 0.35%)_RNvNtCsjoxaZGNdFP9_7ax_task3api9yield_now+0x34 (19 samples, 0.96%)_R.._RNvNtCsjoxaZGNdFP9_7ax_task3api9yield_now+0x36 (7 samples, 0.35%)_RNvNtCsjoxaZGNdFP9_7ax_task3api9yield_now+0x3e (18 samples, 0.91%)_.._RNvNtCsjoxaZGNdFP9_7ax_task3api9yield_now+0x42 (12 samples, 0.61%)_RNvNtCsjoxaZGNdFP9_7ax_task3api9yield_now+0x50 (12 samples, 0.61%)_RNvNtCsjoxaZGNdFP9_7ax_task3api9yield_now+0x60 (17 samples, 0.86%)_.._RNvNtCsjoxaZGNdFP9_7ax_task3api9yield_now+0x7e (8 samples, 0.40%)_RNvNtCsjoxaZGNdFP9_7ax_task3api9yield_now+0x82 (23 samples, 1.16%)_R.._RNvNtCsjoxaZGNdFP9_7ax_task3api9yield_now+0x90 (10 samples, 0.51%)_RNvNtCsjoxaZGNdFP9_7ax_task3api9yield_now+0x92 (8 samples, 0.40%)_RNvNtCsjoxaZGNdFP9_7ax_task3api9yield_now+0xa8 (7 samples, 0.35%)_RNvNtCsjoxaZGNdFP9_7ax_task3api9yield_now+0xac (18 samples, 0.91%)_.._RNvNtCsjoxaZGNdFP9_7ax_task3api9yield_now+0xb0 (14 samples, 0.71%)_RNvNtCsjoxaZGNdFP9_7ax_task3api9yield_now+0xbe (12 samples, 0.61%)_RNvNtCsjoxaZGNdFP9_7ax_task3api9yield_now+0xc (16 samples, 0.81%)_.._RNvNtCsjoxaZGNdFP9_7ax_task3api9yield_now+0xc0 (9 samples, 0.46%)_RNvNtCsjoxaZGNdFP9_7ax_task3api9yield_now+0xd0 (8 samples, 0.40%)_RNvNtNtCse8JQZBARWTK_9ax_driver3pci3fdt18probe_generic_ecam+0x680 (7 samples, 0.35%)_RNvNtNtCse8JQZBARWTK_9ax_driver3pci3fdt18probe_generic_ecam+0x6c0 (7 samples, 0.35%)_RNvNtNtCse8JQZBARWTK_9ax_driver3pci3fdt18probe_generic_ecam+0x70c (11 samples, 0.56%)_RNvNtNtCse8JQZBARWTK_9ax_driver3pci3fdt18probe_generic_ecam+0x710 (83 samples, 4.20%)_RNvNtNtCse8JQZ.._RNvNtNtCse8JQZBARWTK_9ax_driver3pci3fdt18probe_generic_ecam+0x72e (7 samples, 0.35%)_head+0x4f8 (35 samples, 1.77%)_head.._head+0x4fc (17 samples, 0.86%)_.._head+0x504 (10 samples, 0.51%)_head+0x534 (22 samples, 1.11%)_h.._head+0x538 (12 samples, 0.61%)_head+0x53e (15 samples, 0.76%)_.._head+0x582 (12 samples, 0.61%)_head+0x588 (17 samples, 0.86%)_.._head+0x58e (14 samples, 0.71%)_head+0x594 (10 samples, 0.51%)_head+0x59a (12 samples, 0.61%)_head+0x5ae (18 samples, 0.91%)_.._head+0x5b6 (20 samples, 1.01%)_h.._head+0x624 (22 samples, 1.11%)_h.._head+0x62c (9 samples, 0.46%)all (1,976 samples, 100%) \ No newline at end of file diff --git a/docs/flamegraphs/target__qperf-virtio-drivers__net-wget-focused__perf__riscv64__latest__qperf__flamegraph.svg b/docs/flamegraphs/target__qperf-virtio-drivers__net-wget-focused__perf__riscv64__latest__qperf__flamegraph.svg new file mode 100644 index 0000000000..dc2eada740 --- /dev/null +++ b/docs/flamegraphs/target__qperf-virtio-drivers__net-wget-focused__perf__riscv64__latest__qperf__flamegraph.svg @@ -0,0 +1,491 @@ +StarryOS qperf Flame Graph Reset ZoomSearch _RINvMs10_NtNtNtCs2W9OV9R0Aa1_5alloc11collections5btree4nodeINtB7_16BalancingContexttNtNtNtCse8JQZBARWTK_9ax_driver6virtio3net10RxInflightE8do_mergeNCINvB2_20merge_tracking_childNtNtBd_5alloc6GlobalE0INtB7_7NodeRefNtNtB7_6marker3MuttB1k_NtB3r_14LeafOrInternalEB2P_EB1q_+0x92 (11 samples, 0.44%)_RINvMs10_NtNtNtCs2W9OV9R0Aa1_5alloc11collections5btree4nodeINtB7_16BalancingContexttNtNtNtCse8JQZBARWTK_9ax_driver6virtio3net10RxInflightE8do_mergeNCINvB2_20merge_tracking_childNtNtBd_5alloc6GlobalE0INtB7_7NodeRefNtNtB7_6marker3MuttB1k_NtB3r_14LeafOrInternalEB2P_EB1q_+0x96 (13 samples, 0.53%)_RINvMsW_NtNtNtCs2W9OV9R0Aa1_5alloc11collections5btree4nodeINtB6_6HandleINtB6_7NodeRefNtNtB6_6marker3MuttNtNtNtCse8JQZBARWTK_9ax_driver6virtio3net10RxInflightNtB1n_8InternalENtB1n_2KVE5splitNtNtBc_5alloc6GlobalEB1K_+0x110 (14 samples, 0.57%)_RINvMsW_NtNtNtCs2W9OV9R0Aa1_5alloc11collections5btree4nodeINtB6_6HandleINtB6_7NodeRefNtNtB6_6marker3MuttNtNtNtCse8JQZBARWTK_9ax_driver6virtio3net10RxInflightNtB1n_8InternalENtB1n_2KVE5splitNtNtBc_5alloc6GlobalEB1K_+0x11e (9 samples, 0.36%)_RINvMs_NtCsjoxaZGNdFP9_7ax_task10wait_queueNtB5_9WaitQueue10wait_untilNCNvMs2_NtCs2x05nxSvmHt_7ax_sync5mutexNtB1e_8RawMutex18lock_after_prepare0ECs41CxRoq78v7_10ax_display+0x434 (10 samples, 0.40%)_RINvMs_NtCsjoxaZGNdFP9_7ax_task10wait_queueNtB5_9WaitQueue10wait_untilNCNvMs2_NtCs2x05nxSvmHt_7ax_sync5mutexNtB1e_8RawMutex18lock_after_prepare0ECs41CxRoq78v7_10ax_display+0x45a (85 samples, 3.44%)_RINvMs_NtCs.._RINvMs_NtCsjoxaZGNdFP9_7ax_task10wait_queueNtB5_9WaitQueue10wait_untilNCNvMs2_NtCs2x05nxSvmHt_7ax_sync5mutexNtB1e_8RawMutex18lock_after_prepare0ECs41CxRoq78v7_10ax_display+0x466 (68 samples, 2.75%)_RINvMs_N.._RNSNvYNCNvMs1_NtNtNtNtNtCsbgXMhWHegTz_13starry_kernel8pseudofs3dev3tty8terminal5ldiscINtBc_14LineDisciplineNtNtBg_4ntty7ConsoleB1H_E20spawn_polling_reader0INtNtNtCsgiRWr7r9Nzy_4core3ops8function6FnOnceuE9call_once6vtableBm_+0x11a (16 samples, 0.65%)_RNSNvYNCNvMs1_NtNtNtNtNtCsbgXMhWHegTz_13starry_kernel8pseudofs3dev3tty8terminal5ldiscINtBc_14LineDisciplineNtNtBg_4ntty7ConsoleB1H_E20spawn_polling_reader0INtNtNtCsgiRWr7r9Nzy_4core3ops8function6FnOnceuE9call_once6vtableBm_+0x162 (13 samples, 0.53%)_RNSNvYNCNvMs1_NtNtNtNtNtCsbgXMhWHegTz_13starry_kernel8pseudofs3dev3tty8terminal5ldiscINtBc_14LineDisciplineNtNtBg_4ntty7ConsoleB1H_E20spawn_polling_reader0INtNtNtCsgiRWr7r9Nzy_4core3ops8function6FnOnceuE9call_once6vtableBm_+0x166 (10 samples, 0.40%)_RNSNvYNCNvMs1_NtNtNtNtNtCsbgXMhWHegTz_13starry_kernel8pseudofs3dev3tty8terminal5ldiscINtBc_14LineDisciplineNtNtBg_4ntty7ConsoleB1H_E20spawn_polling_reader0INtNtNtCsgiRWr7r9Nzy_4core3ops8function6FnOnceuE9call_once6vtableBm_+0x174 (16 samples, 0.65%)_RNSNvYNCNvMs1_NtNtNtNtNtCsbgXMhWHegTz_13starry_kernel8pseudofs3dev3tty8terminal5ldiscINtBc_14LineDisciplineNtNtBg_4ntty7ConsoleB1H_E20spawn_polling_reader0INtNtNtCsgiRWr7r9Nzy_4core3ops8function6FnOnceuE9call_once6vtableBm_+0x182 (11 samples, 0.44%)_RNSNvYNCNvMs1_NtNtNtNtNtCsbgXMhWHegTz_13starry_kernel8pseudofs3dev3tty8terminal5ldiscINtBc_14LineDisciplineNtNtBg_4ntty7ConsoleB1H_E20spawn_polling_reader0INtNtNtCsgiRWr7r9Nzy_4core3ops8function6FnOnceuE9call_once6vtableBm_+0x18a (9 samples, 0.36%)_RNSNvYNCNvMs1_NtNtNtNtNtCsbgXMhWHegTz_13starry_kernel8pseudofs3dev3tty8terminal5ldiscINtBc_14LineDisciplineNtNtBg_4ntty7ConsoleB1H_E20spawn_polling_reader0INtNtNtCsgiRWr7r9Nzy_4core3ops8function6FnOnceuE9call_once6vtableBm_+0x194 (10 samples, 0.40%)_RNSNvYNCNvMs1_NtNtNtNtNtCsbgXMhWHegTz_13starry_kernel8pseudofs3dev3tty8terminal5ldiscINtBc_14LineDisciplineNtNtBg_4ntty7ConsoleB1H_E20spawn_polling_reader0INtNtNtCsgiRWr7r9Nzy_4core3ops8function6FnOnceuE9call_once6vtableBm_+0x5c (9 samples, 0.36%)_RNSNvYNCNvMs1_NtNtNtNtNtCsbgXMhWHegTz_13starry_kernel8pseudofs3dev3tty8terminal5ldiscINtBc_14LineDisciplineNtNtBg_4ntty7ConsoleB1H_E20spawn_polling_reader0INtNtNtCsgiRWr7r9Nzy_4core3ops8function6FnOnceuE9call_once6vtableBm_+0x8e0 (10 samples, 0.40%)_RNSNvYNCNvMs1_NtNtNtNtNtCsbgXMhWHegTz_13starry_kernel8pseudofs3dev3tty8terminal5ldiscINtBc_14LineDisciplineNtNtBg_4ntty7ConsoleB1H_E20spawn_polling_reader0INtNtNtCsgiRWr7r9Nzy_4core3ops8function6FnOnceuE9call_once6vtableBm_+0xbe (15 samples, 0.61%)_RNSNvYNCNvMs1_NtNtNtNtNtCsbgXMhWHegTz_13starry_kernel8pseudofs3dev3tty8terminal5ldiscINtBc_14LineDisciplineNtNtBg_4ntty7ConsoleB1H_E20spawn_polling_reader0INtNtNtCsgiRWr7r9Nzy_4core3ops8function6FnOnceuE9call_once6vtableBm_+0xe4 (9 samples, 0.36%)_RNSNvYNCNvMs1_NtNtNtNtNtCsbgXMhWHegTz_13starry_kernel8pseudofs3dev3tty8terminal5ldiscINtBc_14LineDisciplineNtNtBg_4ntty7ConsoleB1H_E20spawn_polling_reader0INtNtNtCsgiRWr7r9Nzy_4core3ops8function6FnOnceuE9call_once6vtableBm_+0xfa (15 samples, 0.61%)_RNvCs41CxRoq78v7_10ax_display17framebuffer_flush+0x32 (9 samples, 0.36%)_RNvMs0_Cse38cudTX6ZT_11ax_lazyinitINtB5_8LazyInitINtNtCs4iPnrq9U4Rv_8lock_api5mutex5MutexNtNtCs2x05nxSvmHt_7ax_sync5mutex8RawMutexNtNtCs41CxRoq78v7_10ax_display6device19ErasedDisplayDeviceEE13panic_messageB28_+0x10 (11 samples, 0.44%)_RNvMs0_Cse38cudTX6ZT_11ax_lazyinitINtB5_8LazyInitINtNtCs4iPnrq9U4Rv_8lock_api5mutex5MutexNtNtCs2x05nxSvmHt_7ax_sync5mutex8RawMutexNtNtCs41CxRoq78v7_10ax_display6device19ErasedDisplayDeviceEE13panic_messageB28_+0x16 (10 samples, 0.40%)_RNvMs10_NtNtNtCs2W9OV9R0Aa1_5alloc11collections5btree4nodeINtB6_16BalancingContexttNtNtNtCse8JQZBARWTK_9ax_driver6virtio3net10RxInflightE15bulk_steal_leftB1p_+0x1a6 (9 samples, 0.36%)_RNvMs10_NtNtNtCs2W9OV9R0Aa1_5alloc11collections5btree4nodeINtB6_16BalancingContexttNtNtNtCse8JQZBARWTK_9ax_driver6virtio3net10RxInflightE15bulk_steal_leftB1p_+0x1c8 (12 samples, 0.49%)_RNvMs1_NtCsjoxaZGNdFP9_7ax_task9run_queueINtB5_18CurrentRunQueueRefNtCs9J4N2FZfJib_15ax_kernel_guard16NoPreemptIrqSaveE13yield_currentB7_ (10 samples, 0.40%)_RNvMs1_NtCsjoxaZGNdFP9_7ax_task9run_queueINtB5_18CurrentRunQueueRefNtCs9J4N2FZfJib_15ax_kernel_guard16NoPreemptIrqSaveE13yield_currentB7_+0x116 (14 samples, 0.57%)_RNvMs1_NtCsjoxaZGNdFP9_7ax_task9run_queueINtB5_18CurrentRunQueueRefNtCs9J4N2FZfJib_15ax_kernel_guard16NoPreemptIrqSaveE13yield_currentB7_+0x12a (9 samples, 0.36%)_RNvMs1_NtCsjoxaZGNdFP9_7ax_task9run_queueINtB5_18CurrentRunQueueRefNtCs9J4N2FZfJib_15ax_kernel_guard16NoPreemptIrqSaveE13yield_currentB7_+0x166 (10 samples, 0.40%)_RNvMs1_NtCsjoxaZGNdFP9_7ax_task9run_queueINtB5_18CurrentRunQueueRefNtCs9J4N2FZfJib_15ax_kernel_guard16NoPreemptIrqSaveE13yield_currentB7_+0x176 (9 samples, 0.36%)_RNvMs1_NtCsjoxaZGNdFP9_7ax_task9run_queueINtB5_18CurrentRunQueueRefNtCs9J4N2FZfJib_15ax_kernel_guard16NoPreemptIrqSaveE13yield_currentB7_+0x17a (9 samples, 0.36%)_RNvMs1_NtCsjoxaZGNdFP9_7ax_task9run_queueINtB5_18CurrentRunQueueRefNtCs9J4N2FZfJib_15ax_kernel_guard16NoPreemptIrqSaveE13yield_currentB7_+0x1b0 (11 samples, 0.44%)_RNvMs1_NtCsjoxaZGNdFP9_7ax_task9run_queueINtB5_18CurrentRunQueueRefNtCs9J4N2FZfJib_15ax_kernel_guard16NoPreemptIrqSaveE13yield_currentB7_+0x2c8 (9 samples, 0.36%)_RNvMs1_NtCsjoxaZGNdFP9_7ax_task9run_queueINtB5_18CurrentRunQueueRefNtCs9J4N2FZfJib_15ax_kernel_guard16NoPreemptIrqSaveE13yield_currentB7_+0x2e4 (10 samples, 0.40%)_RNvMs1_NtCsjoxaZGNdFP9_7ax_task9run_queueINtB5_18CurrentRunQueueRefNtCs9J4N2FZfJib_15ax_kernel_guard16NoPreemptIrqSaveE13yield_currentB7_+0xb0 (12 samples, 0.49%)_RNvMs1_NtCsjoxaZGNdFP9_7ax_task9run_queueINtB5_18CurrentRunQueueRefNtCs9J4N2FZfJib_15ax_kernel_guard16NoPreemptIrqSaveE13yield_currentB7_+0xda (10 samples, 0.40%)_RNvMs1_NtCsjoxaZGNdFP9_7ax_task9run_queueINtB5_18CurrentRunQueueRefNtCs9J4N2FZfJib_15ax_kernel_guard16NoPreemptIrqSaveE13yield_currentB7_+0xf6 (10 samples, 0.40%)_RNvMs2_NtCsjMNVNv9nEZt_8ax_alloc10buddy_slabNtB5_15GlobalAllocator11alloc_pages+0x70 (11 samples, 0.44%)_RNvMs2_NtCsjMNVNv9nEZt_8ax_alloc10buddy_slabNtB5_15GlobalAllocator11alloc_pages+0x80 (10 samples, 0.40%)_RNvMs2_NtCsjoxaZGNdFP9_7ax_task9run_queueNtB5_10AxRunQueue7resched (9 samples, 0.36%)_RNvMs2_NtCsjoxaZGNdFP9_7ax_task9run_queueNtB5_10AxRunQueue7resched+0x78 (9 samples, 0.36%)_RNvMs2_NtCsjoxaZGNdFP9_7ax_task9run_queueNtB5_10AxRunQueue7resched+0xa8 (12 samples, 0.49%)_RNvMs2_NtCsjoxaZGNdFP9_7ax_task9run_queueNtB5_10AxRunQueue7resched+0xae (9 samples, 0.36%)_RNvMs2_NtCsjoxaZGNdFP9_7ax_task9run_queueNtB5_10AxRunQueue7resched+0xd2 (15 samples, 0.61%)_RNvMs2_NtCsjoxaZGNdFP9_7ax_task9run_queueNtB5_10AxRunQueue9switch_to (14 samples, 0.57%)_RNvMs2_NtCsjoxaZGNdFP9_7ax_task9run_queueNtB5_10AxRunQueue9switch_to+0x21c (11 samples, 0.44%)_RNvMs2_NtCsjoxaZGNdFP9_7ax_task9run_queueNtB5_10AxRunQueue9switch_to+0x24 (10 samples, 0.40%)_RNvMs3_NtCs2W9OV9R0Aa1_5alloc3stre12to_uppercase+0x434 (9 samples, 0.36%)_RNvMs3_NtCsjoxaZGNdFP9_7ax_task4taskNtB5_9TaskInner29current_check_preempt_pending (26 samples, 1.05%)_R.._RNvMs3_NtCsjoxaZGNdFP9_7ax_task4taskNtB5_9TaskInner29current_check_preempt_pending+0x18 (28 samples, 1.13%)_R.._RNvMs3_NtCsjoxaZGNdFP9_7ax_task4taskNtB5_9TaskInner29current_check_preempt_pending+0x38 (20 samples, 0.81%)_.._RNvMs3_NtCsjoxaZGNdFP9_7ax_task4taskNtB5_9TaskInner29current_check_preempt_pending+0x3c (12 samples, 0.49%)_RNvNtCs9OcUSfjU0zs_17compiler_builtins3mem6memcpy+0x10c (71 samples, 2.87%)_RNvNtCs9.._RNvNtCs9OcUSfjU0zs_17compiler_builtins3mem6memcpy+0x4a (134 samples, 5.42%)_RNvNtCs9OcUSfjU0zs_.._RNvNtCs9OcUSfjU0zs_17compiler_builtins3mem7memmove+0x2a4 (43 samples, 1.74%)_RNvN.._RNvNtCs9OcUSfjU0zs_17compiler_builtins3mem7memmove+0x6c (9 samples, 0.36%)_RNvNtCsjoxaZGNdFP9_7ax_task3api9yield_now (17 samples, 0.69%)_RNvNtCsjoxaZGNdFP9_7ax_task3api9yield_now+0x34 (16 samples, 0.65%)_RNvNtCsjoxaZGNdFP9_7ax_task3api9yield_now+0x3e (9 samples, 0.36%)_RNvNtCsjoxaZGNdFP9_7ax_task3api9yield_now+0x42 (17 samples, 0.69%)_RNvNtCsjoxaZGNdFP9_7ax_task3api9yield_now+0x50 (14 samples, 0.57%)_RNvNtCsjoxaZGNdFP9_7ax_task3api9yield_now+0x60 (12 samples, 0.49%)_RNvNtCsjoxaZGNdFP9_7ax_task3api9yield_now+0x82 (20 samples, 0.81%)_.._RNvNtCsjoxaZGNdFP9_7ax_task3api9yield_now+0x90 (14 samples, 0.57%)_RNvNtCsjoxaZGNdFP9_7ax_task3api9yield_now+0x92 (9 samples, 0.36%)_RNvNtCsjoxaZGNdFP9_7ax_task3api9yield_now+0xac (12 samples, 0.49%)_RNvNtCsjoxaZGNdFP9_7ax_task3api9yield_now+0xb0 (15 samples, 0.61%)_RNvNtCsjoxaZGNdFP9_7ax_task3api9yield_now+0xbe (17 samples, 0.69%)_RNvNtCsjoxaZGNdFP9_7ax_task3api9yield_now+0xc (10 samples, 0.40%)_RNvNtNtCse8JQZBARWTK_9ax_driver3pci3fdt18probe_generic_ecam+0x680 (11 samples, 0.44%)_RNvNtNtCse8JQZBARWTK_9ax_driver3pci3fdt18probe_generic_ecam+0x710 (83 samples, 3.35%)_RNvNtNtCse.._RNvNtNtCse8JQZBARWTK_9ax_driver3pci3fdt18probe_generic_ecam+0x72e (12 samples, 0.49%)_RNvNtNtNtCs4bLJakJfdhC_7smoltcp4wire2ip8checksum4data+0x22 (14 samples, 0.57%)_RNvXs9_NtNtCse8JQZBARWTK_9ax_driver6virtio3netINtB5_10NetRxQueueNtNtNtCsa9GpAcvErGs_14virtio_drivers9transport3pci12PciTransportENtCsfcOzc4h9Az9_8rdif_eth8IRxQueue6submitB9_+0x232 (27 samples, 1.09%)_R.._RNvXs_NtCsjMNVNv9nEZt_8ax_alloc10buddy_slabNtB4_10PercpuSlabNtNtCs4fiTdtanek2_20buddy_slab_allocator4slab9SlabTrait5allocB6_+0xfa (10 samples, 0.40%)_RNvXs_NtCsjMNVNv9nEZt_8ax_alloc10buddy_slabNtB4_10PercpuSlabNtNtCs4fiTdtanek2_20buddy_slab_allocator4slab9SlabTrait5allocB6_+0xfc (11 samples, 0.44%)_head+0x11a2 (30 samples, 1.21%)_he.._head+0x4f8 (22 samples, 0.89%)_.._head+0x4fc (21 samples, 0.85%)_.._head+0x534 (16 samples, 0.65%)_head+0x53e (11 samples, 0.44%)_head+0x582 (10 samples, 0.40%)_head+0x58e (10 samples, 0.40%)_head+0x594 (11 samples, 0.44%)_head+0x59a (13 samples, 0.53%)_head+0x5ae (13 samples, 0.53%)_head+0x5b6 (23 samples, 0.93%)_.._head+0x624 (20 samples, 0.81%)_.._head+0x62c (12 samples, 0.49%)memcpy (10 samples, 0.40%)all (2,474 samples, 100%) \ No newline at end of file diff --git a/docs/flamegraphs/target__qperf-virtio-drivers__net-wget__perf__riscv64__latest__qperf__flamegraph.svg b/docs/flamegraphs/target__qperf-virtio-drivers__net-wget__perf__riscv64__latest__qperf__flamegraph.svg new file mode 100644 index 0000000000..6012386699 --- /dev/null +++ b/docs/flamegraphs/target__qperf-virtio-drivers__net-wget__perf__riscv64__latest__qperf__flamegraph.svg @@ -0,0 +1,491 @@ +StarryOS qperf Flame Graph Reset ZoomSearch _RINvMs10_NtNtNtCs2W9OV9R0Aa1_5alloc11collections5btree4nodeINtB7_16BalancingContexttNtNtNtCse8JQZBARWTK_9ax_driver6virtio3net10RxInflightE8do_mergeNCINvB2_20merge_tracking_childNtNtBd_5alloc6GlobalE0INtB7_7NodeRefNtNtB7_6marker3MuttB1k_NtB3r_14LeafOrInternalEB2P_EB1q_+0x92 (30 samples, 0.67%)_RINvMs10_NtNtNtCs2W9OV9R0Aa1_5alloc11collections5btree4nodeINtB7_16BalancingContexttNtNtNtCse8JQZBARWTK_9ax_driver6virtio3net10RxInflightE8do_mergeNCINvB2_20merge_tracking_childNtNtBd_5alloc6GlobalE0INtB7_7NodeRefNtNtB7_6marker3MuttB1k_NtB3r_14LeafOrInternalEB2P_EB1q_+0x96 (16 samples, 0.36%)_RINvMsW_NtNtNtCs2W9OV9R0Aa1_5alloc11collections5btree4nodeINtB6_6HandleINtB6_7NodeRefNtNtB6_6marker3MuttNtNtNtCse8JQZBARWTK_9ax_driver6virtio3net10RxInflightNtB1n_8InternalENtB1n_2KVE5splitNtNtBc_5alloc6GlobalEB1K_+0x110 (25 samples, 0.56%)_RINvMsW_NtNtNtCs2W9OV9R0Aa1_5alloc11collections5btree4nodeINtB6_6HandleINtB6_7NodeRefNtNtB6_6marker3MuttNtNtNtCse8JQZBARWTK_9ax_driver6virtio3net10RxInflightNtB1n_8InternalENtB1n_2KVE5splitNtNtBc_5alloc6GlobalEB1K_+0x11e (17 samples, 0.38%)_RINvMsW_NtNtNtCs2W9OV9R0Aa1_5alloc11collections5btree4nodeINtB6_6HandleINtB6_7NodeRefNtNtB6_6marker3MuttNtNtNtCse8JQZBARWTK_9ax_driver6virtio3net10RxInflightNtB1n_8InternalENtB1n_2KVE5splitNtNtBc_5alloc6GlobalEB1K_+0x128 (20 samples, 0.45%)_RINvMs_NtCsjoxaZGNdFP9_7ax_task10wait_queueNtB5_9WaitQueue10wait_untilNCNvMs2_NtCs2x05nxSvmHt_7ax_sync5mutexNtB1e_8RawMutex18lock_after_prepare0ECs41CxRoq78v7_10ax_display+0x45a (132 samples, 2.96%)_RINvMs_Nt.._RINvMs_NtCsjoxaZGNdFP9_7ax_task10wait_queueNtB5_9WaitQueue10wait_untilNCNvMs2_NtCs2x05nxSvmHt_7ax_sync5mutexNtB1e_8RawMutex18lock_after_prepare0ECs41CxRoq78v7_10ax_display+0x460 (22 samples, 0.49%)_RINvMs_NtCsjoxaZGNdFP9_7ax_task10wait_queueNtB5_9WaitQueue10wait_untilNCNvMs2_NtCs2x05nxSvmHt_7ax_sync5mutexNtB1e_8RawMutex18lock_after_prepare0ECs41CxRoq78v7_10ax_display+0x466 (123 samples, 2.76%)_RINvMs_N.._RINvMs_NtCsjoxaZGNdFP9_7ax_task10wait_queueNtB5_9WaitQueue10wait_untilNCNvMs2_NtCs2x05nxSvmHt_7ax_sync5mutexNtB1e_8RawMutex18lock_after_prepare0ECs41CxRoq78v7_10ax_display+0x482 (18 samples, 0.40%)_RNSNvYNCNvMs1_NtNtNtNtNtCsbgXMhWHegTz_13starry_kernel8pseudofs3dev3tty8terminal5ldiscINtBc_14LineDisciplineNtNtBg_4ntty7ConsoleB1H_E20spawn_polling_reader0INtNtNtCsgiRWr7r9Nzy_4core3ops8function6FnOnceuE9call_once6vtableBm_+0x108 (22 samples, 0.49%)_RNSNvYNCNvMs1_NtNtNtNtNtCsbgXMhWHegTz_13starry_kernel8pseudofs3dev3tty8terminal5ldiscINtBc_14LineDisciplineNtNtBg_4ntty7ConsoleB1H_E20spawn_polling_reader0INtNtNtCsgiRWr7r9Nzy_4core3ops8function6FnOnceuE9call_once6vtableBm_+0x11a (28 samples, 0.63%)_RNSNvYNCNvMs1_NtNtNtNtNtCsbgXMhWHegTz_13starry_kernel8pseudofs3dev3tty8terminal5ldiscINtBc_14LineDisciplineNtNtBg_4ntty7ConsoleB1H_E20spawn_polling_reader0INtNtNtCsgiRWr7r9Nzy_4core3ops8function6FnOnceuE9call_once6vtableBm_+0x134 (19 samples, 0.43%)_RNSNvYNCNvMs1_NtNtNtNtNtCsbgXMhWHegTz_13starry_kernel8pseudofs3dev3tty8terminal5ldiscINtBc_14LineDisciplineNtNtBg_4ntty7ConsoleB1H_E20spawn_polling_reader0INtNtNtCsgiRWr7r9Nzy_4core3ops8function6FnOnceuE9call_once6vtableBm_+0x150 (19 samples, 0.43%)_RNSNvYNCNvMs1_NtNtNtNtNtCsbgXMhWHegTz_13starry_kernel8pseudofs3dev3tty8terminal5ldiscINtBc_14LineDisciplineNtNtBg_4ntty7ConsoleB1H_E20spawn_polling_reader0INtNtNtCsgiRWr7r9Nzy_4core3ops8function6FnOnceuE9call_once6vtableBm_+0x162 (30 samples, 0.67%)_RNSNvYNCNvMs1_NtNtNtNtNtCsbgXMhWHegTz_13starry_kernel8pseudofs3dev3tty8terminal5ldiscINtBc_14LineDisciplineNtNtBg_4ntty7ConsoleB1H_E20spawn_polling_reader0INtNtNtCsgiRWr7r9Nzy_4core3ops8function6FnOnceuE9call_once6vtableBm_+0x166 (32 samples, 0.72%)_RNSNvYNCNvMs1_NtNtNtNtNtCsbgXMhWHegTz_13starry_kernel8pseudofs3dev3tty8terminal5ldiscINtBc_14LineDisciplineNtNtBg_4ntty7ConsoleB1H_E20spawn_polling_reader0INtNtNtCsgiRWr7r9Nzy_4core3ops8function6FnOnceuE9call_once6vtableBm_+0x174 (30 samples, 0.67%)_RNSNvYNCNvMs1_NtNtNtNtNtCsbgXMhWHegTz_13starry_kernel8pseudofs3dev3tty8terminal5ldiscINtBc_14LineDisciplineNtNtBg_4ntty7ConsoleB1H_E20spawn_polling_reader0INtNtNtCsgiRWr7r9Nzy_4core3ops8function6FnOnceuE9call_once6vtableBm_+0x182 (18 samples, 0.40%)_RNSNvYNCNvMs1_NtNtNtNtNtCsbgXMhWHegTz_13starry_kernel8pseudofs3dev3tty8terminal5ldiscINtBc_14LineDisciplineNtNtBg_4ntty7ConsoleB1H_E20spawn_polling_reader0INtNtNtCsgiRWr7r9Nzy_4core3ops8function6FnOnceuE9call_once6vtableBm_+0x18a (21 samples, 0.47%)_RNSNvYNCNvMs1_NtNtNtNtNtCsbgXMhWHegTz_13starry_kernel8pseudofs3dev3tty8terminal5ldiscINtBc_14LineDisciplineNtNtBg_4ntty7ConsoleB1H_E20spawn_polling_reader0INtNtNtCsgiRWr7r9Nzy_4core3ops8function6FnOnceuE9call_once6vtableBm_+0x1c4 (18 samples, 0.40%)_RNSNvYNCNvMs1_NtNtNtNtNtCsbgXMhWHegTz_13starry_kernel8pseudofs3dev3tty8terminal5ldiscINtBc_14LineDisciplineNtNtBg_4ntty7ConsoleB1H_E20spawn_polling_reader0INtNtNtCsgiRWr7r9Nzy_4core3ops8function6FnOnceuE9call_once6vtableBm_+0x5c (23 samples, 0.52%)_RNSNvYNCNvMs1_NtNtNtNtNtCsbgXMhWHegTz_13starry_kernel8pseudofs3dev3tty8terminal5ldiscINtBc_14LineDisciplineNtNtBg_4ntty7ConsoleB1H_E20spawn_polling_reader0INtNtNtCsgiRWr7r9Nzy_4core3ops8function6FnOnceuE9call_once6vtableBm_+0x890 (28 samples, 0.63%)_RNSNvYNCNvMs1_NtNtNtNtNtCsbgXMhWHegTz_13starry_kernel8pseudofs3dev3tty8terminal5ldiscINtBc_14LineDisciplineNtNtBg_4ntty7ConsoleB1H_E20spawn_polling_reader0INtNtNtCsgiRWr7r9Nzy_4core3ops8function6FnOnceuE9call_once6vtableBm_+0x8a8 (22 samples, 0.49%)_RNSNvYNCNvMs1_NtNtNtNtNtCsbgXMhWHegTz_13starry_kernel8pseudofs3dev3tty8terminal5ldiscINtBc_14LineDisciplineNtNtBg_4ntty7ConsoleB1H_E20spawn_polling_reader0INtNtNtCsgiRWr7r9Nzy_4core3ops8function6FnOnceuE9call_once6vtableBm_+0x8c8 (17 samples, 0.38%)_RNSNvYNCNvMs1_NtNtNtNtNtCsbgXMhWHegTz_13starry_kernel8pseudofs3dev3tty8terminal5ldiscINtBc_14LineDisciplineNtNtBg_4ntty7ConsoleB1H_E20spawn_polling_reader0INtNtNtCsgiRWr7r9Nzy_4core3ops8function6FnOnceuE9call_once6vtableBm_+0x8e (25 samples, 0.56%)_RNSNvYNCNvMs1_NtNtNtNtNtCsbgXMhWHegTz_13starry_kernel8pseudofs3dev3tty8terminal5ldiscINtBc_14LineDisciplineNtNtBg_4ntty7ConsoleB1H_E20spawn_polling_reader0INtNtNtCsgiRWr7r9Nzy_4core3ops8function6FnOnceuE9call_once6vtableBm_+0x8e0 (20 samples, 0.45%)_RNSNvYNCNvMs1_NtNtNtNtNtCsbgXMhWHegTz_13starry_kernel8pseudofs3dev3tty8terminal5ldiscINtBc_14LineDisciplineNtNtBg_4ntty7ConsoleB1H_E20spawn_polling_reader0INtNtNtCsgiRWr7r9Nzy_4core3ops8function6FnOnceuE9call_once6vtableBm_+0xbe (33 samples, 0.74%)_.._RNSNvYNCNvMs1_NtNtNtNtNtCsbgXMhWHegTz_13starry_kernel8pseudofs3dev3tty8terminal5ldiscINtBc_14LineDisciplineNtNtBg_4ntty7ConsoleB1H_E20spawn_polling_reader0INtNtNtCsgiRWr7r9Nzy_4core3ops8function6FnOnceuE9call_once6vtableBm_+0xfa (22 samples, 0.49%)_RNvCs41CxRoq78v7_10ax_display17framebuffer_flush+0x18 (20 samples, 0.45%)_RNvMs0_Cse38cudTX6ZT_11ax_lazyinitINtB5_8LazyInitINtNtCs4iPnrq9U4Rv_8lock_api5mutex5MutexNtNtCs2x05nxSvmHt_7ax_sync5mutex8RawMutexNtNtCs41CxRoq78v7_10ax_display6device19ErasedDisplayDeviceEE13panic_messageB28_+0x10 (21 samples, 0.47%)_RNvMs10_NtNtNtCs2W9OV9R0Aa1_5alloc11collections5btree4nodeINtB6_16BalancingContexttNtNtNtCse8JQZBARWTK_9ax_driver6virtio3net10RxInflightE15bulk_steal_leftB1p_+0x1a6 (19 samples, 0.43%)_RNvMs10_NtNtNtCs2W9OV9R0Aa1_5alloc11collections5btree4nodeINtB6_16BalancingContexttNtNtNtCse8JQZBARWTK_9ax_driver6virtio3net10RxInflightE15bulk_steal_leftB1p_+0x1c8 (29 samples, 0.65%)_RNvMs1_NtCsjoxaZGNdFP9_7ax_task9run_queueINtB5_18CurrentRunQueueRefNtCs9J4N2FZfJib_15ax_kernel_guard16NoPreemptIrqSaveE13yield_currentB7_ (27 samples, 0.61%)_RNvMs1_NtCsjoxaZGNdFP9_7ax_task9run_queueINtB5_18CurrentRunQueueRefNtCs9J4N2FZfJib_15ax_kernel_guard16NoPreemptIrqSaveE13yield_currentB7_+0x116 (20 samples, 0.45%)_RNvMs1_NtCsjoxaZGNdFP9_7ax_task9run_queueINtB5_18CurrentRunQueueRefNtCs9J4N2FZfJib_15ax_kernel_guard16NoPreemptIrqSaveE13yield_currentB7_+0x12a (24 samples, 0.54%)_RNvMs1_NtCsjoxaZGNdFP9_7ax_task9run_queueINtB5_18CurrentRunQueueRefNtCs9J4N2FZfJib_15ax_kernel_guard16NoPreemptIrqSaveE13yield_currentB7_+0x148 (16 samples, 0.36%)_RNvMs1_NtCsjoxaZGNdFP9_7ax_task9run_queueINtB5_18CurrentRunQueueRefNtCs9J4N2FZfJib_15ax_kernel_guard16NoPreemptIrqSaveE13yield_currentB7_+0x176 (18 samples, 0.40%)_RNvMs1_NtCsjoxaZGNdFP9_7ax_task9run_queueINtB5_18CurrentRunQueueRefNtCs9J4N2FZfJib_15ax_kernel_guard16NoPreemptIrqSaveE13yield_currentB7_+0x17a (22 samples, 0.49%)_RNvMs1_NtCsjoxaZGNdFP9_7ax_task9run_queueINtB5_18CurrentRunQueueRefNtCs9J4N2FZfJib_15ax_kernel_guard16NoPreemptIrqSaveE13yield_currentB7_+0x186 (26 samples, 0.58%)_RNvMs1_NtCsjoxaZGNdFP9_7ax_task9run_queueINtB5_18CurrentRunQueueRefNtCs9J4N2FZfJib_15ax_kernel_guard16NoPreemptIrqSaveE13yield_currentB7_+0x1a0 (18 samples, 0.40%)_RNvMs1_NtCsjoxaZGNdFP9_7ax_task9run_queueINtB5_18CurrentRunQueueRefNtCs9J4N2FZfJib_15ax_kernel_guard16NoPreemptIrqSaveE13yield_currentB7_+0x1e4 (21 samples, 0.47%)_RNvMs1_NtCsjoxaZGNdFP9_7ax_task9run_queueINtB5_18CurrentRunQueueRefNtCs9J4N2FZfJib_15ax_kernel_guard16NoPreemptIrqSaveE13yield_currentB7_+0x254 (16 samples, 0.36%)_RNvMs1_NtCsjoxaZGNdFP9_7ax_task9run_queueINtB5_18CurrentRunQueueRefNtCs9J4N2FZfJib_15ax_kernel_guard16NoPreemptIrqSaveE13yield_currentB7_+0x2e4 (27 samples, 0.61%)_RNvMs1_NtCsjoxaZGNdFP9_7ax_task9run_queueINtB5_18CurrentRunQueueRefNtCs9J4N2FZfJib_15ax_kernel_guard16NoPreemptIrqSaveE13yield_currentB7_+0xec (18 samples, 0.40%)_RNvMs1_NtCsjoxaZGNdFP9_7ax_task9run_queueINtB5_18CurrentRunQueueRefNtCs9J4N2FZfJib_15ax_kernel_guard16NoPreemptIrqSaveE13yield_currentB7_+0xf6 (26 samples, 0.58%)_RNvMs2_NtCsjMNVNv9nEZt_8ax_alloc10buddy_slabNtB5_15GlobalAllocator11alloc_pages+0x80 (35 samples, 0.79%)_.._RNvMs2_NtCsjMNVNv9nEZt_8ax_alloc10buddy_slabNtB5_15GlobalAllocator11alloc_pages+0xd6 (17 samples, 0.38%)_RNvMs2_NtCsjMNVNv9nEZt_8ax_alloc10buddy_slabNtB5_15GlobalAllocator11alloc_pages+0xdc (21 samples, 0.47%)_RNvMs2_NtCsjMNVNv9nEZt_8ax_alloc10buddy_slabNtB5_15GlobalAllocator11alloc_pages+0xf2 (20 samples, 0.45%)_RNvMs2_NtCsjMNVNv9nEZt_8ax_alloc10buddy_slabNtB5_15GlobalAllocator11alloc_pages+0xf8 (16 samples, 0.36%)_RNvMs2_NtCsjoxaZGNdFP9_7ax_task9run_queueNtB5_10AxRunQueue7resched (25 samples, 0.56%)_RNvMs2_NtCsjoxaZGNdFP9_7ax_task9run_queueNtB5_10AxRunQueue7resched+0x18 (18 samples, 0.40%)_RNvMs2_NtCsjoxaZGNdFP9_7ax_task9run_queueNtB5_10AxRunQueue7resched+0x2a (18 samples, 0.40%)_RNvMs2_NtCsjoxaZGNdFP9_7ax_task9run_queueNtB5_10AxRunQueue7resched+0xa8 (27 samples, 0.61%)_RNvMs2_NtCsjoxaZGNdFP9_7ax_task9run_queueNtB5_10AxRunQueue7resched+0xae (22 samples, 0.49%)_RNvMs2_NtCsjoxaZGNdFP9_7ax_task9run_queueNtB5_10AxRunQueue7resched+0xb2 (37 samples, 0.83%)_.._RNvMs2_NtCsjoxaZGNdFP9_7ax_task9run_queueNtB5_10AxRunQueue7resched+0xd2 (40 samples, 0.90%)_.._RNvMs2_NtCsjoxaZGNdFP9_7ax_task9run_queueNtB5_10AxRunQueue9switch_to (25 samples, 0.56%)_RNvMs2_NtCsjoxaZGNdFP9_7ax_task9run_queueNtB5_10AxRunQueue9switch_to+0x128 (22 samples, 0.49%)_RNvMs2_NtCsjoxaZGNdFP9_7ax_task9run_queueNtB5_10AxRunQueue9switch_to+0x1e (31 samples, 0.70%)_RNvMs2_NtCsjoxaZGNdFP9_7ax_task9run_queueNtB5_10AxRunQueue9switch_to+0x21c (24 samples, 0.54%)_RNvMs2_NtCsjoxaZGNdFP9_7ax_task9run_queueNtB5_10AxRunQueue9switch_to+0x43e (18 samples, 0.40%)_RNvMs3_NtCs2W9OV9R0Aa1_5alloc3stre12to_uppercase+0x434 (23 samples, 0.52%)_RNvMs3_NtCs2W9OV9R0Aa1_5alloc3stre12to_uppercase+0x440 (29 samples, 0.65%)_RNvMs3_NtCs2W9OV9R0Aa1_5alloc3stre12to_uppercase+0x44a (23 samples, 0.52%)_RNvMs3_NtCsjoxaZGNdFP9_7ax_task4taskNtB5_9TaskInner29current_check_preempt_pending (45 samples, 1.01%)_R.._RNvMs3_NtCsjoxaZGNdFP9_7ax_task4taskNtB5_9TaskInner29current_check_preempt_pending+0x18 (54 samples, 1.21%)_RN.._RNvMs3_NtCsjoxaZGNdFP9_7ax_task4taskNtB5_9TaskInner29current_check_preempt_pending+0x38 (61 samples, 1.37%)_RN.._RNvMs3_NtCsjoxaZGNdFP9_7ax_task4taskNtB5_9TaskInner29current_check_preempt_pending+0x3c (34 samples, 0.76%)_.._RNvMs3_NtCsjoxaZGNdFP9_7ax_task4taskNtB5_9TaskInner29current_check_preempt_pending+0x4e (26 samples, 0.58%)_RNvNtCs9OcUSfjU0zs_17compiler_builtins3mem6memcpy+0x10c (70 samples, 1.57%)_RNv.._RNvNtCs9OcUSfjU0zs_17compiler_builtins3mem6memcpy+0x4a (124 samples, 2.78%)_RNvNtCs9.._RNvNtCs9OcUSfjU0zs_17compiler_builtins3mem7memmove+0x2a4 (36 samples, 0.81%)_.._RNvNtCsjoxaZGNdFP9_7ax_task3api9yield_now (26 samples, 0.58%)_RNvNtCsjoxaZGNdFP9_7ax_task3api9yield_now+0x14 (26 samples, 0.58%)_RNvNtCsjoxaZGNdFP9_7ax_task3api9yield_now+0x34 (33 samples, 0.74%)_.._RNvNtCsjoxaZGNdFP9_7ax_task3api9yield_now+0x3e (18 samples, 0.40%)_RNvNtCsjoxaZGNdFP9_7ax_task3api9yield_now+0x42 (28 samples, 0.63%)_RNvNtCsjoxaZGNdFP9_7ax_task3api9yield_now+0x50 (23 samples, 0.52%)_RNvNtCsjoxaZGNdFP9_7ax_task3api9yield_now+0x60 (35 samples, 0.79%)_.._RNvNtCsjoxaZGNdFP9_7ax_task3api9yield_now+0x7e (17 samples, 0.38%)_RNvNtCsjoxaZGNdFP9_7ax_task3api9yield_now+0x82 (51 samples, 1.15%)_R.._RNvNtCsjoxaZGNdFP9_7ax_task3api9yield_now+0x92 (18 samples, 0.40%)_RNvNtCsjoxaZGNdFP9_7ax_task3api9yield_now+0xa8 (24 samples, 0.54%)_RNvNtCsjoxaZGNdFP9_7ax_task3api9yield_now+0xac (21 samples, 0.47%)_RNvNtCsjoxaZGNdFP9_7ax_task3api9yield_now+0xb0 (20 samples, 0.45%)_RNvNtCsjoxaZGNdFP9_7ax_task3api9yield_now+0xbe (25 samples, 0.56%)_RNvNtCsjoxaZGNdFP9_7ax_task3api9yield_now+0xc (21 samples, 0.47%)_RNvNtCsjoxaZGNdFP9_7ax_task3api9yield_now+0xd0 (20 samples, 0.45%)_RNvNtNtCse8JQZBARWTK_9ax_driver3pci3fdt18probe_generic_ecam+0x680 (18 samples, 0.40%)_RNvNtNtCse8JQZBARWTK_9ax_driver3pci3fdt18probe_generic_ecam+0x6c0 (20 samples, 0.45%)_RNvNtNtCse8JQZBARWTK_9ax_driver3pci3fdt18probe_generic_ecam+0x6e2 (18 samples, 0.40%)_RNvNtNtCse8JQZBARWTK_9ax_driver3pci3fdt18probe_generic_ecam+0x70c (18 samples, 0.40%)_RNvNtNtCse8JQZBARWTK_9ax_driver3pci3fdt18probe_generic_ecam+0x710 (159 samples, 3.57%)_RNvNtNtCse8.._RNvXs9_NtNtCse8JQZBARWTK_9ax_driver6virtio3netINtB5_10NetRxQueueNtNtNtCsa9GpAcvErGs_14virtio_drivers9transport3pci12PciTransportENtCsfcOzc4h9Az9_8rdif_eth8IRxQueue6submitB9_+0x232 (32 samples, 0.72%)_head+0x11a2 (32 samples, 0.72%)_head+0x4f8 (63 samples, 1.41%)_he.._head+0x4fc (32 samples, 0.72%)_head+0x504 (30 samples, 0.67%)_head+0x534 (34 samples, 0.76%)_.._head+0x538 (27 samples, 0.61%)_head+0x53e (19 samples, 0.43%)_head+0x582 (40 samples, 0.90%)_.._head+0x588 (21 samples, 0.47%)_head+0x58e (27 samples, 0.61%)_head+0x594 (26 samples, 0.58%)_head+0x5ae (23 samples, 0.52%)_head+0x5b6 (38 samples, 0.85%)_.._head+0x624 (37 samples, 0.83%)_.._head+0x62c (32 samples, 0.72%)all (4,454 samples, 100%) \ No newline at end of file diff --git a/docs/flamegraphs/target__qperf__virtio-blk-original__flamegraph.svg b/docs/flamegraphs/target__qperf__virtio-blk-original__flamegraph.svg new file mode 100644 index 0000000000..6b6dbfed93 --- /dev/null +++ b/docs/flamegraphs/target__qperf__virtio-blk-original__flamegraph.svg @@ -0,0 +1,491 @@ +Flame Graph Reset ZoomSearch 0xffffffc080220b20 (48 samples, 0.03%)0xffffffc080220b22 (26 samples, 0.01%)0xffffffc080220b24 (36 samples, 0.02%)0xffffffc080220b26 (36 samples, 0.02%)0xffffffc080220b28 (38 samples, 0.02%)0xffffffc080220b2a (41 samples, 0.02%)0xffffffc080220b2c (36 samples, 0.02%)0xffffffc080220b2e (34 samples, 0.02%)0xffffffc080220b30 (42 samples, 0.02%)0xffffffc080220b32 (38 samples, 0.02%)0xffffffc080220b34 (43 samples, 0.02%)0xffffffc080220b38 (45 samples, 0.03%)0xffffffc080220b3c (41 samples, 0.02%)0xffffffc080220b3e (30 samples, 0.02%)0xffffffc080220b80 (30 samples, 0.02%)0xffffffc080220b84 (31 samples, 0.02%)0xffffffc080220b9c (30 samples, 0.02%)0xffffffc080220ba0 (32 samples, 0.02%)0xffffffc080220ba2 (43 samples, 0.02%)0xffffffc080220ba4 (47 samples, 0.03%)0xffffffc080220ba8 (46 samples, 0.03%)0xffffffc080220baa (36 samples, 0.02%)0xffffffc080220bae (30 samples, 0.02%)0xffffffc080220bb0 (24 samples, 0.01%)0xffffffc080220bb2 (45 samples, 0.03%)0xffffffc080220bb4 (47 samples, 0.03%)0xffffffc080220bb8 (42 samples, 0.02%)0xffffffc080220bbc (40 samples, 0.02%)0xffffffc080220bbe (44 samples, 0.02%)0xffffffc08024efde (43 samples, 0.02%)0xffffffc08024efe0 (26 samples, 0.01%)0xffffffc08024efe2 (34 samples, 0.02%)0xffffffc08024efe4 (32 samples, 0.02%)0xffffffc08024efe8 (26 samples, 0.01%)0xffffffc08024efec (62 samples, 0.03%)0xffffffc08024efee (26 samples, 0.01%)0xffffffc08024eff0 (36 samples, 0.02%)0xffffffc08024eff2 (36 samples, 0.02%)0xffffffc08024eff8 (26 samples, 0.01%)0xffffffc08024effc (27 samples, 0.02%)0xffffffc08024effe (35 samples, 0.02%)0x109b (1,622 samples, 0.91%)0x15cf1 (28 samples, 0.02%)0xffffffc0803a7634 (42 samples, 0.02%)0xffffffc0803a7636 (48 samples, 0.03%)0xffffffc0803a763a (52 samples, 0.03%)0xffffffc0803a763c (43 samples, 0.02%)0x204f (227 samples, 0.13%)0xffffffc0803a763e (41 samples, 0.02%)0xfff (119 samples, 0.07%)0xffffffc080201000 (700 samples, 0.39%)0xffffffc080201144 (37 samples, 0.02%)0xffffffc080201146 (18 samples, 0.01%)0xffffffc080201148 (34 samples, 0.02%)0xffffffc08020114c (29 samples, 0.02%)0xffffffc080201150 (31 samples, 0.02%)0xffffffc080201154 (26 samples, 0.01%)0xffffffc080201158 (33 samples, 0.02%)0xffffffc08020115c (35 samples, 0.02%)0xffffffc080201160 (29 samples, 0.02%)0xffffffc080201164 (33 samples, 0.02%)0xffffffc080201168 (26 samples, 0.01%)0xffffffc08020116c (37 samples, 0.02%)0xffffffc080201170 (34 samples, 0.02%)0xffffffc080201174 (34 samples, 0.02%)0xffffffc080201178 (31 samples, 0.02%)0xffffffc08020117c (35 samples, 0.02%)0xffffffc080201180 (28 samples, 0.02%)0xffffffc080201184 (32 samples, 0.02%)0xffffffc080204344 (93 samples, 0.05%)0xffffffc080204346 (36 samples, 0.02%)0xffffffc080204348 (40 samples, 0.02%)0xffffffc08020434a (39 samples, 0.02%)0xffffffc08020434c (28 samples, 0.02%)0xffffffc08020434e (33 samples, 0.02%)0xffffffc080204350 (36 samples, 0.02%)0xffffffc080204352 (36 samples, 0.02%)0xffffffc080204354 (34 samples, 0.02%)0xffffffc080204356 (37 samples, 0.02%)0xffffffc080204358 (38 samples, 0.02%)0xffffffc08020435a (33 samples, 0.02%)0xffffffc08020435c (37 samples, 0.02%)0xffffffc08020435e (36 samples, 0.02%)0xffffffc080204360 (42 samples, 0.02%)0xffffffc080204362 (27 samples, 0.02%)0xffffffc080204366 (123 samples, 0.07%)0xffffffc08020436a (21 samples, 0.01%)0xffffffc08020436c (24 samples, 0.01%)0xffffffc080204370 (38 samples, 0.02%)0xffffffc080204372 (25 samples, 0.01%)0xffffffc080204376 (95 samples, 0.05%)0xffffffc080204378 (31 samples, 0.02%)0xffffffc08020437a (30 samples, 0.02%)0xffffffc08020437e (35 samples, 0.02%)0xffffffc080204380 (42 samples, 0.02%)0xffffffc080204384 (35 samples, 0.02%)0xffffffc080204388 (97 samples, 0.05%)0xffffffc08020438c (34 samples, 0.02%)0xffffffc080204390 (33 samples, 0.02%)0xffffffc080204394 (31 samples, 0.02%)0xffffffc080204396 (32 samples, 0.02%)0xffffffc08020439a (43 samples, 0.02%)0xffffffc08020439e (27 samples, 0.02%)0xffffffc0802043a0 (37 samples, 0.02%)0xffffffc0802043b2 (43 samples, 0.02%)0xffffffc0802043b4 (34 samples, 0.02%)0xffffffc0802043b6 (42 samples, 0.02%)0xffffffc0802043ba (34 samples, 0.02%)0xffffffc0802043bc (43 samples, 0.02%)0xffffffc0802043c0 (33 samples, 0.02%)0xffffffc0802043c4 (34 samples, 0.02%)0xffffffc0802043c8 (43 samples, 0.02%)0xffffffc0802043cc (39 samples, 0.02%)0xffffffc0802043d0 (29 samples, 0.02%)0xffffffc0802043d4 (27 samples, 0.02%)0xffffffc0802043d8 (37 samples, 0.02%)0xffffffc0802043dc (38 samples, 0.02%)0xffffffc0802043e0 (36 samples, 0.02%)0xffffffc0802043e4 (50 samples, 0.03%)0xffffffc0802043e8 (19 samples, 0.01%)0xffffffc0802043ec (36 samples, 0.02%)0xffffffc0802043ee (42 samples, 0.02%)0xffffffc0802043f2 (37 samples, 0.02%)0xffffffc0802043f4 (39 samples, 0.02%)0xffffffc0802043f8 (32 samples, 0.02%)0xffffffc0802043fa (27 samples, 0.02%)0xffffffc0802043fe (35 samples, 0.02%)0xffffffc080204400 (35 samples, 0.02%)0xffffffc080204404 (23 samples, 0.01%)0xffffffc080204408 (30 samples, 0.02%)0xffffffc08020440c (39 samples, 0.02%)0xffffffc08020440e (26 samples, 0.01%)0xffffffc080204412 (36 samples, 0.02%)0xffffffc080204414 (30 samples, 0.02%)0xffffffc080204418 (22 samples, 0.01%)0xffffffc08020441a (34 samples, 0.02%)0xffffffc08020441e (38 samples, 0.02%)0xffffffc080204420 (31 samples, 0.02%)0xffffffc080204424 (29 samples, 0.02%)0xffffffc080204428 (41 samples, 0.02%)0xffffffc08020442a (34 samples, 0.02%)0xffffffc08020442c (51 samples, 0.03%)0xffffffc080204430 (38 samples, 0.02%)0xffffffc080204432 (31 samples, 0.02%)0xffffffc080204434 (22 samples, 0.01%)0xffffffc080204436 (28 samples, 0.02%)0xffffffc08020443a (33 samples, 0.02%)0xffffffc08020443c (39 samples, 0.02%)0xffffffc08020443e (32 samples, 0.02%)0xffffffc080204442 (29 samples, 0.02%)0xffffffc080204444 (42 samples, 0.02%)0xffffffc080204446 (37 samples, 0.02%)0xffffffc08020444a (30 samples, 0.02%)0xffffffc08020444c (26 samples, 0.01%)0xffffffc08020444e (33 samples, 0.02%)0xffffffc080204452 (31 samples, 0.02%)0xffffffc080204454 (33 samples, 0.02%)0xffffffc080204456 (28 samples, 0.02%)0xffffffc08020445a (27 samples, 0.02%)0xffffffc080204460 (45 samples, 0.03%)0xffffffc080204464 (27 samples, 0.02%)0xffffffc080204468 (46 samples, 0.03%)0xffffffc08020446c (31 samples, 0.02%)0xffffffc080204470 (39 samples, 0.02%)0xffffffc080204474 (33 samples, 0.02%)0xffffffc080204478 (35 samples, 0.02%)0xffffffc08020447c (30 samples, 0.02%)0xffffffc080204480 (32 samples, 0.02%)0xffffffc080204484 (38 samples, 0.02%)0xffffffc080204488 (37 samples, 0.02%)0xffffffc08020448c (34 samples, 0.02%)0xffffffc080204490 (22 samples, 0.01%)0xffffffc080204494 (27 samples, 0.02%)0xffffffc08020449c (36 samples, 0.02%)0xffffffc08020449e (40 samples, 0.02%)0xffffffc0802044a2 (36 samples, 0.02%)0xffffffc0802044a4 (30 samples, 0.02%)0xffffffc0802044a8 (21 samples, 0.01%)0xffffffc0802044ac (39 samples, 0.02%)0xffffffc0802044b0 (25 samples, 0.01%)0xffffffc0802044b4 (35 samples, 0.02%)0xffffffc0802044b8 (30 samples, 0.02%)0xffffffc0802044ba (38 samples, 0.02%)0xffffffc0802044be (26 samples, 0.01%)0xffffffc0802044c2 (27 samples, 0.02%)0xffffffc0802044c6 (28 samples, 0.02%)0xffffffc0802044ca (24 samples, 0.01%)0xffffffc0802044ce (35 samples, 0.02%)0xffffffc0802044d2 (40 samples, 0.02%)0xffffffc0802044d6 (37 samples, 0.02%)0xffffffc0802044d8 (27 samples, 0.02%)0xffffffc0802044da (41 samples, 0.02%)0xffffffc0802044dc (39 samples, 0.02%)0xffffffc0802044de (28 samples, 0.02%)0xffffffc0802044e2 (36 samples, 0.02%)0xffffffc0802044e4 (18 samples, 0.01%)0xffffffc0802044e6 (34 samples, 0.02%)0xffffffc0802044ea (27 samples, 0.02%)0xffffffc0802044ee (32 samples, 0.02%)0xffffffc0802044f2 (33 samples, 0.02%)0xffffffc0802044f6 (38 samples, 0.02%)0xffffffc0802044fa (33 samples, 0.02%)0xffffffc080204502 (29 samples, 0.02%)0xffffffc080204506 (35 samples, 0.02%)0xffffffc08020450a (35 samples, 0.02%)0xffffffc08020450e (31 samples, 0.02%)0xffffffc080204512 (30 samples, 0.02%)0xffffffc080204516 (40 samples, 0.02%)0xffffffc08020451a (22 samples, 0.01%)0xffffffc08020451e (36 samples, 0.02%)0xffffffc080204522 (37 samples, 0.02%)0xffffffc080204524 (30 samples, 0.02%)0xffffffc080204528 (33 samples, 0.02%)0xffffffc08020452a (41 samples, 0.02%)0xffffffc08020452e (22 samples, 0.01%)0xffffffc080204530 (27 samples, 0.02%)0xffffffc080204534 (26 samples, 0.01%)0xffffffc080204536 (30 samples, 0.02%)0xffffffc08020453a (28 samples, 0.02%)0xffffffc08020453c (30 samples, 0.02%)0xffffffc08020453e (39 samples, 0.02%)0xffffffc080204542 (31 samples, 0.02%)0xffffffc080204544 (30 samples, 0.02%)0xffffffc080204548 (26 samples, 0.01%)0xffffffc08020454a (43 samples, 0.02%)0xffffffc08020454e (37 samples, 0.02%)0xffffffc080204550 (41 samples, 0.02%)0xffffffc080204554 (28 samples, 0.02%)0xffffffc080204558 (31 samples, 0.02%)0xffffffc08020455c (26 samples, 0.01%)0xffffffc080204560 (26 samples, 0.01%)0xffffffc080204564 (28 samples, 0.02%)0xffffffc080204566 (30 samples, 0.02%)0xffffffc080204568 (32 samples, 0.02%)0xffffffc08020456c (36 samples, 0.02%)0xffffffc08020456e (32 samples, 0.02%)0xffffffc080204570 (24 samples, 0.01%)0xffffffc080204574 (33 samples, 0.02%)0xffffffc08020458c (36 samples, 0.02%)0xffffffc08020463c (23 samples, 0.01%)0xffffffc0802046e6 (27 samples, 0.02%)0xffffffc0802046ea (20 samples, 0.01%)0xffffffc0802046ec (20 samples, 0.01%)0xffffffc080204c1a (25 samples, 0.01%)0xffffffc0802051b2 (33 samples, 0.02%)0xffffffc0802051b4 (94 samples, 0.05%)0xffffffc0802051ba (20 samples, 0.01%)0xffffffc0802051bc (20 samples, 0.01%)0xffffffc0802051be (19 samples, 0.01%)0xffffffc0802051c0 (21 samples, 0.01%)0xffffffc080205f0a (44 samples, 0.02%)0xffffffc080205f0e (92 samples, 0.05%)0xffffffc080205f12 (32 samples, 0.02%)0xffffffc080205f14 (33 samples, 0.02%)0xffffffc080205f18 (36 samples, 0.02%)0xffffffc080205f1a (34 samples, 0.02%)0xffffffc080205f1e (76 samples, 0.04%)0xffffffc080205f20 (38 samples, 0.02%)0xffffffc080205f24 (25 samples, 0.01%)0xffffffc080205f26 (33 samples, 0.02%)0xffffffc080205f2a (32 samples, 0.02%)0xffffffc080205f2e (106 samples, 0.06%)0xffffffc080205f32 (32 samples, 0.02%)0xffffffc080205f36 (24 samples, 0.01%)0xffffffc080205f38 (30 samples, 0.02%)0xffffffc080205f3a (34 samples, 0.02%)0xffffffc080205f3c (31 samples, 0.02%)0xffffffc080205f40 (46 samples, 0.03%)0xffffffc080205f44 (34 samples, 0.02%)0xffffffc080205f46 (31 samples, 0.02%)0xffffffc080205f66 (23 samples, 0.01%)0xffffffc080205f68 (35 samples, 0.02%)0xffffffc080205f6c (33 samples, 0.02%)0xffffffc080205f6e (25 samples, 0.01%)0xffffffc080205f72 (39 samples, 0.02%)0xffffffc080205f76 (29 samples, 0.02%)0xffffffc080205f7a (31 samples, 0.02%)0xffffffc080205f7e (78 samples, 0.04%)0xffffffc080205f82 (76 samples, 0.04%)0xffffffc080205f86 (28 samples, 0.02%)0xffffffc080205f88 (28 samples, 0.02%)0xffffffc080205f8c (34 samples, 0.02%)0xffffffc080205f8e (38 samples, 0.02%)0xffffffc080205f92 (77 samples, 0.04%)0xffffffc080205f94 (31 samples, 0.02%)0xffffffc080205f98 (29 samples, 0.02%)0xffffffc080205f9a (29 samples, 0.02%)0xffffffc080205f9e (37 samples, 0.02%)0xffffffc080205fa0 (23 samples, 0.01%)0xffffffc080205fb4 (31 samples, 0.02%)0xffffffc080205fb8 (25 samples, 0.01%)0xffffffc080205fbc (39 samples, 0.02%)0xffffffc080205fc0 (41 samples, 0.02%)0xffffffc080205fc4 (36 samples, 0.02%)0xffffffc080205fc8 (97 samples, 0.05%)0xffffffc080205fcc (84 samples, 0.05%)0xffffffc080205fd0 (25 samples, 0.01%)0xffffffc080205fd2 (34 samples, 0.02%)0xffffffc080205fd6 (36 samples, 0.02%)0xffffffc080205fd8 (32 samples, 0.02%)0xffffffc080205fdc (72 samples, 0.04%)0xffffffc080205fde (37 samples, 0.02%)0xffffffc080205fe2 (28 samples, 0.02%)0xffffffc080205fe4 (20 samples, 0.01%)0xffffffc080205fe8 (29 samples, 0.02%)0xffffffc080205fea (34 samples, 0.02%)0xffffffc080205ff6 (23 samples, 0.01%)0xffffffc080205ff8 (39 samples, 0.02%)0xffffffc080205ffa (44 samples, 0.02%)0xffffffc080205ffc (46 samples, 0.03%)0xffffffc080205ffe (31 samples, 0.02%)0xffffffc080206000 (51 samples, 0.03%)0xffffffc080206002 (35 samples, 0.02%)0xffffffc080206004 (36 samples, 0.02%)0xffffffc080206006 (28 samples, 0.02%)0xffffffc080206008 (27 samples, 0.02%)0xffffffc08020600a (29 samples, 0.02%)0xffffffc08020600c (41 samples, 0.02%)0xffffffc08020600e (27 samples, 0.02%)0xffffffc080206010 (46 samples, 0.03%)0xffffffc080206012 (25 samples, 0.01%)0xffffffc080206d0e (65 samples, 0.04%)0xffffffc080206d10 (26 samples, 0.01%)0xffffffc080206d12 (42 samples, 0.02%)0xffffffc080206d14 (29 samples, 0.02%)0xffffffc080206d16 (35 samples, 0.02%)0xffffffc080206d18 (36 samples, 0.02%)0xffffffc080206d1a (30 samples, 0.02%)0xffffffc080206d1e (103 samples, 0.06%)0xffffffc080206d22 (29 samples, 0.02%)0xffffffc080206d24 (39 samples, 0.02%)0xffffffc080206d28 (41 samples, 0.02%)0xffffffc080206d2a (28 samples, 0.02%)0xffffffc080206d2e (94 samples, 0.05%)0xffffffc080206d30 (40 samples, 0.02%)0xffffffc080206d34 (33 samples, 0.02%)0xffffffc080206d36 (29 samples, 0.02%)0xffffffc080206d3a (39 samples, 0.02%)0xffffffc080206d3e (79 samples, 0.04%)0xffffffc080206d42 (29 samples, 0.02%)0xffffffc080206d46 (31 samples, 0.02%)0xffffffc080206d4a (22 samples, 0.01%)0xffffffc080206d4e (40 samples, 0.02%)0xffffffc080206d50 (25 samples, 0.01%)0xffffffc080206d54 (39 samples, 0.02%)0xffffffc080206d56 (46 samples, 0.03%)0xffffffc080206d5a (38 samples, 0.02%)0xffffffc080206d5e (26 samples, 0.01%)0xffffffc080206d62 (31 samples, 0.02%)0xffffffc080206d82 (21 samples, 0.01%)0xffffffc080206d84 (37 samples, 0.02%)0xffffffc080206d88 (33 samples, 0.02%)0xffffffc080206d8a (37 samples, 0.02%)0xffffffc080206d8e (33 samples, 0.02%)0xffffffc080206d92 (44 samples, 0.02%)0xffffffc080206d96 (29 samples, 0.02%)0xffffffc080206d9a (95 samples, 0.05%)0xffffffc080206d9e (81 samples, 0.05%)0xffffffc080206da2 (26 samples, 0.01%)0xffffffc080206da4 (19 samples, 0.01%)0xffffffc080206da8 (33 samples, 0.02%)0xffffffc080206daa (24 samples, 0.01%)0xffffffc080206dae (88 samples, 0.05%)0xffffffc080206db0 (25 samples, 0.01%)0xffffffc080206db4 (46 samples, 0.03%)0xffffffc080206db6 (35 samples, 0.02%)0xffffffc080206dba (31 samples, 0.02%)0xffffffc080206dbc (37 samples, 0.02%)0xffffffc080206dd4 (31 samples, 0.02%)0xffffffc080206dd8 (75 samples, 0.04%)0xffffffc080206ddc (23 samples, 0.01%)0xffffffc080206dde (26 samples, 0.01%)0xffffffc080206de2 (33 samples, 0.02%)0xffffffc080206de4 (41 samples, 0.02%)0xffffffc080206de8 (100 samples, 0.06%)0xffffffc080206dea (29 samples, 0.02%)0xffffffc080206dee (31 samples, 0.02%)0xffffffc080206df0 (24 samples, 0.01%)0xffffffc080206df4 (29 samples, 0.02%)0xffffffc080206df8 (104 samples, 0.06%)0xffffffc080206dfc (37 samples, 0.02%)0xffffffc080206dfe (31 samples, 0.02%)0xffffffc080206e02 (42 samples, 0.02%)0xffffffc080206e06 (28 samples, 0.02%)0xffffffc080206e08 (31 samples, 0.02%)0xffffffc080206e1a (35 samples, 0.02%)0xffffffc080206e1c (34 samples, 0.02%)0xffffffc080206e20 (29 samples, 0.02%)0xffffffc080206e22 (37 samples, 0.02%)0xffffffc080206f16 (34 samples, 0.02%)0xffffffc080206f1a (31 samples, 0.02%)0xffffffc080206f1e (35 samples, 0.02%)0xffffffc080206f22 (33 samples, 0.02%)0xffffffc080206f2a (20 samples, 0.01%)0xffffffc080206f34 (19 samples, 0.01%)0xffffffc080206f3c (19 samples, 0.01%)0xffffffc080206faa (23 samples, 0.01%)0xffffffc080206fae (28 samples, 0.02%)0xffffffc080206fb2 (22 samples, 0.01%)0xffffffc080206fba (21 samples, 0.01%)0xffffffc080206fbc (18 samples, 0.01%)0xffffffc080206fbe (25 samples, 0.01%)0xffffffc080206fc2 (21 samples, 0.01%)0xffffffc080206fc4 (18 samples, 0.01%)0xffffffc080206fc6 (21 samples, 0.01%)0xffffffc080207028 (34 samples, 0.02%)0xffffffc080207030 (59 samples, 0.03%)0xffffffc080207034 (31 samples, 0.02%)0xffffffc080207038 (43 samples, 0.02%)0xffffffc08020703c (42 samples, 0.02%)0xffffffc080207040 (111 samples, 0.06%)0xffffffc080207044 (79 samples, 0.04%)0xffffffc080207048 (28 samples, 0.02%)0xffffffc08020704c (42 samples, 0.02%)0xffffffc08020704e (36 samples, 0.02%)0xffffffc080207052 (38 samples, 0.02%)0xffffffc080207056 (77 samples, 0.04%)0xffffffc080207058 (31 samples, 0.02%)0xffffffc08020705c (39 samples, 0.02%)0xffffffc08020705e (24 samples, 0.01%)0xffffffc080207062 (45 samples, 0.03%)0xffffffc080207064 (29 samples, 0.02%)0xffffffc08020707c (27 samples, 0.02%)0xffffffc08020707e (26 samples, 0.01%)0xffffffc080207080 (28 samples, 0.02%)0xffffffc080207082 (28 samples, 0.02%)0xffffffc080207084 (30 samples, 0.02%)0xffffffc080207086 (32 samples, 0.02%)0xffffffc080207088 (27 samples, 0.02%)0xffffffc08020c31c (27 samples, 0.02%)0xffffffc08021afc2 (4,619 samples, 2.58%)0x..0xffffffc08021afc4 (4,680 samples, 2.62%)0x..0xffffffc08021afc6 (4,603 samples, 2.57%)0x..0xffffffc08021afca (4,743 samples, 2.65%)0x..0xffffffc08021afce (4,634 samples, 2.59%)0x..0xffffffc08021afd2 (4,763 samples, 2.66%)0x..0xffffffc08021afd4 (4,678 samples, 2.62%)0x..0xffffffc08021afd8 (4,533 samples, 2.54%)0x..0xffffffc08021afdc (4,500 samples, 2.52%)0x..0xffffffc08021afe0 (4,638 samples, 2.59%)0x..0xffffffc08021afe2 (4,488 samples, 2.51%)0x..0xffffffc08021e7b2 (24 samples, 0.01%)0xffffffc08021e7b8 (23 samples, 0.01%)0xffffffc08021e7bc (20 samples, 0.01%)0xffffffc08021e7c0 (21 samples, 0.01%)0xffffffc080220b20 (26 samples, 0.01%)0xffffffc080220b2a (19 samples, 0.01%)0xffffffc080220ba0 (18 samples, 0.01%)0xffffffc080220ba2 (20 samples, 0.01%)0xffffffc0802240b2 (85 samples, 0.05%)0xffffffc0802240b4 (97 samples, 0.05%)0xffffffc0802240b6 (89 samples, 0.05%)0xffffffc0802240ba (112 samples, 0.06%)0xffffffc0802240bc (84 samples, 0.05%)0xffffffc0802240be (101 samples, 0.06%)0xffffffc080232bf8 (19 samples, 0.01%)0xffffffc080232c3a (20 samples, 0.01%)0xffffffc080232c3e (21 samples, 0.01%)0xffffffc080232c42 (23 samples, 0.01%)0xffffffc080232c46 (20 samples, 0.01%)0xffffffc080232c4a (19 samples, 0.01%)0xffffffc080232c4c (18 samples, 0.01%)0xffffffc080232c4e (30 samples, 0.02%)0xffffffc080232c76 (18 samples, 0.01%)0xffffffc080232c82 (18 samples, 0.01%)0xffffffc080232c86 (26 samples, 0.01%)0xffffffc080232c8a (21 samples, 0.01%)0xffffffc080232e28 (19 samples, 0.01%)0xffffffc080232e54 (195 samples, 0.11%)0xffffffc080232e58 (92 samples, 0.05%)0xffffffc080232e76 (2,187 samples, 1.22%)0xffffffc080232e78 (3,654 samples, 2.04%)0..0xffffffc080232e7c (5,967 samples, 3.34%)0xf..0xffffffc080232e80 (3,615 samples, 2.02%)0..0xffffffc080232e84 (3,587 samples, 2.01%)0..0xffffffc080232e88 (3,662 samples, 2.05%)0..0xffffffc080232e8c (4,232 samples, 2.37%)0x..0xffffffc080232f9e (29 samples, 0.02%)0xffffffc080232fa6 (18 samples, 0.01%)0xffffffc080232faa (26 samples, 0.01%)0xffffffc080232fb0 (20 samples, 0.01%)0xffffffc080232fc4 (30 samples, 0.02%)0xffffffc080232fc6 (21 samples, 0.01%)0xffffffc080232fc8 (20 samples, 0.01%)0xffffffc080232ff4 (40 samples, 0.02%)0xffffffc08023d2cd (57 samples, 0.03%)0xffffffc08024fa4c (33 samples, 0.02%)0xffffffc08024fa50 (46 samples, 0.03%)0xffffffc08024fa52 (32 samples, 0.02%)0xffffffc08024fa54 (40 samples, 0.02%)0xffffffc08024fa58 (28 samples, 0.02%)0xffffffc08024fa5a (46 samples, 0.03%)0xffffffc08024fa5c (47 samples, 0.03%)0xffffffc08024fa5e (42 samples, 0.02%)0xffffffc08024fa60 (27 samples, 0.02%)0xffffffc08024fa64 (41 samples, 0.02%)0xffffffc08024fa66 (34 samples, 0.02%)0xffffffc08024fa68 (31 samples, 0.02%)0xffffffc08024fa6a (30 samples, 0.02%)0xffffffc08024fa6c (34 samples, 0.02%)0xffffffc08024fa6e (31 samples, 0.02%)0xffffffc08024fa70 (37 samples, 0.02%)0xffffffc08024fa74 (39 samples, 0.02%)0xffffffc08024fa84 (30 samples, 0.02%)0xffffffc08024fa88 (43 samples, 0.02%)0xffffffc08024fa8c (29 samples, 0.02%)0xffffffc08024fa8e (30 samples, 0.02%)0xffffffc08024faa8 (42 samples, 0.02%)0xffffffc08023d81f (918 samples, 0.51%)0xffffffc08024c480 (94 samples, 0.05%)0xffffffc08024c484 (118 samples, 0.07%)0xffffffc08024c488 (103 samples, 0.06%)0xffffffc08024c48c (97 samples, 0.05%)0xffffffc08024c48e (107 samples, 0.06%)0xffffffc08024c490 (327 samples, 0.18%)0xffffffc08024c494 (366 samples, 0.20%)0xffffffc08024c498 (328 samples, 0.18%)0xffffffc08024c49c (318 samples, 0.18%)0xffffffc08024c49e (2,648 samples, 1.48%)0xffffffc08024c4a0 (2,299 samples, 1.29%)0xffffffc08024c4a2 (2,376 samples, 1.33%)0xffffffc08024c4a4 (2,292 samples, 1.28%)0xffffffc08024c4a8 (2,237 samples, 1.25%)0xffffffc08024c4ac (2,178 samples, 1.22%)0xffffffc08024c4ae (2,252 samples, 1.26%)0xffffffc08024c4b0 (2,268 samples, 1.27%)0xffffffc08024c4b4 (2,304 samples, 1.29%)0xffffffc08024c4b6 (2,208 samples, 1.24%)0xffffffc08024c4c0 (355 samples, 0.20%)0xffffffc08024c4c2 (311 samples, 0.17%)0xffffffc08024c4c4 (242 samples, 0.14%)0xffffffc08024c4c6 (231 samples, 0.13%)0xffffffc08024c4c8 (222 samples, 0.12%)0xffffffc08024c4ca (263 samples, 0.15%)0xffffffc08024c4cc (248 samples, 0.14%)0xffffffc08024c4ce (102 samples, 0.06%)0xffffffc08024c4d0 (103 samples, 0.06%)0xffffffc08024c4d2 (101 samples, 0.06%)0xffffffc08024c4d6 (96 samples, 0.05%)0xffffffc08024c4d8 (85 samples, 0.05%)0xffffffc08024c4da (96 samples, 0.05%)0xffffffc08024c4de (69 samples, 0.04%)0xffffffc08024c4e2 (77 samples, 0.04%)0xffffffc08024c4e6 (87 samples, 0.05%)0xffffffc08024c4ea (79 samples, 0.04%)0xffffffc08024c4ec (67 samples, 0.04%)0xffffffc08024c4f0 (96 samples, 0.05%)0xffffffc08024c4f4 (100 samples, 0.06%)0xffffffc08024c524 (88 samples, 0.05%)0xffffffc08024c526 (97 samples, 0.05%)0xffffffc08024c528 (96 samples, 0.05%)0xffffffc08024c52a (91 samples, 0.05%)0xffffffc08024c574 (86 samples, 0.05%)0xffffffc08024c576 (68 samples, 0.04%)0xffffffc08024c578 (75 samples, 0.04%)0xffffffc08024c57a (98 samples, 0.05%)0xffffffc08024c57e (95 samples, 0.05%)0xffffffc08024c582 (75 samples, 0.04%)0xffffffc08024c584 (90 samples, 0.05%)0xffffffc08024c5ec (36 samples, 0.02%)0xffffffc08024c5fa (21 samples, 0.01%)0xffffffc08024c602 (19 samples, 0.01%)0xffffffc08024c60a (18 samples, 0.01%)0xffffffc08024c614 (19 samples, 0.01%)0xffffffc08024c61e (23 samples, 0.01%)0xffffffc08024c646 (21 samples, 0.01%)0xffffffc08024c650 (32 samples, 0.02%)0xffffffc08024c656 (19 samples, 0.01%)0xffffffc08024c664 (19 samples, 0.01%)0xffffffc08024c66c (24 samples, 0.01%)0xffffffc08024c674 (23 samples, 0.01%)0xffffffc08024c6dc (21 samples, 0.01%)0xffffffc08024c6e4 (20 samples, 0.01%)0xffffffc08024c6ee (21 samples, 0.01%)0xffffffc08024c6f2 (26 samples, 0.01%)0xffffffc08024c8b2 (21 samples, 0.01%)0xffffffc08024c910 (18 samples, 0.01%)0xffffffc08024c926 (22 samples, 0.01%)0xffffffc08024c928 (19 samples, 0.01%)0xffffffc08024c942 (18 samples, 0.01%)0xffffffc08024ca5e (91 samples, 0.05%)0xffffffc08024ca62 (123 samples, 0.07%)0xffffffc08024ca66 (91 samples, 0.05%)0xffffffc08024ca6a (80 samples, 0.04%)0xffffffc08024ca6e (93 samples, 0.05%)0xffffffc08024ca70 (97 samples, 0.05%)0xffffffc08024ca72 (113 samples, 0.06%)0xffffffc08024cc94 (65 samples, 0.04%)0xffffffc08024cc98 (108 samples, 0.06%)0xffffffc08024cc9c (82 samples, 0.05%)0xffffffc08024cc9e (89 samples, 0.05%)0xffffffc08024cca2 (102 samples, 0.06%)0xffffffc08024cca4 (96 samples, 0.05%)0xffffffc08024cca6 (110 samples, 0.06%)0xffffffc08024ccaa (89 samples, 0.05%)0xffffffc08024ccac (91 samples, 0.05%)0xffffffc08024ccae (106 samples, 0.06%)0xffffffc08024ccb2 (89 samples, 0.05%)0xffffffc08024ccb6 (91 samples, 0.05%)0xffffffc08024ccb8 (107 samples, 0.06%)0xffffffc08024ccba (92 samples, 0.05%)0xffffffc08024ccbe (105 samples, 0.06%)0xffffffc08024ccc0 (84 samples, 0.05%)0xffffffc08024efec (18 samples, 0.01%)0xffffffc08024f092 (20 samples, 0.01%)0xffffffc08024f176 (18 samples, 0.01%)0xffffffc08024f1dc (24 samples, 0.01%)0xffffffc08024f5fa (24 samples, 0.01%)0xffffffc08024f600 (28 samples, 0.02%)0xffffffc08024f602 (22 samples, 0.01%)0xffffffc08024f604 (19 samples, 0.01%)0xffffffc08024f606 (27 samples, 0.02%)0xffffffc08024f60a (24 samples, 0.01%)0xffffffc08024f60c (20 samples, 0.01%)0xffffffc08024f612 (25 samples, 0.01%)0xffffffc08024f618 (18 samples, 0.01%)0xffffffc08024f61c (20 samples, 0.01%)0xffffffc08024f620 (26 samples, 0.01%)0xffffffc08024f624 (24 samples, 0.01%)0xffffffc08024f628 (22 samples, 0.01%)0xffffffc08024f738 (18 samples, 0.01%)0xffffffc08024fc8a (36 samples, 0.02%)0xffffffc08024fc8c (19 samples, 0.01%)0xffffffc08024fc8e (23 samples, 0.01%)0xffffffc08024fc90 (23 samples, 0.01%)0xffffffc08024fc94 (26 samples, 0.01%)0xffffffc08024fc9c (19 samples, 0.01%)0xffffffc08024fc9e (24 samples, 0.01%)0xffffffc08024fca2 (24 samples, 0.01%)0xffffffc08024fca4 (26 samples, 0.01%)0xffffffc08024fe30 (19 samples, 0.01%)0xffffffc08024fe32 (24 samples, 0.01%)0xffffffc08024fe40 (24 samples, 0.01%)0xffffffc08024fe42 (28 samples, 0.02%)0xffffffc08024fe46 (18 samples, 0.01%)0xffffffc08024fe94 (26 samples, 0.01%)0xffffffc08024fe96 (24 samples, 0.01%)0xffffffc08024fe98 (26 samples, 0.01%)0xffffffc08024fe9a (22 samples, 0.01%)0xffffffc08024feaa (22 samples, 0.01%)0xffffffc08024feac (22 samples, 0.01%)0xffffffc080254958 (24 samples, 0.01%)0xffffffc080254996 (20 samples, 0.01%)0xffffffc080254998 (23 samples, 0.01%)0xffffffc0802549ec (23 samples, 0.01%)0xffffffc0802549f0 (18 samples, 0.01%)0xffffffc0802549f6 (18 samples, 0.01%)0xffffffc080254a96 (20 samples, 0.01%)0xffffffc080254a9e (20 samples, 0.01%)0xffffffc080254abc (20 samples, 0.01%)0xffffffc08025533e (21 samples, 0.01%)0xffffffc08025534c (22 samples, 0.01%)0xffffffc080296630 (312 samples, 0.17%)0xffffffc08020409d (28 samples, 0.02%)0xffffffc08029abb1 (45 samples, 0.03%)0xffffffc08029b2e6 (35 samples, 0.02%)0xffffffc08029b2f4 (19 samples, 0.01%)0xffffffc08029b2fa (28 samples, 0.02%)0xffffffc08029b30a (28 samples, 0.02%)0xffffffc08029b328 (23 samples, 0.01%)0xffffffc0803a7634 (52 samples, 0.03%)0xffffffc0803a7636 (52 samples, 0.03%)0xffffffc0803a763a (59 samples, 0.03%)0xffffffc0803a763c (66 samples, 0.04%)0xffffffc0803a763e (64 samples, 0.04%)0xffffffc0802a4585 (486 samples, 0.27%)0xffffffc0802a9f2e (26 samples, 0.01%)0xffffffc0802a9f30 (23 samples, 0.01%)0xffffffc0802a9f36 (26 samples, 0.01%)0xffffffc0802a9f3c (20 samples, 0.01%)0xffffffc0802a9f40 (21 samples, 0.01%)0xffffffc0802a9f44 (26 samples, 0.01%)0xffffffc0802a9f48 (24 samples, 0.01%)0xffffffc0802a9f50 (18 samples, 0.01%)0xffffffc0802a9f5a (22 samples, 0.01%)0xffffffc0802ab76e (29 samples, 0.02%)0xffffffc0802ab770 (25 samples, 0.01%)0xffffffc0802ab772 (22 samples, 0.01%)0xffffffc0802ab776 (23 samples, 0.01%)0xffffffc0802ab77a (31 samples, 0.02%)0xffffffc0802ab77e (25 samples, 0.01%)0xffffffc0802ab782 (20 samples, 0.01%)0xffffffc0802ab786 (28 samples, 0.02%)0xffffffc0802ab78a (29 samples, 0.02%)0xffffffc0802ab78e (35 samples, 0.02%)0xffffffc0802ab790 (27 samples, 0.02%)0xffffffc0802ad157 (34 samples, 0.02%)0xffffffc0802e1601 (31 samples, 0.02%)0xffffffc0803584aa (86 samples, 0.05%)0xffffffc0803584ac (95 samples, 0.05%)0xffffffc0803584ae (87 samples, 0.05%)0xffffffc0803584b0 (96 samples, 0.05%)0xffffffc0803584b2 (78 samples, 0.04%)0xffffffc0803584b6 (91 samples, 0.05%)0xffffffc0803584b8 (77 samples, 0.04%)0xffffffc0803584bc (103 samples, 0.06%)0xffffffc0803584c0 (88 samples, 0.05%)0xffffffc0803584da (80 samples, 0.04%)0xffffffc0803584dc (102 samples, 0.06%)0xffffffc0803584e8 (24 samples, 0.01%)0xffffffc080358506 (19 samples, 0.01%)0xffffffc080358512 (32 samples, 0.02%)0xffffffc08035851c (22 samples, 0.01%)0xffffffc08035851e (28 samples, 0.02%)0xffffffc0803a75ea (76 samples, 0.04%)0xffffffc0803a75ec (61 samples, 0.03%)0xffffffc0803a75ee (55 samples, 0.03%)0xffffffc0803a75f2 (49 samples, 0.03%)0xffffffc0803a75f6 (53 samples, 0.03%)0xffffffc0803a75fa (39 samples, 0.02%)0xffffffc0803a75fe (49 samples, 0.03%)0xffffffc0803a7618 (50 samples, 0.03%)0xffffffc0803a761a (43 samples, 0.02%)0xffffffc0803a761e (53 samples, 0.03%)0xffffffc0803a7622 (62 samples, 0.03%)0xffffffc0803a7626 (46 samples, 0.03%)0xffffffc0803a762a (51 samples, 0.03%)0xffffffc0803a762e (34 samples, 0.02%)0xffffffc0803a7632 (33 samples, 0.02%)0xffffffc0803a7634 (3,546 samples, 1.98%)0..0xffffffc0803a7636 (3,757 samples, 2.10%)0..0xffffffc0803a763a (3,592 samples, 2.01%)0..0xffffffc0803a763c (3,569 samples, 2.00%)0..0xffffffc0803a763e (3,489 samples, 1.95%)0..0xffffffc0803a7642 (31 samples, 0.02%)0xffffffc0803a7644 (22 samples, 0.01%)0xffffffc0803a7648 (31 samples, 0.02%)0xffffffc0803a764c (34 samples, 0.02%)0xffffffc0803a7650 (40 samples, 0.02%)0xffffffc0803a766c (46 samples, 0.03%)0xffffffc0803a766e (57 samples, 0.03%)0xffffffc0803a7670 (27 samples, 0.02%)0xffffffc0803a7674 (18 samples, 0.01%)0xffffffc0803a767a (20 samples, 0.01%)0xffffffc0803a767e (22 samples, 0.01%)0xffffffc0803a7682 (22 samples, 0.01%)0xffffffc0803a7688 (19 samples, 0.01%)0xffffffc0803a768c (23 samples, 0.01%)0xffffffc0803a768e (22 samples, 0.01%)0xffffffc0803a7692 (18 samples, 0.01%)0xffffffc0803a76d0 (24 samples, 0.01%)0xffffffc0803a76d6 (18 samples, 0.01%)0xffffffc0803a76d8 (23 samples, 0.01%)0xffffffc0803a76de (20 samples, 0.01%)0xffffffc0803a76ee (22 samples, 0.01%)0xffffffc0803a76f2 (21 samples, 0.01%)0xffffffc0803a76f6 (82 samples, 0.05%)0xffffffc0803a76f8 (76 samples, 0.04%)0xffffffc0803a76fc (74 samples, 0.04%)0xffffffc0803a7700 (89 samples, 0.05%)0xffffffc0803a7702 (61 samples, 0.03%)0xffffffc0803a7706 (81 samples, 0.05%)0xffffffc0803a770a (63 samples, 0.04%)0xffffffc0803a770e (68 samples, 0.04%)0xffffffc0803a7712 (66 samples, 0.04%)0xffffffc0803a7714 (65 samples, 0.04%)0xffffffc0803a7718 (19 samples, 0.01%)0xffffffc0803a771c (19 samples, 0.01%)0xffffffc0803a771e (20 samples, 0.01%)0xffffffc0803a7720 (18 samples, 0.01%)0xffffffc0803a772e (22 samples, 0.01%)0xffffffc0803a7740 (21 samples, 0.01%)0xffffffc0803a7742 (24 samples, 0.01%)0xffffffc0803a774a (27 samples, 0.02%)0xffffffc0803a774e (22 samples, 0.01%)0xffffffc0803a7752 (26 samples, 0.01%)0xffffffc0803a7756 (23 samples, 0.01%)0xffffffc0803a775c (21 samples, 0.01%)0xffffffc0803a7760 (18 samples, 0.01%)0xffffffc0803a7764 (18 samples, 0.01%)0xffffffc0803a7768 (21 samples, 0.01%)0xffffffc0803a776a (19 samples, 0.01%)0xffffffc0803a7770 (18 samples, 0.01%)0xffffffc0803a7772 (24 samples, 0.01%)0xffffffc0803a786a (21 samples, 0.01%)0xffffffc0803a786c (18 samples, 0.01%)0xffffffc0803a7870 (28 samples, 0.02%)0xffffffc0803a7872 (20 samples, 0.01%)0xffffffc0803a7874 (20 samples, 0.01%)0xffffffc0803a7b26 (31 samples, 0.02%)0xffffffc0803a7b72 (1,294 samples, 0.72%)0xffffffc0803a7b74 (1,294 samples, 0.72%)0xffffffc0803a7b76 (1,298 samples, 0.73%)0xffffffc0803a7b7a (18 samples, 0.01%)0xffffffc0803a7b9c (106 samples, 0.06%)0xffffffc0803a7ba0 (54 samples, 0.03%)0xffffffc0803cec67 (50 samples, 0.03%)0xffffffc0804c43ff (23 samples, 0.01%)0xffffffc080220b20 (107 samples, 0.06%)0xffffffc080220b22 (53 samples, 0.03%)0xffffffc080220b24 (49 samples, 0.03%)0xffffffc080220b26 (57 samples, 0.03%)0xffffffc080220b28 (63 samples, 0.04%)0xffffffc080220b2a (61 samples, 0.03%)0xffffffc080220b2c (52 samples, 0.03%)0xffffffc080220b2e (67 samples, 0.04%)0xffffffc080220b30 (70 samples, 0.04%)0xffffffc080220b32 (56 samples, 0.03%)0xffffffc080220b34 (63 samples, 0.04%)0xffffffc080220b38 (71 samples, 0.04%)0xffffffc080220b3c (60 samples, 0.03%)0xffffffc080220b3e (60 samples, 0.03%)0xffffffc080220b80 (68 samples, 0.04%)0xffffffc080220b84 (46 samples, 0.03%)0xffffffc080220b9c (50 samples, 0.03%)0xffffffc080220ba0 (61 samples, 0.03%)0xffffffc080220ba2 (67 samples, 0.04%)0xffffffc080220ba4 (60 samples, 0.03%)0xffffffc080220ba8 (65 samples, 0.04%)0xffffffc080220baa (68 samples, 0.04%)0xffffffc080220bae (67 samples, 0.04%)0xffffffc080220bb0 (78 samples, 0.04%)0xffffffc080220bb2 (43 samples, 0.02%)0xffffffc080220bb4 (56 samples, 0.03%)0xffffffc080220bb8 (81 samples, 0.05%)0xffffffc080220bbc (60 samples, 0.03%)0xffffffc080220bbe (82 samples, 0.05%)0xffffffc08024efde (54 samples, 0.03%)0xffffffc08024efe0 (70 samples, 0.04%)0xffffffc08024efe2 (58 samples, 0.03%)0xffffffc08024efe4 (58 samples, 0.03%)0xffffffc08024efe8 (64 samples, 0.04%)0xffffffc08024efec (98 samples, 0.05%)0xffffffc08024efee (53 samples, 0.03%)0xffffffc08024eff0 (67 samples, 0.04%)0xffffffc08024eff2 (58 samples, 0.03%)0xffffffc08024eff8 (59 samples, 0.03%)0xffffffc08024effc (51 samples, 0.03%)0xffffffc08024effe (62 samples, 0.03%)0xffffffc0804c77ff (2,853 samples, 1.60%)0xffffffc080861bff (18 samples, 0.01%)0xffffffc0808d75ff (85 samples, 0.05%)0xffffffc08093d50f (85 samples, 0.05%)0xffffffc0803a786c (20 samples, 0.01%)0xffffffc0803a7870 (20 samples, 0.01%)0xffffffc08093d4af (148 samples, 0.08%)0xffffffc0809dbfff (19 samples, 0.01%)0xffffffc080cbed3f (25 samples, 0.01%)all (178,770 samples, 100%) \ No newline at end of file diff --git a/docs/flamegraphs/target__qperf__virtio-blk-patched__flamegraph.svg b/docs/flamegraphs/target__qperf__virtio-blk-patched__flamegraph.svg new file mode 100644 index 0000000000..dee0eddb9d --- /dev/null +++ b/docs/flamegraphs/target__qperf__virtio-blk-patched__flamegraph.svg @@ -0,0 +1,491 @@ +Flame Graph Reset ZoomSearch 0xffffffc0802204c4 (49 samples, 0.03%)0xffffffc0802204c6 (31 samples, 0.02%)0xffffffc0802204c8 (40 samples, 0.02%)0xffffffc0802204ca (32 samples, 0.02%)0xffffffc0802204cc (35 samples, 0.02%)0xffffffc0802204ce (20 samples, 0.01%)0xffffffc0802204d0 (40 samples, 0.02%)0xffffffc0802204d2 (39 samples, 0.02%)0xffffffc0802204d4 (28 samples, 0.02%)0xffffffc0802204d6 (36 samples, 0.02%)0xffffffc0802204d8 (27 samples, 0.02%)0xffffffc0802204dc (35 samples, 0.02%)0xffffffc0802204e0 (41 samples, 0.02%)0xffffffc0802204e2 (30 samples, 0.02%)0xffffffc080220524 (45 samples, 0.03%)0xffffffc080220528 (29 samples, 0.02%)0xffffffc080220540 (32 samples, 0.02%)0xffffffc080220544 (23 samples, 0.01%)0xffffffc080220546 (36 samples, 0.02%)0xffffffc080220548 (34 samples, 0.02%)0xffffffc08022054c (28 samples, 0.02%)0xffffffc08022054e (35 samples, 0.02%)0xffffffc080220552 (31 samples, 0.02%)0xffffffc080220554 (27 samples, 0.02%)0xffffffc080220556 (34 samples, 0.02%)0xffffffc080220558 (30 samples, 0.02%)0xffffffc08022055c (39 samples, 0.02%)0xffffffc080220560 (28 samples, 0.02%)0xffffffc080220562 (34 samples, 0.02%)0xffffffc08024ee18 (29 samples, 0.02%)0xffffffc08024ee1a (42 samples, 0.02%)0xffffffc08024ee1c (31 samples, 0.02%)0xffffffc08024ee1e (34 samples, 0.02%)0xffffffc08024ee22 (32 samples, 0.02%)0xffffffc08024ee26 (52 samples, 0.03%)0xffffffc08024ee28 (23 samples, 0.01%)0xffffffc08024ee2a (45 samples, 0.03%)0xffffffc08024ee2c (33 samples, 0.02%)0xffffffc08024ee32 (31 samples, 0.02%)0xffffffc08024ee36 (27 samples, 0.02%)0xffffffc08024ee38 (26 samples, 0.01%)0x109b (1,514 samples, 0.85%)0x15cf1 (21 samples, 0.01%)0xffffffc0803a7482 (38 samples, 0.02%)0xffffffc0803a7484 (54 samples, 0.03%)0xffffffc0803a7488 (46 samples, 0.03%)0xffffffc0803a748a (42 samples, 0.02%)0x204f (221 samples, 0.12%)0xffffffc0803a748c (39 samples, 0.02%)0xffffffc080232dce (18 samples, 0.01%)0xfff (258 samples, 0.14%)0xffffffc080201000 (682 samples, 0.38%)0xffffffc080201144 (24 samples, 0.01%)0xffffffc080201146 (38 samples, 0.02%)0xffffffc080201148 (26 samples, 0.01%)0xffffffc08020114c (26 samples, 0.01%)0xffffffc080201150 (30 samples, 0.02%)0xffffffc080201154 (22 samples, 0.01%)0xffffffc080201158 (26 samples, 0.01%)0xffffffc08020115c (32 samples, 0.02%)0xffffffc080201160 (28 samples, 0.02%)0xffffffc080201162 (31 samples, 0.02%)0xffffffc080201164 (34 samples, 0.02%)0xffffffc080201168 (24 samples, 0.01%)0xffffffc08020116c (25 samples, 0.01%)0xffffffc080201170 (36 samples, 0.02%)0xffffffc080201174 (37 samples, 0.02%)0xffffffc080201178 (35 samples, 0.02%)0xffffffc08020117c (30 samples, 0.02%)0xffffffc080201180 (34 samples, 0.02%)0xffffffc080201184 (30 samples, 0.02%)0xffffffc080204344 (80 samples, 0.04%)0xffffffc080204346 (33 samples, 0.02%)0xffffffc080204348 (41 samples, 0.02%)0xffffffc08020434a (27 samples, 0.02%)0xffffffc08020434c (27 samples, 0.02%)0xffffffc08020434e (32 samples, 0.02%)0xffffffc080204350 (24 samples, 0.01%)0xffffffc080204352 (32 samples, 0.02%)0xffffffc080204354 (35 samples, 0.02%)0xffffffc080204356 (30 samples, 0.02%)0xffffffc080204358 (41 samples, 0.02%)0xffffffc08020435a (30 samples, 0.02%)0xffffffc08020435c (42 samples, 0.02%)0xffffffc08020435e (33 samples, 0.02%)0xffffffc080204360 (40 samples, 0.02%)0xffffffc080204362 (24 samples, 0.01%)0xffffffc080204366 (107 samples, 0.06%)0xffffffc08020436a (26 samples, 0.01%)0xffffffc08020436c (36 samples, 0.02%)0xffffffc080204370 (30 samples, 0.02%)0xffffffc080204372 (34 samples, 0.02%)0xffffffc080204376 (98 samples, 0.05%)0xffffffc080204378 (37 samples, 0.02%)0xffffffc08020437a (34 samples, 0.02%)0xffffffc08020437e (40 samples, 0.02%)0xffffffc080204380 (37 samples, 0.02%)0xffffffc080204384 (37 samples, 0.02%)0xffffffc080204388 (86 samples, 0.05%)0xffffffc08020438c (34 samples, 0.02%)0xffffffc080204390 (32 samples, 0.02%)0xffffffc080204394 (28 samples, 0.02%)0xffffffc080204396 (26 samples, 0.01%)0xffffffc08020439a (29 samples, 0.02%)0xffffffc08020439e (27 samples, 0.02%)0xffffffc0802043a0 (29 samples, 0.02%)0xffffffc0802043b2 (37 samples, 0.02%)0xffffffc0802043b4 (32 samples, 0.02%)0xffffffc0802043b6 (34 samples, 0.02%)0xffffffc0802043ba (30 samples, 0.02%)0xffffffc0802043bc (33 samples, 0.02%)0xffffffc0802043c0 (28 samples, 0.02%)0xffffffc0802043c4 (34 samples, 0.02%)0xffffffc0802043c8 (37 samples, 0.02%)0xffffffc0802043cc (28 samples, 0.02%)0xffffffc0802043d0 (34 samples, 0.02%)0xffffffc0802043d4 (28 samples, 0.02%)0xffffffc0802043d8 (35 samples, 0.02%)0xffffffc0802043dc (20 samples, 0.01%)0xffffffc0802043e0 (36 samples, 0.02%)0xffffffc0802043e4 (27 samples, 0.02%)0xffffffc0802043e8 (40 samples, 0.02%)0xffffffc0802043ec (32 samples, 0.02%)0xffffffc0802043ee (25 samples, 0.01%)0xffffffc0802043f2 (32 samples, 0.02%)0xffffffc0802043f4 (32 samples, 0.02%)0xffffffc0802043f8 (33 samples, 0.02%)0xffffffc0802043fa (22 samples, 0.01%)0xffffffc0802043fe (36 samples, 0.02%)0xffffffc080204400 (25 samples, 0.01%)0xffffffc080204404 (31 samples, 0.02%)0xffffffc080204408 (35 samples, 0.02%)0xffffffc08020440c (35 samples, 0.02%)0xffffffc08020440e (38 samples, 0.02%)0xffffffc080204412 (33 samples, 0.02%)0xffffffc080204414 (33 samples, 0.02%)0xffffffc080204418 (34 samples, 0.02%)0xffffffc08020441a (27 samples, 0.02%)0xffffffc08020441e (29 samples, 0.02%)0xffffffc080204420 (30 samples, 0.02%)0xffffffc080204424 (26 samples, 0.01%)0xffffffc080204428 (31 samples, 0.02%)0xffffffc08020442a (41 samples, 0.02%)0xffffffc08020442c (24 samples, 0.01%)0xffffffc080204430 (34 samples, 0.02%)0xffffffc080204432 (34 samples, 0.02%)0xffffffc080204434 (35 samples, 0.02%)0xffffffc080204436 (25 samples, 0.01%)0xffffffc08020443a (30 samples, 0.02%)0xffffffc08020443c (37 samples, 0.02%)0xffffffc08020443e (34 samples, 0.02%)0xffffffc080204442 (26 samples, 0.01%)0xffffffc080204444 (41 samples, 0.02%)0xffffffc080204446 (42 samples, 0.02%)0xffffffc08020444a (30 samples, 0.02%)0xffffffc08020444c (32 samples, 0.02%)0xffffffc08020444e (30 samples, 0.02%)0xffffffc080204452 (40 samples, 0.02%)0xffffffc080204454 (31 samples, 0.02%)0xffffffc080204456 (38 samples, 0.02%)0xffffffc08020445a (32 samples, 0.02%)0xffffffc080204460 (37 samples, 0.02%)0xffffffc080204464 (34 samples, 0.02%)0xffffffc080204468 (39 samples, 0.02%)0xffffffc08020446c (19 samples, 0.01%)0xffffffc080204470 (30 samples, 0.02%)0xffffffc080204474 (33 samples, 0.02%)0xffffffc080204478 (30 samples, 0.02%)0xffffffc08020447c (22 samples, 0.01%)0xffffffc080204480 (37 samples, 0.02%)0xffffffc080204484 (38 samples, 0.02%)0xffffffc080204488 (31 samples, 0.02%)0xffffffc08020448c (43 samples, 0.02%)0xffffffc080204490 (28 samples, 0.02%)0xffffffc080204494 (33 samples, 0.02%)0xffffffc080204498 (27 samples, 0.02%)0xffffffc08020449c (24 samples, 0.01%)0xffffffc08020449e (31 samples, 0.02%)0xffffffc0802044a2 (40 samples, 0.02%)0xffffffc0802044a4 (39 samples, 0.02%)0xffffffc0802044a8 (38 samples, 0.02%)0xffffffc0802044ac (32 samples, 0.02%)0xffffffc0802044b0 (27 samples, 0.02%)0xffffffc0802044b4 (30 samples, 0.02%)0xffffffc0802044b8 (23 samples, 0.01%)0xffffffc0802044be (41 samples, 0.02%)0xffffffc0802044c2 (38 samples, 0.02%)0xffffffc0802044c6 (28 samples, 0.02%)0xffffffc0802044ca (30 samples, 0.02%)0xffffffc0802044ce (32 samples, 0.02%)0xffffffc0802044d2 (34 samples, 0.02%)0xffffffc0802044d6 (29 samples, 0.02%)0xffffffc0802044d8 (32 samples, 0.02%)0xffffffc0802044da (37 samples, 0.02%)0xffffffc0802044dc (27 samples, 0.02%)0xffffffc0802044de (42 samples, 0.02%)0xffffffc0802044e2 (26 samples, 0.01%)0xffffffc0802044e4 (37 samples, 0.02%)0xffffffc0802044e6 (21 samples, 0.01%)0xffffffc0802044ea (37 samples, 0.02%)0xffffffc0802044ee (39 samples, 0.02%)0xffffffc0802044f2 (35 samples, 0.02%)0xffffffc0802044f6 (28 samples, 0.02%)0xffffffc0802044fa (34 samples, 0.02%)0xffffffc0802044fe (30 samples, 0.02%)0xffffffc080204502 (19 samples, 0.01%)0xffffffc080204506 (25 samples, 0.01%)0xffffffc08020450a (32 samples, 0.02%)0xffffffc08020450e (30 samples, 0.02%)0xffffffc080204512 (24 samples, 0.01%)0xffffffc080204516 (30 samples, 0.02%)0xffffffc08020451a (29 samples, 0.02%)0xffffffc08020451e (33 samples, 0.02%)0xffffffc080204522 (31 samples, 0.02%)0xffffffc080204524 (22 samples, 0.01%)0xffffffc080204528 (33 samples, 0.02%)0xffffffc08020452a (28 samples, 0.02%)0xffffffc08020452e (26 samples, 0.01%)0xffffffc080204530 (46 samples, 0.03%)0xffffffc080204534 (25 samples, 0.01%)0xffffffc080204536 (31 samples, 0.02%)0xffffffc08020453a (41 samples, 0.02%)0xffffffc08020453c (37 samples, 0.02%)0xffffffc08020453e (30 samples, 0.02%)0xffffffc080204542 (27 samples, 0.02%)0xffffffc080204544 (33 samples, 0.02%)0xffffffc080204548 (34 samples, 0.02%)0xffffffc08020454a (27 samples, 0.02%)0xffffffc08020454e (40 samples, 0.02%)0xffffffc080204550 (25 samples, 0.01%)0xffffffc080204554 (40 samples, 0.02%)0xffffffc080204558 (31 samples, 0.02%)0xffffffc08020455c (28 samples, 0.02%)0xffffffc080204560 (39 samples, 0.02%)0xffffffc080204564 (20 samples, 0.01%)0xffffffc080204566 (38 samples, 0.02%)0xffffffc080204568 (35 samples, 0.02%)0xffffffc08020456c (34 samples, 0.02%)0xffffffc08020456e (37 samples, 0.02%)0xffffffc080204570 (37 samples, 0.02%)0xffffffc080204574 (37 samples, 0.02%)0xffffffc08020458c (30 samples, 0.02%)0xffffffc08020463c (21 samples, 0.01%)0xffffffc0802046e6 (18 samples, 0.01%)0xffffffc0802046ea (19 samples, 0.01%)0xffffffc0802051b2 (34 samples, 0.02%)0xffffffc0802051b4 (62 samples, 0.03%)0xffffffc0802051b8 (20 samples, 0.01%)0xffffffc0802051ba (19 samples, 0.01%)0xffffffc080205f0a (76 samples, 0.04%)0xffffffc080205f0e (105 samples, 0.06%)0xffffffc080205f12 (36 samples, 0.02%)0xffffffc080205f14 (24 samples, 0.01%)0xffffffc080205f18 (33 samples, 0.02%)0xffffffc080205f1a (37 samples, 0.02%)0xffffffc080205f1e (76 samples, 0.04%)0xffffffc080205f20 (25 samples, 0.01%)0xffffffc080205f24 (28 samples, 0.02%)0xffffffc080205f26 (34 samples, 0.02%)0xffffffc080205f2a (32 samples, 0.02%)0xffffffc080205f2e (87 samples, 0.05%)0xffffffc080205f32 (38 samples, 0.02%)0xffffffc080205f36 (28 samples, 0.02%)0xffffffc080205f38 (23 samples, 0.01%)0xffffffc080205f3a (34 samples, 0.02%)0xffffffc080205f3c (38 samples, 0.02%)0xffffffc080205f40 (36 samples, 0.02%)0xffffffc080205f44 (29 samples, 0.02%)0xffffffc080205f46 (32 samples, 0.02%)0xffffffc080205f66 (37 samples, 0.02%)0xffffffc080205f68 (32 samples, 0.02%)0xffffffc080205f6c (28 samples, 0.02%)0xffffffc080205f6e (32 samples, 0.02%)0xffffffc080205f72 (32 samples, 0.02%)0xffffffc080205f76 (41 samples, 0.02%)0xffffffc080205f7a (30 samples, 0.02%)0xffffffc080205f7e (78 samples, 0.04%)0xffffffc080205f82 (77 samples, 0.04%)0xffffffc080205f86 (39 samples, 0.02%)0xffffffc080205f88 (30 samples, 0.02%)0xffffffc080205f8c (36 samples, 0.02%)0xffffffc080205f8e (33 samples, 0.02%)0xffffffc080205f92 (67 samples, 0.04%)0xffffffc080205f94 (30 samples, 0.02%)0xffffffc080205f98 (40 samples, 0.02%)0xffffffc080205f9a (30 samples, 0.02%)0xffffffc080205f9e (36 samples, 0.02%)0xffffffc080205fa0 (28 samples, 0.02%)0xffffffc080205fb4 (39 samples, 0.02%)0xffffffc080205fb8 (39 samples, 0.02%)0xffffffc080205fbc (29 samples, 0.02%)0xffffffc080205fc0 (42 samples, 0.02%)0xffffffc080205fc4 (33 samples, 0.02%)0xffffffc080205fc8 (76 samples, 0.04%)0xffffffc080205fcc (75 samples, 0.04%)0xffffffc080205fd0 (32 samples, 0.02%)0xffffffc080205fd2 (34 samples, 0.02%)0xffffffc080205fd6 (46 samples, 0.03%)0xffffffc080205fd8 (28 samples, 0.02%)0xffffffc080205fdc (79 samples, 0.04%)0xffffffc080205fde (33 samples, 0.02%)0xffffffc080205fe2 (25 samples, 0.01%)0xffffffc080205fe4 (38 samples, 0.02%)0xffffffc080205fe8 (30 samples, 0.02%)0xffffffc080205fea (34 samples, 0.02%)0xffffffc080205ff6 (30 samples, 0.02%)0xffffffc080205ff8 (29 samples, 0.02%)0xffffffc080205ffa (32 samples, 0.02%)0xffffffc080205ffc (42 samples, 0.02%)0xffffffc080205ffe (27 samples, 0.02%)0xffffffc080206000 (65 samples, 0.04%)0xffffffc080206002 (41 samples, 0.02%)0xffffffc080206004 (34 samples, 0.02%)0xffffffc080206006 (48 samples, 0.03%)0xffffffc080206008 (34 samples, 0.02%)0xffffffc08020600a (38 samples, 0.02%)0xffffffc08020600c (33 samples, 0.02%)0xffffffc08020600e (31 samples, 0.02%)0xffffffc080206010 (24 samples, 0.01%)0xffffffc080206012 (29 samples, 0.02%)0xffffffc080206d0e (64 samples, 0.04%)0xffffffc080206d10 (25 samples, 0.01%)0xffffffc080206d12 (37 samples, 0.02%)0xffffffc080206d14 (37 samples, 0.02%)0xffffffc080206d16 (25 samples, 0.01%)0xffffffc080206d18 (33 samples, 0.02%)0xffffffc080206d1a (25 samples, 0.01%)0xffffffc080206d1e (100 samples, 0.06%)0xffffffc080206d22 (30 samples, 0.02%)0xffffffc080206d24 (26 samples, 0.01%)0xffffffc080206d28 (32 samples, 0.02%)0xffffffc080206d2a (25 samples, 0.01%)0xffffffc080206d2e (84 samples, 0.05%)0xffffffc080206d30 (25 samples, 0.01%)0xffffffc080206d34 (25 samples, 0.01%)0xffffffc080206d36 (28 samples, 0.02%)0xffffffc080206d3a (35 samples, 0.02%)0xffffffc080206d3e (100 samples, 0.06%)0xffffffc080206d42 (34 samples, 0.02%)0xffffffc080206d46 (29 samples, 0.02%)0xffffffc080206d4a (38 samples, 0.02%)0xffffffc080206d4e (30 samples, 0.02%)0xffffffc080206d50 (31 samples, 0.02%)0xffffffc080206d54 (34 samples, 0.02%)0xffffffc080206d56 (31 samples, 0.02%)0xffffffc080206d5a (33 samples, 0.02%)0xffffffc080206d5e (22 samples, 0.01%)0xffffffc080206d62 (33 samples, 0.02%)0xffffffc080206d82 (23 samples, 0.01%)0xffffffc080206d84 (27 samples, 0.02%)0xffffffc080206d88 (34 samples, 0.02%)0xffffffc080206d8a (26 samples, 0.01%)0xffffffc080206d8e (32 samples, 0.02%)0xffffffc080206d92 (36 samples, 0.02%)0xffffffc080206d96 (34 samples, 0.02%)0xffffffc080206d9a (87 samples, 0.05%)0xffffffc080206d9e (92 samples, 0.05%)0xffffffc080206da2 (37 samples, 0.02%)0xffffffc080206da4 (22 samples, 0.01%)0xffffffc080206da8 (33 samples, 0.02%)0xffffffc080206daa (21 samples, 0.01%)0xffffffc080206dae (80 samples, 0.04%)0xffffffc080206db0 (31 samples, 0.02%)0xffffffc080206db4 (37 samples, 0.02%)0xffffffc080206db6 (25 samples, 0.01%)0xffffffc080206dba (36 samples, 0.02%)0xffffffc080206dbc (31 samples, 0.02%)0xffffffc080206dd4 (41 samples, 0.02%)0xffffffc080206dd8 (88 samples, 0.05%)0xffffffc080206ddc (31 samples, 0.02%)0xffffffc080206dde (30 samples, 0.02%)0xffffffc080206de2 (31 samples, 0.02%)0xffffffc080206de4 (33 samples, 0.02%)0xffffffc080206de8 (99 samples, 0.06%)0xffffffc080206dea (41 samples, 0.02%)0xffffffc080206dee (27 samples, 0.02%)0xffffffc080206df0 (33 samples, 0.02%)0xffffffc080206df4 (34 samples, 0.02%)0xffffffc080206df8 (81 samples, 0.05%)0xffffffc080206dfc (28 samples, 0.02%)0xffffffc080206dfe (30 samples, 0.02%)0xffffffc080206e02 (40 samples, 0.02%)0xffffffc080206e06 (35 samples, 0.02%)0xffffffc080206e08 (30 samples, 0.02%)0xffffffc080206e1a (48 samples, 0.03%)0xffffffc080206e1c (28 samples, 0.02%)0xffffffc080206e20 (36 samples, 0.02%)0xffffffc080206e22 (35 samples, 0.02%)0xffffffc080206f16 (29 samples, 0.02%)0xffffffc080206f1a (34 samples, 0.02%)0xffffffc080206f1e (35 samples, 0.02%)0xffffffc080206f22 (34 samples, 0.02%)0xffffffc080206f2a (19 samples, 0.01%)0xffffffc080206f34 (29 samples, 0.02%)0xffffffc080206f38 (22 samples, 0.01%)0xffffffc080206f3c (22 samples, 0.01%)0xffffffc080206f40 (18 samples, 0.01%)0xffffffc080206fae (23 samples, 0.01%)0xffffffc080206fb2 (20 samples, 0.01%)0xffffffc080206fb6 (28 samples, 0.02%)0xffffffc080206fba (18 samples, 0.01%)0xffffffc080206fbe (21 samples, 0.01%)0xffffffc080206fc2 (25 samples, 0.01%)0xffffffc080207028 (34 samples, 0.02%)0xffffffc080207030 (62 samples, 0.03%)0xffffffc080207034 (27 samples, 0.02%)0xffffffc080207038 (26 samples, 0.01%)0xffffffc08020703c (43 samples, 0.02%)0xffffffc080207040 (101 samples, 0.06%)0xffffffc080207044 (81 samples, 0.05%)0xffffffc080207048 (30 samples, 0.02%)0xffffffc08020704c (29 samples, 0.02%)0xffffffc08020704e (32 samples, 0.02%)0xffffffc080207052 (34 samples, 0.02%)0xffffffc080207056 (79 samples, 0.04%)0xffffffc080207058 (35 samples, 0.02%)0xffffffc08020705c (26 samples, 0.01%)0xffffffc08020705e (34 samples, 0.02%)0xffffffc080207062 (21 samples, 0.01%)0xffffffc080207064 (18 samples, 0.01%)0xffffffc08020707c (33 samples, 0.02%)0xffffffc08020707e (25 samples, 0.01%)0xffffffc080207080 (34 samples, 0.02%)0xffffffc080207082 (41 samples, 0.02%)0xffffffc080207084 (27 samples, 0.02%)0xffffffc080207086 (36 samples, 0.02%)0xffffffc080207088 (34 samples, 0.02%)0xffffffc08020c372 (27 samples, 0.02%)0xffffffc08021a960 (4,714 samples, 2.63%)0x..0xffffffc08021a962 (4,589 samples, 2.57%)0x..0xffffffc08021a964 (4,776 samples, 2.67%)0x..0xffffffc08021a968 (4,687 samples, 2.62%)0x..0xffffffc08021a96c (4,856 samples, 2.71%)0x..0xffffffc08021a970 (4,773 samples, 2.67%)0x..0xffffffc08021a972 (4,696 samples, 2.62%)0x..0xffffffc08021a976 (4,779 samples, 2.67%)0x..0xffffffc08021a97a (4,723 samples, 2.64%)0x..0xffffffc08021a97e (4,751 samples, 2.66%)0x..0xffffffc08021a980 (4,659 samples, 2.60%)0x..0xffffffc08021e156 (20 samples, 0.01%)0xffffffc08021e158 (19 samples, 0.01%)0xffffffc08021e15a (22 samples, 0.01%)0xffffffc08021e164 (18 samples, 0.01%)0xffffffc08021e16c (18 samples, 0.01%)0xffffffc0802204c4 (29 samples, 0.02%)0xffffffc0802204ca (22 samples, 0.01%)0xffffffc0802204d4 (21 samples, 0.01%)0xffffffc080223a56 (83 samples, 0.05%)0xffffffc080223a58 (84 samples, 0.05%)0xffffffc080223a5a (96 samples, 0.05%)0xffffffc080223a5e (84 samples, 0.05%)0xffffffc080223a60 (109 samples, 0.06%)0xffffffc080223a62 (89 samples, 0.05%)0xffffffc080232a32 (24 samples, 0.01%)0xffffffc080232a3e (24 samples, 0.01%)0xffffffc080232a40 (19 samples, 0.01%)0xffffffc080232a46 (22 samples, 0.01%)0xffffffc080232a7e (19 samples, 0.01%)0xffffffc080232a82 (28 samples, 0.02%)0xffffffc080232a86 (24 samples, 0.01%)0xffffffc080232c0e (20 samples, 0.01%)0xffffffc080232c58 (163 samples, 0.09%)0xffffffc080232c5c (99 samples, 0.06%)0xffffffc080232c7a (2,048 samples, 1.14%)0xffffffc080232c7c (3,730 samples, 2.08%)0..0xffffffc080232c80 (6,156 samples, 3.44%)0xf..0xffffffc080232c84 (3,792 samples, 2.12%)0..0xffffffc080232c88 (3,677 samples, 2.06%)0..0xffffffc080232c8c (3,765 samples, 2.10%)0..0xffffffc080232c90 (4,293 samples, 2.40%)0x..0xffffffc08024c2aa (91 samples, 0.05%)0xffffffc08024c2ae (90 samples, 0.05%)0xffffffc08024c2b2 (100 samples, 0.06%)0xffffffc08024c2b6 (85 samples, 0.05%)0xffffffc08024c2b8 (118 samples, 0.07%)0xffffffc08024c2ba (322 samples, 0.18%)0xffffffc08024c2be (348 samples, 0.19%)0xffffffc08024c2c2 (306 samples, 0.17%)0xffffffc08024c2c6 (331 samples, 0.19%)0xffffffc08024c2c8 (2,609 samples, 1.46%)0xffffffc08024c2ca (2,347 samples, 1.31%)0xffffffc08024c2cc (2,149 samples, 1.20%)0xffffffc08024c2ce (2,198 samples, 1.23%)0xffffffc08024c2d2 (2,219 samples, 1.24%)0xffffffc08024c2d6 (2,202 samples, 1.23%)0xffffffc08024c2d8 (2,334 samples, 1.30%)0xffffffc08024c2da (2,200 samples, 1.23%)0xffffffc08024c2de (2,274 samples, 1.27%)0xffffffc08024c2e0 (2,295 samples, 1.28%)0xffffffc08024c2ea (349 samples, 0.20%)0xffffffc08024c2ec (329 samples, 0.18%)0xffffffc08024c2ee (241 samples, 0.13%)0xffffffc08024c2f0 (233 samples, 0.13%)0xffffffc08024c2f2 (255 samples, 0.14%)0xffffffc08024c2f4 (221 samples, 0.12%)0xffffffc08024c2f6 (239 samples, 0.13%)0xffffffc08024c2f8 (107 samples, 0.06%)0xffffffc08024c2fa (103 samples, 0.06%)0xffffffc08024c2fc (109 samples, 0.06%)0xffffffc08024c300 (85 samples, 0.05%)0xffffffc08024c302 (97 samples, 0.05%)0xffffffc08024c304 (89 samples, 0.05%)0xffffffc08024c308 (85 samples, 0.05%)0xffffffc08024c30c (70 samples, 0.04%)0xffffffc08024c310 (72 samples, 0.04%)0xffffffc08024c314 (76 samples, 0.04%)0xffffffc08024c316 (80 samples, 0.04%)0xffffffc08024c31a (66 samples, 0.04%)0xffffffc08024c31e (97 samples, 0.05%)0xffffffc08024c34e (102 samples, 0.06%)0xffffffc08024c350 (85 samples, 0.05%)0xffffffc08024c352 (105 samples, 0.06%)0xffffffc08024c354 (108 samples, 0.06%)0xffffffc08024c35c (21 samples, 0.01%)0xffffffc08024c39e (89 samples, 0.05%)0xffffffc08024c3a0 (100 samples, 0.06%)0xffffffc08024c3a2 (85 samples, 0.05%)0xffffffc08024c3a4 (77 samples, 0.04%)0xffffffc08024c3a8 (88 samples, 0.05%)0xffffffc08024c3ac (82 samples, 0.05%)0xffffffc08024c3ae (93 samples, 0.05%)0xffffffc08024c3b4 (18 samples, 0.01%)0xffffffc08024c416 (31 samples, 0.02%)0xffffffc08024c43e (28 samples, 0.02%)0xffffffc08024c444 (18 samples, 0.01%)0xffffffc08024c47a (22 samples, 0.01%)0xffffffc08024c47e (19 samples, 0.01%)0xffffffc08024c496 (32 samples, 0.02%)0xffffffc08024c49a (24 samples, 0.01%)0xffffffc08024c4ae (18 samples, 0.01%)0xffffffc08024c500 (19 samples, 0.01%)0xffffffc08024c504 (27 samples, 0.02%)0xffffffc08024c506 (19 samples, 0.01%)0xffffffc08024c518 (29 samples, 0.02%)0xffffffc08024c73e (19 samples, 0.01%)0xffffffc08024c762 (19 samples, 0.01%)0xffffffc08024c780 (19 samples, 0.01%)0xffffffc08024c782 (20 samples, 0.01%)0xffffffc08024c888 (108 samples, 0.06%)0xffffffc08024c88c (83 samples, 0.05%)0xffffffc08024c890 (114 samples, 0.06%)0xffffffc08024c894 (92 samples, 0.05%)0xffffffc08024c898 (99 samples, 0.06%)0xffffffc08024c89a (93 samples, 0.05%)0xffffffc08024c89c (102 samples, 0.06%)0xffffffc08024cac2 (91 samples, 0.05%)0xffffffc08024cac6 (96 samples, 0.05%)0xffffffc08024caca (88 samples, 0.05%)0xffffffc08024cacc (113 samples, 0.06%)0xffffffc08024cad0 (100 samples, 0.06%)0xffffffc08024cad2 (99 samples, 0.06%)0xffffffc08024cad4 (93 samples, 0.05%)0xffffffc08024cad8 (80 samples, 0.04%)0xffffffc08024cada (84 samples, 0.05%)0xffffffc08024cadc (107 samples, 0.06%)0xffffffc08024cae0 (96 samples, 0.05%)0xffffffc08024cae4 (93 samples, 0.05%)0xffffffc08024cae6 (109 samples, 0.06%)0xffffffc08024cae8 (94 samples, 0.05%)0xffffffc08024caec (102 samples, 0.06%)0xffffffc08024caee (93 samples, 0.05%)0xffffffc08024ee22 (19 samples, 0.01%)0xffffffc08024ee26 (19 samples, 0.01%)0xffffffc08024ee32 (19 samples, 0.01%)0xffffffc08024eeba (18 samples, 0.01%)0xffffffc08024eebe (18 samples, 0.01%)0xffffffc08024eec4 (20 samples, 0.01%)0xffffffc08024eed2 (20 samples, 0.01%)0xffffffc08024f00e (20 samples, 0.01%)0xffffffc08024f43c (19 samples, 0.01%)0xffffffc08024f43e (20 samples, 0.01%)0xffffffc08024f444 (31 samples, 0.02%)0xffffffc08024f448 (21 samples, 0.01%)0xffffffc08024f454 (18 samples, 0.01%)0xffffffc08024f45a (20 samples, 0.01%)0xffffffc08024f45e (26 samples, 0.01%)0xffffffc08024f460 (22 samples, 0.01%)0xffffffc08024f462 (29 samples, 0.02%)0xffffffc08024f49c (23 samples, 0.01%)0xffffffc08024f52e (21 samples, 0.01%)0xffffffc08024f534 (20 samples, 0.01%)0xffffffc08024f540 (18 samples, 0.01%)0xffffffc08024f88e (34 samples, 0.02%)0xffffffc08024f892 (27 samples, 0.02%)0xffffffc08024f894 (33 samples, 0.02%)0xffffffc08024f896 (33 samples, 0.02%)0xffffffc08024f89a (39 samples, 0.02%)0xffffffc08024f89c (32 samples, 0.02%)0xffffffc08024f89e (28 samples, 0.02%)0xffffffc08024f8a0 (46 samples, 0.03%)0xffffffc08024f8a2 (39 samples, 0.02%)0xffffffc08024f8a6 (37 samples, 0.02%)0xffffffc08024f8a8 (31 samples, 0.02%)0xffffffc08024f8aa (27 samples, 0.02%)0xffffffc08024f8ac (29 samples, 0.02%)0xffffffc08024f8ae (40 samples, 0.02%)0xffffffc08024f8b0 (41 samples, 0.02%)0xffffffc08024f8b2 (38 samples, 0.02%)0xffffffc08024f8b6 (40 samples, 0.02%)0xffffffc08024f8c6 (25 samples, 0.01%)0xffffffc08024f8ca (39 samples, 0.02%)0xffffffc08024f8ce (35 samples, 0.02%)0xffffffc08024f8d0 (26 samples, 0.01%)0xffffffc08024f8ea (36 samples, 0.02%)0xffffffc08024facc (21 samples, 0.01%)0xffffffc08024face (27 samples, 0.02%)0xffffffc08024fad0 (24 samples, 0.01%)0xffffffc08024fad2 (28 samples, 0.02%)0xffffffc08024fad6 (18 samples, 0.01%)0xffffffc08024fada (20 samples, 0.01%)0xffffffc08024fade (22 samples, 0.01%)0xffffffc08024fae0 (23 samples, 0.01%)0xffffffc08024fae4 (21 samples, 0.01%)0xffffffc08024fae6 (22 samples, 0.01%)0xffffffc08024fc74 (19 samples, 0.01%)0xffffffc08024fc76 (24 samples, 0.01%)0xffffffc08024fc78 (21 samples, 0.01%)0xffffffc08024fc7a (19 samples, 0.01%)0xffffffc08024fc7e (25 samples, 0.01%)0xffffffc08024fc82 (21 samples, 0.01%)0xffffffc08024fc8a (18 samples, 0.01%)0xffffffc08024fc8c (29 samples, 0.02%)0xffffffc08024fcd8 (19 samples, 0.01%)0xffffffc08024fcda (29 samples, 0.02%)0xffffffc08024fcde (21 samples, 0.01%)0xffffffc08024fce6 (21 samples, 0.01%)0xffffffc08024fcea (18 samples, 0.01%)0xffffffc08024fcee (22 samples, 0.01%)0xffffffc08024fcf0 (20 samples, 0.01%)0xffffffc0802547ec (21 samples, 0.01%)0xffffffc0802547f0 (20 samples, 0.01%)0xffffffc080254852 (18 samples, 0.01%)0xffffffc080254870 (18 samples, 0.01%)0xffffffc0802548ea (20 samples, 0.01%)0xffffffc0802548f0 (20 samples, 0.01%)0xffffffc0802548f2 (22 samples, 0.01%)0xffffffc0802551aa (21 samples, 0.01%)0xffffffc0802551bc (22 samples, 0.01%)0xffffffc080296484 (276 samples, 0.15%)0xffffffc08020409d (38 samples, 0.02%)0xffffffc08029aa05 (53 samples, 0.03%)0xffffffc08029b13a (20 samples, 0.01%)0xffffffc08029b14e (28 samples, 0.02%)0xffffffc08029b15e (18 samples, 0.01%)0xffffffc08029b16a (22 samples, 0.01%)0xffffffc0803a7482 (62 samples, 0.03%)0xffffffc0803a7484 (61 samples, 0.03%)0xffffffc0803a7488 (52 samples, 0.03%)0xffffffc0803a748a (52 samples, 0.03%)0xffffffc0803a748c (68 samples, 0.04%)0xffffffc0802a43d9 (463 samples, 0.26%)0xffffffc0802a9d82 (22 samples, 0.01%)0xffffffc0802a9d84 (25 samples, 0.01%)0xffffffc0802a9d88 (21 samples, 0.01%)0xffffffc0802a9d8a (25 samples, 0.01%)0xffffffc0802a9d8e (24 samples, 0.01%)0xffffffc0802a9d94 (30 samples, 0.02%)0xffffffc0802a9d98 (20 samples, 0.01%)0xffffffc0802a9d9c (19 samples, 0.01%)0xffffffc0802a9da0 (28 samples, 0.02%)0xffffffc0802a9da4 (22 samples, 0.01%)0xffffffc0802a9da8 (20 samples, 0.01%)0xffffffc0802a9dae (29 samples, 0.02%)0xffffffc0802ab5c2 (19 samples, 0.01%)0xffffffc0802ab5c4 (27 samples, 0.02%)0xffffffc0802ab5c6 (24 samples, 0.01%)0xffffffc0802ab5ca (20 samples, 0.01%)0xffffffc0802ab5ce (24 samples, 0.01%)0xffffffc0802ab5d2 (22 samples, 0.01%)0xffffffc0802ab5d6 (23 samples, 0.01%)0xffffffc0802ab5da (18 samples, 0.01%)0xffffffc0802ab5de (23 samples, 0.01%)0xffffffc0802ab5e2 (31 samples, 0.02%)0xffffffc0802ab5e4 (21 samples, 0.01%)0xffffffc0802acfab (23 samples, 0.01%)0xffffffc0802e1455 (34 samples, 0.02%)0xffffffc0803582f8 (82 samples, 0.05%)0xffffffc0803582fa (92 samples, 0.05%)0xffffffc0803582fc (71 samples, 0.04%)0xffffffc0803582fe (60 samples, 0.03%)0xffffffc080358300 (93 samples, 0.05%)0xffffffc080358304 (99 samples, 0.06%)0xffffffc080358306 (105 samples, 0.06%)0xffffffc08035830a (112 samples, 0.06%)0xffffffc08035830e (75 samples, 0.04%)0xffffffc080358328 (88 samples, 0.05%)0xffffffc08035832a (90 samples, 0.05%)0xffffffc080358336 (18 samples, 0.01%)0xffffffc080358350 (18 samples, 0.01%)0xffffffc080358356 (18 samples, 0.01%)0xffffffc080358360 (29 samples, 0.02%)0xffffffc080358366 (20 samples, 0.01%)0xffffffc08035836c (18 samples, 0.01%)0xffffffc08035836e (18 samples, 0.01%)0xffffffc0803a7438 (95 samples, 0.05%)0xffffffc0803a743a (43 samples, 0.02%)0xffffffc0803a743c (44 samples, 0.02%)0xffffffc0803a7440 (57 samples, 0.03%)0xffffffc0803a7444 (46 samples, 0.03%)0xffffffc0803a7448 (52 samples, 0.03%)0xffffffc0803a744c (43 samples, 0.02%)0xffffffc0803a7462 (18 samples, 0.01%)0xffffffc0803a7466 (55 samples, 0.03%)0xffffffc0803a7468 (46 samples, 0.03%)0xffffffc0803a746c (35 samples, 0.02%)0xffffffc0803a7470 (55 samples, 0.03%)0xffffffc0803a7474 (57 samples, 0.03%)0xffffffc0803a7478 (64 samples, 0.04%)0xffffffc0803a747c (29 samples, 0.02%)0xffffffc0803a7480 (29 samples, 0.02%)0xffffffc0803a7482 (3,510 samples, 1.96%)0..0xffffffc0803a7484 (3,808 samples, 2.13%)0..0xffffffc0803a7488 (3,581 samples, 2.00%)0..0xffffffc0803a748a (3,572 samples, 2.00%)0..0xffffffc0803a748c (3,500 samples, 1.96%)0..0xffffffc0803a7490 (41 samples, 0.02%)0xffffffc0803a7492 (42 samples, 0.02%)0xffffffc0803a7496 (35 samples, 0.02%)0xffffffc0803a749a (27 samples, 0.02%)0xffffffc0803a749e (23 samples, 0.01%)0xffffffc0803a74aa (18 samples, 0.01%)0xffffffc0803a74b4 (20 samples, 0.01%)0xffffffc0803a74ba (63 samples, 0.04%)0xffffffc0803a74bc (55 samples, 0.03%)0xffffffc0803a74be (24 samples, 0.01%)0xffffffc0803a74c2 (26 samples, 0.01%)0xffffffc0803a74c4 (21 samples, 0.01%)0xffffffc0803a74c8 (21 samples, 0.01%)0xffffffc0803a74cc (20 samples, 0.01%)0xffffffc0803a74d0 (23 samples, 0.01%)0xffffffc0803a74d6 (25 samples, 0.01%)0xffffffc0803a74dc (19 samples, 0.01%)0xffffffc0803a751e (32 samples, 0.02%)0xffffffc0803a7522 (29 samples, 0.02%)0xffffffc0803a7524 (22 samples, 0.01%)0xffffffc0803a7526 (18 samples, 0.01%)0xffffffc0803a752a (20 samples, 0.01%)0xffffffc0803a752c (21 samples, 0.01%)0xffffffc0803a7530 (23 samples, 0.01%)0xffffffc0803a753c (24 samples, 0.01%)0xffffffc0803a7544 (71 samples, 0.04%)0xffffffc0803a7546 (68 samples, 0.04%)0xffffffc0803a754a (72 samples, 0.04%)0xffffffc0803a754e (80 samples, 0.04%)0xffffffc0803a7550 (72 samples, 0.04%)0xffffffc0803a7554 (65 samples, 0.04%)0xffffffc0803a7558 (75 samples, 0.04%)0xffffffc0803a755c (65 samples, 0.04%)0xffffffc0803a7560 (69 samples, 0.04%)0xffffffc0803a7562 (81 samples, 0.05%)0xffffffc0803a7566 (24 samples, 0.01%)0xffffffc0803a7568 (22 samples, 0.01%)0xffffffc0803a756c (24 samples, 0.01%)0xffffffc0803a756e (21 samples, 0.01%)0xffffffc0803a757c (20 samples, 0.01%)0xffffffc0803a758e (18 samples, 0.01%)0xffffffc0803a7594 (22 samples, 0.01%)0xffffffc0803a7598 (26 samples, 0.01%)0xffffffc0803a75a4 (20 samples, 0.01%)0xffffffc0803a75a8 (19 samples, 0.01%)0xffffffc0803a75aa (18 samples, 0.01%)0xffffffc0803a75ae (19 samples, 0.01%)0xffffffc0803a75b2 (20 samples, 0.01%)0xffffffc0803a75b8 (24 samples, 0.01%)0xffffffc0803a75be (21 samples, 0.01%)0xffffffc0803a75c0 (20 samples, 0.01%)0xffffffc0803a75c4 (18 samples, 0.01%)0xffffffc0803a76b8 (20 samples, 0.01%)0xffffffc0803a76ba (21 samples, 0.01%)0xffffffc0803a76be (22 samples, 0.01%)0xffffffc0803a76c0 (19 samples, 0.01%)0xffffffc0803a76c2 (23 samples, 0.01%)0xffffffc0803a7974 (22 samples, 0.01%)0xffffffc0803a79c0 (1,292 samples, 0.72%)0xffffffc0803a79c2 (1,287 samples, 0.72%)0xffffffc0803a79c4 (1,270 samples, 0.71%)0xffffffc0803a79c8 (18 samples, 0.01%)0xffffffc0803a79ea (124 samples, 0.07%)0xffffffc0803a79ee (48 samples, 0.03%)0xffffffc0803cec3f (43 samples, 0.02%)0xffffffc0804c0fff (19 samples, 0.01%)0xffffffc0804c43ff (25 samples, 0.01%)0xffffffc0802204c4 (87 samples, 0.05%)0xffffffc0802204c6 (67 samples, 0.04%)0xffffffc0802204c8 (53 samples, 0.03%)0xffffffc0802204ca (72 samples, 0.04%)0xffffffc0802204cc (50 samples, 0.03%)0xffffffc0802204ce (61 samples, 0.03%)0xffffffc0802204d0 (68 samples, 0.04%)0xffffffc0802204d2 (63 samples, 0.04%)0xffffffc0802204d4 (75 samples, 0.04%)0xffffffc0802204d6 (65 samples, 0.04%)0xffffffc0802204d8 (60 samples, 0.03%)0xffffffc0802204dc (75 samples, 0.04%)0xffffffc0802204e0 (53 samples, 0.03%)0xffffffc0802204e2 (52 samples, 0.03%)0xffffffc080220524 (58 samples, 0.03%)0xffffffc080220528 (60 samples, 0.03%)0xffffffc080220540 (49 samples, 0.03%)0xffffffc080220544 (52 samples, 0.03%)0xffffffc080220546 (54 samples, 0.03%)0xffffffc080220548 (63 samples, 0.04%)0xffffffc08022054c (61 samples, 0.03%)0xffffffc08022054e (71 samples, 0.04%)0xffffffc080220552 (65 samples, 0.04%)0xffffffc080220554 (58 samples, 0.03%)0xffffffc080220556 (56 samples, 0.03%)0xffffffc080220558 (66 samples, 0.04%)0xffffffc08022055c (59 samples, 0.03%)0xffffffc080220560 (73 samples, 0.04%)0xffffffc080220562 (73 samples, 0.04%)0xffffffc08024ee18 (64 samples, 0.04%)0xffffffc08024ee1a (49 samples, 0.03%)0xffffffc08024ee1c (66 samples, 0.04%)0xffffffc08024ee1e (66 samples, 0.04%)0xffffffc08024ee22 (57 samples, 0.03%)0xffffffc08024ee26 (117 samples, 0.07%)0xffffffc08024ee28 (52 samples, 0.03%)0xffffffc08024ee2a (66 samples, 0.04%)0xffffffc08024ee2c (60 samples, 0.03%)0xffffffc08024ee32 (62 samples, 0.03%)0xffffffc08024ee36 (58 samples, 0.03%)0xffffffc08024ee38 (70 samples, 0.04%)0xffffffc0804c77ff (2,832 samples, 1.58%)0xffffffc0808f9bff (18 samples, 0.01%)0xffffffc0808f9c4f (18 samples, 0.01%)0xffffffc0803a76b8 (20 samples, 0.01%)0xffffffc0803a76be (27 samples, 0.02%)0xffffffc0803a76c0 (21 samples, 0.01%)0xffffffc08095050f (255 samples, 0.14%)0xffffffc0809dbfff (29 samples, 0.02%)0xffffffc080a2cfff (18 samples, 0.01%)0xffffffc080a2efff (24 samples, 0.01%)all (178,906 samples, 100%) \ No newline at end of file diff --git a/docs/flamegraphs/target__starry-syscall-harness__perf__riscv64__latest__qperf__flamegraph.svg b/docs/flamegraphs/target__starry-syscall-harness__perf__riscv64__latest__qperf__flamegraph.svg new file mode 100644 index 0000000000..b780d37803 --- /dev/null +++ b/docs/flamegraphs/target__starry-syscall-harness__perf__riscv64__latest__qperf__flamegraph.svg @@ -0,0 +1,491 @@ +StarryOS qperf Flame Graph Reset ZoomSearch 0x800065ae (110 samples, 8.76%)0x800065ae0x8000b04e (5 samples, 0.40%)0x8000b160 (6 samples, 0.48%)_RINvMNtCslaH5yrbsIDe_14virtio_drivers5queueINtB3_9VirtQueueNtNtCs7o8tY3fp65W_9ax_driver6virtio13VirtIoHalImplKj10_E19add_notify_wait_popNtNtNtB5_9transport3pci12PciTransportEBZ_+0x2ec (7 samples, 0.56%)_RNvMs1_NtCs3CCktNovUfS_7ax_task9run_queueINtB5_18CurrentRunQueueRefNtCsgbat0RU8KR6_15ax_kernel_guard16NoPreemptIrqSaveE13yield_currentB7_+0xac (5 samples, 0.40%)_RNvNtCs5hyz25ijnDh_17compiler_builtins3mem6memcpy+0x4a (6 samples, 0.48%)_start+0x1000 (878 samples, 69.96%)_start+0x1000_start+0x10cc (5 samples, 0.40%)all (1,255 samples, 100%) \ No newline at end of file diff --git a/docs/harness-os-knowledge-graph.md b/docs/harness-os-knowledge-graph.md new file mode 100644 index 0000000000..cbe84330cb --- /dev/null +++ b/docs/harness-os-knowledge-graph.md @@ -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 +``` + +也可以让当前 tgoskits GUI 扫描相邻的本地教学仓库: + +```text +GET /api/knowledge-graph?repo_root=/home/cg24/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 模式。 diff --git a/docs/qperf-callchain-flamegraph-design.md b/docs/qperf-callchain-flamegraph-design.md new file mode 100644 index 0000000000..01d1d79883 --- /dev/null +++ b/docs/qperf-callchain-flamegraph-design.md @@ -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。 diff --git a/docs/qperf-callchain-validation-report.md b/docs/qperf-callchain-validation-report.md new file mode 100644 index 0000000000..7d9d3752b7 --- /dev/null +++ b/docs/qperf-callchain-validation-report.md @@ -0,0 +1,346 @@ +# qperf 深调用栈火焰图优化验收报告 + +## 1. 验收目标 + +本轮验证要回答的问题: + +* qperf 火焰图浅是否确认为“只有 PC/TB leaf 采样”。 +* `--full-stack` / `--perf-callchain fp` 是否能生成真实纵向调用链。 +* folded stack 是否保留完整 Rust demangled 路径。 +* blk/net workload 是否能看到 syscall、fs/net、virtio、allocator、BTreeMap、memcpy/memmove 等路径。 +* 默认 leaf profile 是否保持兼容。 + +## 2. 验收环境 + +| 项目 | 值 | +| --- | --- | +| 仓库 commit | `34d0e92d5` | +| host | WSL2 Linux `5.15.167.4-microsoft-standard-WSL2` | +| CPU | Intel Core i7-14650HX,24 vCPU | +| QEMU | `qemu-system-riscv64` 10.2.1 | +| guest arch | `riscv64` | +| 运行方式 | 直接在宿主 WSL 环境运行,不在 Docker 中运行。本轮按用户已安装宿主 QEMU 的环境继续验证。 | +| host perf | 未启用 | +| qperf metrics | net case 启用,blk full-stack case 未启用 | + +当前工作区还包含本轮代码改动与此前未跟踪的文档/图片文件,验收报告只引用确认存在的 `target/qperf-callchain-validation/` 产物。 + +full-stack 构建后的 ELF 已做反汇编抽查,`VirtQueue::add_notify_wait_pop` prologue 中存在: + +```text +sd ra, 0x88(sp) +sd s0, 0x80(sp) +addi s0, sp, 0x90 +``` + +证据文件:`target/qperf-callchain-validation/full-stack-frame-pointer-objdump.txt`。这说明 `-Cforce-frame-pointers=yes` 已经进入实际 kernel 构建,而不是只停留在 CLI 参数层面。 + +## 3. 诊断结论 + +旧 blk 产物: + +```bash +awk -F';' '{print NF}' target/qperf-host-rerun/blk-harness/perf/riscv64/latest/qperf/stack.folded | sort -n | uniq -c +``` + +结果为: + +```text +623 1 +``` + +`resolve.stats.json` 显示旧 raw 格式为 v2,`raw_records=1292`、`total_frames=1292`,说明旧样本基本只有 leaf PC。根因是采样侧没有真实 callchain,而不是 flamegraph SVG 样式、采样频率或 analyzer 把多帧压扁。 + +## 4. 实现与验证矩阵 + +| 验收项 | 结果 | 证据路径 | 备注 | +| --- | --- | --- | --- | +| `cargo starry perf --help` 暴露 callchain 参数 | PASS | `target/qperf-callchain-validation/cargo-starry-perf-help.txt` | 包含 `--full-stack`、`--perf-callchain`、`--perf-debuginfo`、`--perf-force-frame-pointers`。 | +| harness `perf-profile --help` 暴露 callchain 参数 | PASS | `target/qperf-callchain-validation/harness-perf-profile-help.txt` | 包含 `--callchain`、`--full-stack`。 | +| leaf baseline 兼容 | PASS | `target/qperf-callchain-validation/blk-leaf/perf/riscv64/latest/report.json` | 默认 leaf 仍为一层栈。 | +| blk full-stack 深栈 | PASS | `target/qperf-callchain-validation/blk-full-stack/perf/riscv64/latest/qperf/stack.folded` | 579 条 workload 样本中 578 条为多帧。 | +| net full-stack 深栈 | PASS | `target/qperf-callchain-validation/net-full-stack/perf/riscv64/latest/qperf/stack.folded` | 661 条 workload 样本中 652 条为多帧。 | +| `stack-depth-summary.csv` | PASS | `target/qperf-callchain-validation/*/perf/riscv64/latest/qperf/stack-depth-summary.csv` | 输出 raw FP trace depth 分布。 | +| `hotspots.csv` 深栈百分比 | PASS | `target/qperf-callchain-validation/blk-full-stack/perf/riscv64/latest/hotspots.csv` | 函数热点百分比已按帧总量计算。 | +| net qperf metrics 合入 report | PASS | `target/qperf-callchain-validation/net-full-stack/perf/riscv64/latest/report.json` | `workload_metrics.values` 包含 virtio/net counters。 | +| logical stack fallback | N/A | 无 | 因真实 FP unwind 已可用,本轮未实现 logical stack;CLI 会明确拒绝该模式。 | + +## 5. leaf baseline + +命令: + +```bash +cargo starry perf \ + --case blk-leaf \ + --output-dir target/qperf-callchain-validation/blk-leaf \ + --host-time \ + --timeout 120 \ + --workload-timeout 75 \ + --start-marker QPERF_BEGIN \ + --stop-marker QPERF_END \ + --shell-init-cmd 'echo QPERF_BEGIN:blk; dd if=/usr/bin/lto-dump of=/dev/null bs=64k; echo QPERF_END:blk' \ + --no-truncate +``` + +结果: + +| 指标 | 值 | +| --- | ---: | +| result | `ok` | +| dd bytes | 53,601,104 | +| dd elapsed | 5.764698 s | +| dd throughput | 9,298,163 B/s | +| marker window | 5.832138317 s | +| boot samples excluded | 154 | +| selected records | 577 | +| selected multi-frame records | 0 | +| raw max depth | 1 | + +depth 分布: + +```text +depth,samples +1,577 +``` + +结论:默认 leaf 模式保持旧行为和低开销,但不会生成纵向火焰图。 + +## 6. blk full-stack + +命令: + +```bash +cargo starry perf \ + --case blk-full-stack \ + --output-dir target/qperf-callchain-validation/blk-full-stack \ + --full-stack \ + --host-time \ + --timeout 180 \ + --workload-timeout 120 \ + --start-marker QPERF_BEGIN \ + --stop-marker QPERF_END \ + --shell-init-cmd 'echo QPERF_BEGIN:blk; dd if=/usr/bin/lto-dump of=/dev/null bs=64k; echo QPERF_END:blk' \ + --no-truncate +``` + +结果: + +| 指标 | 值 | +| --- | ---: | +| result | `incomplete` | +| dd bytes | 53,601,104 | +| dd elapsed | 5.779240 s | +| dd throughput | 9,274,766 B/s | +| marker window | 5.845178559 s | +| boot samples excluded | 160 | +| post-window samples excluded | 1222 | +| selected records | 579 | +| selected multi-frame records | 578 | +| samples with FP | 578 | +| unwind success | 578 | +| report avg symbol depth | 43.887737478 | +| raw max depth | 18 | + +`stack-depth-summary.csv`: + +```text +depth,samples +1,1 +4,2 +5,2 +6,39 +7,2 +8,6 +9,42 +10,52 +11,44 +12,77 +13,41 +14,72 +15,183 +16,8 +17,7 +18,1 +``` + +`awk -F';' '{print NF}' .../stack.folded` 能看到 folded 符号层数最高到 72。层数大于 raw depth 的原因是 analyzer 通过 debug info 展开了 inline frame。 + +blk 关键路径已经能在 `stack.folded` 中看到: + +```text +starry_kernel::syscall::fs::io::sys_read + -> ax_fs_ng / rsext4 + -> ax_driver::block::binding::Block::read_blocks_wait + -> rd_block::CmdQueue::read_blocks_blocking + -> ax_driver::virtio::block::BlockQueue::submit_request + -> virtio_drivers::device::blk::VirtIOBlk::read_blocks + -> virtio_drivers::queue::VirtQueue::add_notify_wait_pop +``` + +top categories: + +| category | samples | percent | +| --- | ---: | ---: | +| block_io_path | 434 | 74.9568% | +| memcpy | 179 | 30.9154% | +| virtio_notify_kick | 176 | 30.3972% | +| virtqueue_add_notify_wait_pop | 173 | 29.8791% | +| lock_mutex_wait | 82 | 14.1623% | + +`result=incomplete` 的原因是 QMP stop 后 QEMU 在等待退出阶段被超时清理,导致 plugin shutdown summary 不完整;marker window、raw sample、folded stack 与 report 已生成。本项是 stop/shutdown 可靠性问题,不影响“是否能生成深调用栈”的结论。 + +## 7. net full-stack + +命令: + +```bash +cargo starry perf \ + --case net-full-stack \ + --output-dir target/qperf-callchain-validation/net-full-stack \ + --full-stack \ + --qperf-metrics \ + --host-time \ + --timeout 300 \ + --workload-timeout 240 \ + --start-marker QPERF_BEGIN \ + --stop-marker QPERF_END \ + --shell-init-cmd 'echo reset > /proc/qperf_metrics; echo QPERF_BEGIN:net; wget -O /dev/null http://10.0.2.2:8000/tmp/axbuild/rootfs/rootfs-riscv64-alpine.img.tar.xz; cat /proc/qperf_metrics; echo QPERF_END:net' \ + --no-truncate +``` + +结果: + +| 指标 | 值 | +| --- | ---: | +| result | `ok` | +| wget bytes | 63,543,705 | +| wget elapsed | 6.688766343 s | +| wget throughput | 9,500,063 B/s | +| marker window | 6.688766343 s | +| boot samples excluded | 159 | +| selected records | 661 | +| selected multi-frame records | 652 | +| samples with FP | 658 | +| unwind success | 652 | +| report avg symbol depth | 50.69591528 | +| raw max depth | 17 | + +`stack-depth-summary.csv`: + +```text +depth,samples +1,9 +3,3 +4,2 +5,1 +6,34 +7,7 +8,12 +9,8 +10,58 +11,136 +12,62 +13,93 +14,183 +15,45 +16,5 +17,3 +``` + +net 关键路径已经能在 `stack.folded` 中看到: + +```text +starry_kernel::syscall::fs::io::sys_readv + -> starry_kernel::file::net::Socket::read + -> ax_net_ng::SocketOps::recv + -> ax_net_ng::poll_interfaces + -> ax_net_ng::device::driver::RdNetDriver::prefetch_rx_packets + -> rd_net::RxQueue::receive / reclaim_packet + -> dma_api::array::ContiguousArray::read_with + -> compiler_builtins::mem::memcpy +``` + +net counters 已进入 `report.json.workload_metrics.values`: + +| counter | 值 | +| --- | ---: | +| virtqueue_add_count | 47,855 | +| virtio_notify_kick_count | 47,855 | +| virtqueue_pop_complete_count | 47,791 | +| virtqueue_add_notify_wait_pop_count | 1,177 | +| virtqueue_depth_max | 63 | +| virtio_net_rx_packets | 44,139 | +| virtio_net_rx_bytes | 65,935,922 | +| virtio_net_rx_copy_within_count | 44,139 | +| virtio_net_rx_copy_within_bytes | 65,935,922 | +| virtio_net_tx_packets | 2,476 | +| virtio_net_tx_staging_copy_bytes | 148,700 | +| virtio_net_inflight_insert_count | 46,678 | +| virtio_net_inflight_remove_count | 46,614 | +| virtio_net_inflight_get_count | 46,614 | + +top categories: + +| category | samples | percent | +| --- | ---: | ---: | +| net_rx_tx_path | 441 | 66.7171% | +| memcpy | 233 | 35.2496% | +| lock_mutex_wait | 100 | 15.1286% | +| memmove | 65 | 9.8336% | +| net_inflight_btree | 63 | 9.5310% | + +## 8. 证据文件 + +| 用途 | 路径 | +| --- | --- | +| blk leaf report | `target/qperf-callchain-validation/blk-leaf/perf/riscv64/latest/report.json` | +| blk leaf depth | `target/qperf-callchain-validation/blk-leaf/perf/riscv64/latest/qperf/stack-depth-summary.csv` | +| blk full-stack report | `target/qperf-callchain-validation/blk-full-stack/perf/riscv64/latest/report.json` | +| blk full-stack flamegraph | `target/qperf-callchain-validation/blk-full-stack/perf/riscv64/latest/qperf/flamegraph.svg` | +| blk full-stack workload flamegraph | `target/qperf-callchain-validation/blk-full-stack/perf/riscv64/latest/qperf/flamegraph.workload.svg` | +| blk full-stack folded | `target/qperf-callchain-validation/blk-full-stack/perf/riscv64/latest/qperf/stack.folded` | +| blk full-stack depth | `target/qperf-callchain-validation/blk-full-stack/perf/riscv64/latest/qperf/stack-depth-summary.csv` | +| net full-stack report | `target/qperf-callchain-validation/net-full-stack/perf/riscv64/latest/report.json` | +| net full-stack flamegraph | `target/qperf-callchain-validation/net-full-stack/perf/riscv64/latest/qperf/flamegraph.svg` | +| net full-stack workload flamegraph | `target/qperf-callchain-validation/net-full-stack/perf/riscv64/latest/qperf/flamegraph.workload.svg` | +| net full-stack folded | `target/qperf-callchain-validation/net-full-stack/perf/riscv64/latest/qperf/stack.folded` | +| net full-stack depth | `target/qperf-callchain-validation/net-full-stack/perf/riscv64/latest/qperf/stack-depth-summary.csv` | +| full-stack FP 反汇编抽查 | `target/qperf-callchain-validation/full-stack-frame-pointer-objdump.txt` | + +## 9. 验证命令 + +已执行: + +```bash +cargo fmt +cargo clippy --manifest-path tools/qperf/Cargo.toml -- -D warnings +cargo clippy --manifest-path tools/qperf/analyzer/Cargo.toml -- -D warnings +cargo clippy -p axbuild -- -D warnings +python3 -m py_compile tools/starry-syscall-harness/harness.py +``` + +其中 qperf clippy 初次发现两个手写 `% 8 == 0` 对齐判断,已改为 `is_multiple_of(8)` 后通过。 + +## 10. 局限性 + +* 默认模式仍是 leaf;只有 `--full-stack` 或 `--perf-callchain fp --perf-force-frame-pointers --perf-debuginfo` 才能期待深栈。 +* 当前 unwind 只覆盖 kernel symbol;用户态栈与用户 ELF symbol 尚未纳入。 +* trap、异常入口、任务切换、汇编 trampoline 仍可能截断调用链。 +* `report.json.callchain.avg_depth` 是 symbolized/inlined frame 平均层数;raw FP 地址深度以 `stack-depth-summary.csv` 为准。 +* `hotspot_categories.csv` 是 inclusive stack 归类,深栈下 allocator/scheduler 可能因为共同上层路径被频繁命中,不能按互斥 CPU 时间解读。 +* blk full-stack 本次 QEMU stop 结果为 `incomplete`,需要后续继续改善 QMP stop 与 plugin shutdown flush。 +* host perf/PMU 未启用,本报告不包含 host PMU 结论。 +* vsock 未在本轮补测;没有 `/dev/vhost-vsock` 的 host 不能做定量结论。 + +## 11. 结论 + +结论:PASS,针对“火焰图没有纵向延展”的 MVP 目标已经达成。 + +证据是: + +* leaf baseline 仍全部为一帧,复现了原问题。 +* `--full-stack` blk case 中 578/579 条 workload 样本为多帧,raw max depth 为 18,folded symbol depth 最高到 72。 +* `--full-stack` net case 中 652/661 条 workload 样本为多帧,raw max depth 为 17,folded symbol depth 最高到 78。 +* folded stack 中已经出现 syscall -> fs/net -> driver -> virtqueue/memcpy 的完整工程路径。 + +因此,现在 qperf 不再只能生成 leaf hotspot 火焰图;在 full-stack 模式下可以生成具备明显纵向展开的 RISC-V kernel flamegraph。默认 leaf 模式保留为低开销兼容路径。 diff --git a/docs/qperf-cargo-starry-integration-report.md b/docs/qperf-cargo-starry-integration-report.md new file mode 100644 index 0000000000..44c526d18c --- /dev/null +++ b/docs/qperf-cargo-starry-integration-report.md @@ -0,0 +1,179 @@ +# qperf 与 cargo starry 集成报告 + +## 1. 背景与目标 + +本轮目标是降低 qperf 使用门槛,并提升火焰图可读性: + +* 用户不再需要手写复杂 `tools/starry-syscall-harness/harness.py perf-profile ...`。 +* `cargo starry perf` 生成完整 qperf report、csv、folded stack、SVG flamegraph。 +* `cargo starry run --perf` 作为 `cargo starry qemu --perf` alias 路径,提供 run 语义入口。 +* 火焰图保留更完整的 Rust demangled symbol,支持 symbol style、focus、boot/workload/post/focused 视图。 + +本轮不修改 virtio 数据路径,也不宣称修复 virtio 性能问题。 + +## 2. 现有架构梳理 + +`.cargo/config.toml` 中 `cargo starry` 是 alias:`cargo run -p tg-xtask -- starry`。实际 StarryOS CLI 在 `scripts/axbuild/src/starry/mod.rs`,qperf runner 在 `scripts/axbuild/src/starry/perf.rs`。 + +本轮选择的集成点: + +* 保留并增强已有 `Command::Perf(ArgsPerf)`,即 `cargo starry perf`。 +* 给 `Command::Qemu(ArgsQemu)` 增加 `run` alias,并在 `ArgsQemu` 上增加 `--perf` 与 `--perf-*` 参数。 +* 继续复用 `perf::run()`,避免复制 qperf/QEMU/plugin/analyzer 逻辑。 +* 增加 harness `perf-postprocess`,让 cargo 入口也能生成与 harness 一致的 `report.json/report.md/hotspots.csv/hotspot_categories.csv`。 +* `cargo starry perf` 默认把 axbuild 临时目录隔离到输出目录下的 `axbuild-tmp/`;底层 `axbuild_tmp_dir()` 也支持 `AXBUILD_TMP_DIR`,避免已有 `tmp/axbuild/` 被 Docker/root-owned 文件污染时阻塞 profile。 + +## 3. 新命令设计 + +### `cargo starry perf` + +```bash +cargo starry perf --case boot +``` + +默认值: + +| 参数 | 默认值 | +| --- | --- | +| arch | `riscv64` | +| case | `boot` | +| output | `target/qperf//perf//latest/` | +| freq | `99` | +| max-depth | `128` | +| mode | `tb` | +| format | `all` | +| top | `80` | +| min-percent | `0.3` | +| host-time | enabled unless `--no-host-time` | + +### `cargo starry run --perf` + +`cargo starry run` 是 `cargo starry qemu` 的 alias。带 `--perf` 时转换为 `ArgsPerf` 并调用同一套 `perf::run()`: + +```bash +cargo starry run \ + --perf \ + --perf-case blk-read \ + --perf-workload 'echo QPERF_BEGIN:blk; dd if=/usr/bin/lto-dump of=/dev/null bs=64k; echo QPERF_END:blk' \ + --perf-start-marker QPERF_BEGIN \ + --perf-stop-marker QPERF_END \ + --perf-qperf-metrics +``` + +当前 `run --perf` 支持默认 qperf QEMU/rootfs flow,不支持和 `--qemu-config`、`--rootfs`、`--config`、`--target`、`--smp` 混用;这些组合会给出明确错误,避免静默忽略。 + +## 4. 火焰图增强 + +新增能力: + +* analyzer 支持 `--symbol-style full|short|module`。 +* analyzer fallback symtab 也会做 Rust demangle。 +* analyzer 支持 `--focus ` 生成聚焦 folded/flamegraph。 +* analyzer 支持 `--min-percent` 控制 SVG frame 最小宽度。 +* `cargo starry perf` 输出默认、workload、boot、post、focus 多个火焰图路径。 +* `--full-stack` 会把 qperf plugin max depth 至少提升到 256。 +* `--no-truncate` 会把 flamegraph min width 降到 0。 + +真实验证中,新 analyzer 已能把旧 `_R...` mangled symbol 转换为可读 Rust 路径,例如: + +```text +>::add_notify_wait_pop +::alloc +``` + +但当前 qperf 仍不保证恢复截图级完整调用栈。根因是 stack unwind 仍依赖 frame pointer 链,QEMU plugin sample 只记录 IP trace,没有 DWARF unwind 状态、vCPU/thread 元数据或 guest backtrace。 + +## 5. 使用示例 + +boot: + +```bash +cargo starry perf --case boot +``` + +blk-read: + +```bash +cargo starry perf \ + --case blk-read \ + --qperf-metrics \ + --start-marker QPERF_BEGIN \ + --stop-marker QPERF_END \ + --workload-timeout 45 \ + --workload 'echo reset > /proc/qperf_metrics; echo QPERF_BEGIN:blk-read; dd if=/usr/bin/lto-dump of=/dev/null bs=64k; cat /proc/qperf_metrics; echo QPERF_END:blk-read' +``` + +net-wget: + +```bash +cargo starry perf \ + --case net-wget \ + --qperf-metrics \ + --start-marker QPERF_BEGIN \ + --stop-marker QPERF_END \ + --workload 'echo reset > /proc/qperf_metrics; echo QPERF_BEGIN:net-wget; wget -O /dev/null http://10.0.2.2:8000/tmp/axbuild/rootfs/rootfs-riscv64-alpine.img.tar.xz; cat /proc/qperf_metrics; echo QPERF_END:net-wget' +``` + +在 Docker/WSL 下,net server 应与 QEMU 处在可达网络拓扑中;此前验证显示 WSL host 上直接启动 HTTP server 时 guest 访问 `10.0.2.2:8000` 会 connection refused。 + +A/B compare: + +```bash +python3 tools/starry-syscall-harness/harness.py perf-compare \ + --baseline target/qperf/blk-read/perf/riscv64/latest/report.json \ + --candidate target/qperf/blk-read-patched/perf/riscv64/latest/report.json \ + --name blk-read-ab \ + --output-dir target/qperf/compare +``` + +## 6. 验收结果 + +| 验收项 | 结果 | 证据路径 | 备注 | +| --- | --- | --- | --- | +| qperf-analyzer help | PASS | `target/qperf-integration-smoke/help/qperf-analyzer-help.txt` | `--symbol-style`、`--focus`、`--min-percent` 出现在 help | +| harness perf-profile help | PASS | `target/qperf-integration-smoke/help/harness-perf-profile-help.txt` | 旧 harness 入口保留,并暴露新增 flamegraph 参数 | +| harness perf-postprocess help | PASS | `target/qperf-integration-smoke/help/harness-perf-postprocess-help.txt` | cargo 入口复用此 postprocess 生成 report/csv | +| cargo starry perf help | PASS | `target/qperf-integration-smoke/help/cargo-starry-perf-help.txt` | 使用临时 `CARGO_HOME` 与测试用 `PKG_CONFIG_PATH` 通过;当前 host 原生环境仍缺 `libudev.pc` | +| cargo starry run help | PASS | `target/qperf-integration-smoke/help/cargo-starry-run-help.txt` | `run` alias 暴露 `--perf`、`--perf-case`、`--perf-workload`、`--perf-focus` 等参数 | +| axbuild check/clippy | PASS | command output | `cargo check -p axbuild`、`cargo clippy -p axbuild -- -D warnings` 通过 | +| cargo CLI parse tests | PASS | command output | `command_parses_perf_*` 与 `command_parses_run_perf_alias` 通过 | +| qperf plugin check | PASS | command output | `cargo check --manifest-path tools/qperf/Cargo.toml` 通过 | +| analyzer flamegraph resolve | PASS | `target/qperf-integration-smoke/analyzer/flamegraph.svg` | 复用已有 blk raw sample 生成 SVG | +| analyzer focused flamegraph | PASS | `target/qperf-integration-smoke/analyzer/flamegraph.virtio.svg` | `--focus 'virtio|VirtQueue'` 输出 159 samples | +| stack.folded symbol 粒度 | PARTIAL | `target/qperf-integration-smoke/analyzer/stack.full.folded` | symbol demangle 可读;调用链仍常短栈 | +| harness perf-postprocess | PASS | `target/qperf-integration-smoke/postprocess/report.json` | 从既有 qperf artifacts 生成 report/csv,参数中包含 `symbol_style/focus/no_truncate` | +| cargo starry perf boot | FAIL | `target/qperf-integration-smoke/logs/cargo-starry-perf-boot.log` | qperf tools、StarryOS build、rootfs 准备均已推进;宿主缺 `qemu-system-riscv64`,未产生 raw samples/report | +| cargo starry perf blk | NOT RUN | N/A | 与 boot 相同的 QEMU host 依赖阻塞,未重复下载/运行 | +| old full harness QEMU run | NOT RUN | N/A | 本轮未再触发 Docker profile,避免重新生成 root-owned `tmp/axbuild`;CLI/help 兼容已验证 | + +本轮真实 boot profile 阻塞原因: + +```text +Error: qperf requires `qemu-system-riscv64` in PATH; install the matching QEMU system emulator or run the Docker-based harness perf-profile entrypoint +``` + +额外环境说明: + +* 当前 host 原生 `pkg-config` 找不到 `libudev.pc`。help/check 验证使用 `/tmp/fake-pkgconfig` 作为只用于编译帮助/测试的替代,不代表生产运行环境;正常环境应安装 `libudev-dev`。 +* 默认 Cargo registry cache 仍有 root-owned cache warning;验证使用 `CARGO_HOME=/tmp/tgoskits-cargo-home` 避免写入用户 cache。 +* 原仓库 `tmp/axbuild/` 存在 root-owned 文件;本轮已通过 `AXBUILD_TMP_DIR` 和 cargo perf 默认 `axbuild-tmp/` 隔离规避。 +* `rust-objcopy` 初始不在 PATH;验证时临时加入 Rust toolchain 的 llvm-tools 路径,随后现有 `starry-kallsyms.sh` 安装了 `cargo-binutils` 与 `gen_ksym` 到 `/tmp/tgoskits-cargo-home/bin`。 + +## 7. 局限性 + +* `cargo starry perf` 代码路径已实现并推进到 QEMU 启动前,但当前 host 缺 `qemu-system-riscv64`,所以 boot/blk profile 未能生成新的 raw samples 和最终 report。 +* qperf 仍是 QEMU TCG plugin 采样,不是 guest PMU。 +* marker window 仍是 timestamp 后处理过滤,不是 runtime pause/resume。 +* stack unwind 仍依赖 frame pointer,不能保证完整 Rust 调用链。 +* counters 仍是 driver-visible 近似值,不是 ring-level 精确统计。 +* host perf/PMU 是可选 host QEMU process 指标。 +* vsock 仍受 `/dev/vhost-vsock` 限制。 + +## 8. 下一步建议 + +1. 在安装 `qemu-system-riscv64`、`libudev-dev`,并保证 `rust-objcopy` 在 PATH 的 host 上重跑 `cargo starry perf --case boot`。 +2. 重跑 blk marker profile,确认 cargo 入口完整生成 `report.json/report.md/hotspots.csv/hotspot_categories.csv/qperf/flamegraph.svg`。 +3. cargo 入口闭环后开始 net RX 去 `copy_within()` A/B。 +4. 开始 net inflight `BTreeMap` 到 fixed array/slab 的 A/B。 +5. 开始 blk pending read / async queue 原型 A/B。 +6. 继续探索 ring-level virtqueue counters 和 runtime pause/resume sampling。 diff --git a/docs/qperf-cargo-starry-integration.md b/docs/qperf-cargo-starry-integration.md new file mode 100644 index 0000000000..6e56460f44 --- /dev/null +++ b/docs/qperf-cargo-starry-integration.md @@ -0,0 +1,168 @@ +# qperf cargo starry 集成指南 + +## 快速开始 + +默认 boot profile: + +```bash +cargo starry perf --case boot +``` + +blk marker profile: + +```bash +cargo starry perf \ + --case blk-read \ + --qperf-metrics \ + --start-marker QPERF_BEGIN \ + --stop-marker QPERF_END \ + --workload-timeout 45 \ + --workload 'echo reset > /proc/qperf_metrics; echo QPERF_BEGIN:blk-read; dd if=/usr/bin/lto-dump of=/dev/null bs=64k; cat /proc/qperf_metrics; echo QPERF_END:blk-read' +``` + +`cargo starry run --perf` 是 `cargo starry qemu --perf` 的 alias 路径,适合用户按 run 语义启动默认 qperf: + +```bash +cargo starry run --perf --perf-case boot +``` + +如果只是复盘已有结果或在没有 host QEMU 的机器上做报告分析,可以直接阅读已经生成的 +`report.json`、`hotspot_categories.csv` 和 `qperf/stack.folded`。当前仓库中的 blk +瓶颈分析见 `docs/qperf-current-blk-bottleneck-analysis.md`。 + +## 环境依赖 + +`cargo starry perf` 在 host 上直接运行 QEMU,需要: + +* `qemu-system-riscv64` 或对应 arch 的 system QEMU 在 `PATH` 中。 +* Rust `llvm-tools`/`cargo-binutils` 提供 `rust-objcopy`、`rust-nm`。 +* axbuild 依赖的 host 库,例如 `libudev.pc`;Debian/Ubuntu 通常来自 `libudev-dev`。 + +本入口会把 StarryOS build config、generated axconfig 和 managed rootfs 隔离到当前 qperf 输出目录下的 `axbuild-tmp/`。高级用户可以显式设置 `AXBUILD_TMP_DIR=` 复用或重定向这部分临时文件。 + +## 默认值 + +`cargo starry perf` 默认使用: + +| 参数 | 默认值 | +| --- | --- | +| arch | `riscv64` | +| case | `boot` | +| output | `target/qperf//perf//latest/` | +| qperf freq | `99` | +| max depth | `128` | +| mode | `tb` | +| format | `all` | +| top | `80` | +| min percent | `0.3` | +| host time | enabled | +| qperf metrics | disabled unless `--qperf-metrics` | + +生成完成后会打印: + +```text +qperf report generated: + report: target/qperf//perf/riscv64/latest/report.md + flamegraph: target/qperf//perf/riscv64/latest/qperf/flamegraph.svg + folded stack: target/qperf//perf/riscv64/latest/qperf/stack.folded + json: target/qperf//perf/riscv64/latest/report.json +``` + +## 高级参数 + +常用 qperf 参数: + +```bash +cargo starry perf \ + --case net-wget \ + --freq 199 \ + --max-depth 256 \ + --mode insn \ + --symbol-style full \ + --focus 'virtio|net|memcpy|memmove' \ + --no-truncate +``` + +`cargo starry run --perf` 使用 `--perf-*` 前缀: + +```bash +cargo starry run \ + --perf \ + --perf-case blk-read \ + --perf-workload 'echo QPERF_BEGIN:blk; dd if=/usr/bin/lto-dump of=/dev/null bs=64k; echo QPERF_END:blk' \ + --perf-start-marker QPERF_BEGIN \ + --perf-stop-marker QPERF_END \ + --perf-qperf-metrics \ + --perf-symbol-style full \ + --perf-focus 'virtio|block' +``` + +当前 `run --perf` 只支持默认 qperf QEMU/rootfs flow,以及 `--arch`、`--debug` 这类轻量 build override。带 `--qemu-config`、`--rootfs`、`--config`、`--target`、`--smp` 的 perf run 仍应使用 plain `cargo starry qemu` 或后续扩展。 + +## 输出文件 + +| 文件 | 说明 | +| --- | --- | +| `report.json` | 机器可读报告 | +| `report.md` | 可直接阅读/粘贴的 Markdown 报告 | +| `hotspots.csv` | symbol hotspot | +| `hotspot_categories.csv` | 工程归因类别 | +| `qperf/stack.folded` | 完整 folded stack | +| `qperf/flamegraph.svg` | 默认完整火焰图 | +| `qperf/flamegraph.workload.svg` | marker workload window 火焰图 | +| `qperf/flamegraph.boot.svg` | boot 阶段火焰图 | +| `qperf/flamegraph.post.svg` | post-window 火焰图 | +| `qperf/flamegraph.focus.svg` | `--focus` 过滤后的火焰图 | +| `qperf/summary.txt` | qperf run 摘要 | + +## 用 qperf 做 blk 瓶颈初筛 + +推荐先跑 marker + metrics workload: + +```bash +cargo starry perf \ + --case blk-read \ + --qperf-metrics \ + --start-marker QPERF_BEGIN \ + --stop-marker QPERF_END \ + --workload-timeout 45 \ + --workload 'echo reset > /proc/qperf_metrics; echo QPERF_BEGIN:blk-read; dd if=/usr/bin/lto-dump of=/dev/null bs=64k; cat /proc/qperf_metrics; echo QPERF_END:blk-read' +``` + +读报告时优先看三组字段: + +| 字段 | 用途 | +| --- | --- | +| `window` | 确认 boot/post-window 样本是否被排除 | +| `hotspot_categories.csv` | 看 copy、virtqueue、allocator、scheduler 等工程类别占比 | +| `workload_metrics.values` | 看 `virtqueue_add_notify_wait_pop_count`、notify/kick、blk read bytes/requests 等 driver-visible counters | + +当前已有 blk profile 显示,`virtqueue_add_notify_wait_pop` 和 +`virtio_notify_kick` 都在 workload window 内占到约 25% 级别,且 +`virtio_blk_read_bytes / virtio_blk_read_requests` 约为 4 KiB。这个结果指向 +“大量同步 4 KiB 级别 virtqueue 请求,queue depth 没有被持续利用”的 blk +优化方向。完整证据和限制见 `docs/qperf-current-blk-bottleneck-analysis.md`。 + +## A/B compare + +```bash +python3 tools/starry-syscall-harness/harness.py perf-compare \ + --baseline target/qperf/blk-read/perf/riscv64/latest/report.json \ + --candidate target/qperf/blk-read-patched/perf/riscv64/latest/report.json \ + --name blk-read-ab \ + --output-dir target/qperf/compare +``` + +## 网络与 vsock 注意事项 + +在 Docker/WSL 下,guest 的 `10.0.2.2` 通常指向 QEMU slirp 所在网络命名空间,不一定能访问 WSL host 上启动的 HTTP server。net profile 建议在同一个 Docker 容器内启动 HTTP server,或明确使用 host 网络。 + +vsock 需要 host 具备 `/dev/vhost-vsock`。如果不存在,不应输出伪造吞吐或 counter。 + +## 当前局限 + +* qperf 仍是 QEMU TCG plugin 采样,不是 guest PMU。 +* marker window 仍是 raw timestamp 后处理过滤,不是 runtime pause/resume。 +* stack unwind 依赖 frame pointer 和可解析 DWARF;inline、tail call、汇编 trampoline 可能断栈。 +* virtio counters 是 driver-visible 近似值,不是 ring-level 精确硬件事件。 +* user symbol 解析当前只在符号存在于 kernel ELF 时可见。 diff --git a/docs/qperf-current-blk-bottleneck-analysis.md b/docs/qperf-current-blk-bottleneck-analysis.md new file mode 100644 index 0000000000..492bf21b91 --- /dev/null +++ b/docs/qperf-current-blk-bottleneck-analysis.md @@ -0,0 +1,176 @@ +# qperf 当前 virtio-blk 瓶颈分析 + +## 1. 数据来源 + +本页基于当前仓库中已经生成的 marker-aware qperf 结果,不包含新编造数据。 + +主证据: + +* `target/qperf-validation/blk/perf/riscv64/latest/report.json` +* `target/qperf-validation/blk/perf/riscv64/latest/report.md` +* `target/qperf-validation/blk/perf/riscv64/latest/hotspot_categories.csv` +* `target/qperf-validation/blk/perf/riscv64/latest/hotspots.csv` + +交叉核对: + +* `target/qperf-tooling-experiments/blk/perf/riscv64/latest/report.json` +* `target/qperf-tooling-experiments/blk/perf/riscv64/latest/hotspot_categories.csv` + +本轮分析没有重新运行 QEMU。当前宿主环境缺少 `qemu-system-riscv64`,`cargo starry perf --case boot` 的构建阶段可以推进,但启动 QEMU profiling 会失败;失败日志见 `target/qperf-integration-smoke/logs/cargo-starry-perf-boot.log`。 + +## 2. qperf 当前能力 + +当前 qperf 已经不只是火焰图采样器,可以同时提供: + +* marker/window:用 `QPERF_BEGIN` 和 `QPERF_END` 从 boot 样本中切出 workload window。 +* symbol hotspot:`hotspots.csv` 列出采样最多的函数和栈。 +* 工程归因类别:`hotspot_categories.csv` 聚合 `memcpy`、`virtqueue_add_notify_wait_pop`、`virtio_notify_kick`、`block_io_path`、`allocator` 等类别。 +* workload parser:从 `dd` 输出解析 bytes、elapsed 和 B/s。 +* virtio driver-visible counters:从 `/proc/qperf_metrics` 解析 virtqueue、blk、net 计数。 +* 归一化指标:`normalized_metrics` 给出 `samples_per_MB`、`host_elapsed_sec_per_MB`、`category_samples_per_MB` 等字段。 + +需要注意的是,当前 marker/window 仍是后处理 timestamp filter,不是 QEMU plugin runtime pause/resume;virtqueue 计数也仍是 driver-visible 近似值,不是 ring-level 精确事件。 + +## 3. blk workload 摘要 + +workload: + +```bash +echo reset > /proc/qperf_metrics +echo QPERF_BEGIN:blk-read +dd if=/usr/bin/lto-dump of=/dev/null bs=64k +cat /proc/qperf_metrics +echo QPERF_END:blk-read +``` + +`target/qperf-validation/blk/perf/riscv64/latest/report.json` 中的关键结果: + +| 字段 | 数值 | +| --- | ---: | +| dd bytes | 53,601,104 | +| dd elapsed | 5.794463 s | +| dd throughput | 9,250,400.60 B/s | +| qperf workload window | 5.951667225 s | +| boot samples excluded | 164 | +| post-window samples excluded | 492 | +| folded stack lines | 590 | +| samples per MB | 11.007236 | +| host elapsed sec per MB | 0.235666 | + +`host_perf_metrics.enabled` 为 `false`,因此本报告没有 host PMU/perf stat 事件。`guest_instructions_per_MB` 和 `guest_blocks_per_MB` 为 `null`,不能用它们做本轮结论。 + +## 4. 工程归因热点 + +`hotspot_categories.csv` 中 workload window 内的 top categories: + +| category | samples | percent | +| --- | ---: | ---: | +| memcpy | 173 | 29.3220% | +| virtio_notify_kick | 154 | 26.1017% | +| virtqueue_add_notify_wait_pop | 151 | 25.5932% | +| block_io_path | 108 | 18.3051% | +| allocator | 79 | 13.3898% | +| scheduler_wait_preempt | 10 | 1.6949% | +| memmove | 7 | 1.1864% | +| virtqueue_pop_complete | 2 | 0.3390% | + +交叉核对 profile `target/qperf-tooling-experiments/blk/perf/riscv64/latest/` 的结果接近: + +| category | samples | percent | +| --- | ---: | ---: | +| memcpy | 166 | 28.1834% | +| virtio_notify_kick | 145 | 24.6180% | +| virtqueue_add_notify_wait_pop | 144 | 24.4482% | +| block_io_path | 115 | 19.5246% | +| allocator | 89 | 15.1104% | + +两组结果都显示,blk workload 的主要采样集中在 copy、virtqueue 同步提交/等待、notify/kick、block I/O 路径和 allocator/cache 管理。 + +## 5. virtio-blk counters + +`/proc/qperf_metrics` 被 harness 合入 `report.json.workload_metrics.values`。主 profile 的关键计数如下: + +| counter | value | +| --- | ---: | +| virtqueue_add_notify_wait_pop_count | 13,780 | +| virtqueue_add_count | 13,847 | +| virtio_notify_kick_count | 13,847 | +| virtqueue_pop_complete_count | 13,783 | +| virtqueue_depth_max | 63 | +| virtqueue_depth_hist_0 | 13,781 | +| virtqueue_depth_hist_1 | 13,783 | +| virtqueue_depth_hist_33_64 | 35 | +| virtio_blk_read_requests | 13,478 | +| virtio_blk_read_bytes | 55,195,136 | +| virtio_blk_write_requests | 302 | +| virtio_blk_write_bytes | 1,236,992 | + +派生指标: + +| 指标 | 数值 | +| --- | ---: | +| add_notify_wait_pop per MB | 257.08 | +| notify/kick per MB | 258.33 | +| read request per MB | 251.45 | +| blk read bytes per request | 4,095.20 | +| blk read bytes per add_notify_wait_pop | 4,005.45 | + +虽然 guest 命令使用 `bs=64k`,driver-visible blk read request 平均仍约 4 KiB。这说明当前路径没有把上层 64 KiB read 有效合并成更大的 virtqueue 批量请求,而是表现为大量同步 4 KiB 级别请求。 + +## 6. 代码路径核对 + +当前 `drivers/ax-driver/src/virtio/block.rs` 中: + +* `VirtIoBlkDevice::new()` 调用 `raw.disable_interrupts()`。 +* `submit_request()` 的 read 分支调用 `self.raw.raw.read_blocks(request.block_id, &mut buffer)`。 +* read 完成后才 `record_blk_read(bytes)`。 +* `poll_request()` 当前直接返回 `Ok(())`。 + +因此从 driver 层看,当前 blk request 是同步完成语义:提交 read 时就在同一调用路径中等待底层 virtqueue 完成,而不是把多个 pending request 放进 virtqueue 后再集中完成。 + +## 7. 瓶颈判断 + +当前最明确的 virtio-blk 瓶颈是: + +**blk read 路径以接近 4 KiB 粒度频繁执行同步 `VirtQueue::add_notify_wait_pop`,并几乎每个 virtqueue add 都触发 notify/kick,导致 queue depth 没有被持续利用。** + +证据链: + +* `virtqueue_add_notify_wait_pop` 占 25.5932% inclusive samples。 +* `virtio_notify_kick` 占 26.1017% inclusive samples。 +* `virtqueue_add_notify_wait_pop_count = 13,780`,`virtio_notify_kick_count = 13,847`,两者与 `virtqueue_add_count = 13,847` 接近。 +* `virtio_blk_read_requests = 13,478`,`virtio_blk_read_bytes = 55,195,136`,平均每个 read request 约 4,095 bytes。 +* `virtqueue_depth_hist_0` 和 `virtqueue_depth_hist_1` 各约 13.8k,说明大部分观测点接近空队列或单请求状态;`virtqueue_depth_max = 63` 只说明曾经出现过较深队列,不代表 workload 稳定利用 queue depth。 +* `drivers/ax-driver/src/virtio/block.rs` 的 `submit_request()` 直接调用同步 `read_blocks()`,`poll_request()` 没有真正完成异步轮询。 + +## 8. 次级瓶颈和风险 + +`memcpy` 是采样占比最高的单类,主 profile 中为 29.3220%。这说明 blk workload 中 copy 开销非常明显,但当前 qperf 只能证明 copy 是真实热点,不能仅凭这一份报告断言 copy 全部来自 virtio-blk driver。`hotspots.csv` 还出现 ext4/data block cache、BTreeMap、allocator 相关 symbol,copy 可能来自文件系统 cache、用户/内核 buffer 复制或 block buffer 管理。 + +因此本轮更稳妥的 blk 优化切入点是同步 virtqueue 提交/等待和 request 粒度,而不是直接宣称 driver DMA copy 是唯一主因。 + +## 9. 建议的下一步 A/B 实验 + +1. 实现最小 pending-read 原型:把 blk read 分成 submit 和 complete 两阶段,避免每个 4 KiB request 立即 `add_notify_wait_pop`。 +2. 增加或复用 `read_blocks_nb()` / `complete_read_blocks()` 形式的接口,在队列中累积多个请求后统一 notify 或批量回收 used ring。 +3. 在 block/fs 层尝试合并连续块,让 `bs=64k` 能转换成更少、更大的 virtio request。 +4. 对比 baseline 和 candidate 的以下指标: + * `virtqueue_add_notify_wait_pop_count` + * `virtio_notify_kick_count` + * `virtio_blk_read_requests` + * `virtqueue_depth_hist_*` + * `virtqueue_add_notify_wait_pop` category percent + * `virtio_notify_kick` category percent + * `dd throughput` +5. 如果候选方案有效,预期现象是 `add_notify_wait_pop per MB` 和 `notify/kick per MB` 明显下降,稳定 queue depth 上升,dd throughput 上升或 host elapsed per MB 下降。 + +## 10. 后续需要补强的 qperf 字段 + +为了把结论从 driver-visible 近似推进到 ring-level 精确归因,后续应把以下计数下沉到 `virtio-drivers` 或更接近 virtqueue ring 的位置: + +* 每个 queue 的 add、notify、used pop 精确次数。 +* notify coalescing 或 skipped notify 次数。 +* ring avail/used depth 的采样直方图。 +* 等待 used ring 的自旋或阻塞时间。 +* 每个 blk request 的 sector count、byte count、merge 来源。 +* block/fs copy counters,用于区分 FS cache copy、user copy 和 driver buffer copy。 diff --git a/docs/qperf-flamegraph-guide.md b/docs/qperf-flamegraph-guide.md new file mode 100644 index 0000000000..89345bc6f9 --- /dev/null +++ b/docs/qperf-flamegraph-guide.md @@ -0,0 +1,182 @@ +# qperf 火焰图指南 + +## 快速生成 + +默认 profile 使用 leaf 模式,开销低,但调用栈通常只有一层: + +```bash +cargo starry perf --case boot --symbol-style full +``` + +需要纵向展开的深调用栈时,使用 `--full-stack`: + +```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' +``` + +`--full-stack` 会启用 frame pointer callchain,并在 kernel 构建中加入: + +```text +-Cdebuginfo=2 +-Cstrip=none +-Cforce-frame-pointers=yes +``` + +因此它比默认 profile 慢,也会触发更多构建工作;只在需要深栈火焰图时开启。 + +## callchain 模式 + +| 模式 | 用法 | 说明 | +| --- | --- | --- | +| `leaf` | 默认 | 只记录采样 PC,适合粗略热点和旧命令兼容。 | +| `fp` | `--perf-callchain fp` 或 `--full-stack` | 读取 RISC-V `sp/fp`,按 frame pointer 链恢复 kernel 调用栈。 | +| `logical` | 当前不可用 | 预留人工插桩逻辑栈模式。本轮没有实现,不会伪装成真实 callchain。 | + +如果只传 `--perf-callchain fp`,还应配合: + +```bash +--perf-debuginfo --perf-force-frame-pointers +``` + +实际使用中推荐直接传 `--full-stack`。 + +## 读哪些文件 + +| 文件 | 说明 | +| --- | --- | +| `qperf/flamegraph.svg` | 完整 profile 火焰图。 | +| `qperf/flamegraph.workload.svg` | marker window 内样本火焰图。 | +| `qperf/flamegraph.boot.svg` | start marker 前样本火焰图。 | +| `qperf/flamegraph.post.svg` | stop marker 后样本火焰图,可能为空。 | +| `qperf/flamegraph.focus.svg` | `--focus` regex 命中的 focused 火焰图。 | +| `qperf/stack.folded` | folded stack 原始输入,默认保留完整 demangled Rust symbol。 | +| `qperf/stack-depth-summary.csv` | raw callchain 地址深度分布。 | +| `hotspots.csv` | 函数级热点聚合。 | +| `hotspot_categories.csv` | 工程类别 inclusive stack 聚合。 | +| `report.json` | 机器可读报告,包含 `callchain` 与 `resolve_stats`。 | + +检查火焰图是否真的有深栈: + +```bash +awk -F';' '{print NF}' target/.../qperf/stack.folded | sort -n | uniq -c +cat target/.../qperf/stack-depth-summary.csv +``` + +如果大部分 `NF=1`,说明当前 folded stack 仍是 leaf-only;应确认是否开启 `--full-stack`,以及 kernel 是否用 frame pointer 构建。 + +## symbol style + +| style | 用途 | +| --- | --- | +| `full` | 保留完整 Rust demangled path,适合归因和搜索。 | +| `module` | 保留 crate 与尾部模块/函数,适合 SVG 可读性。 | +| `short` | 只看函数尾名,适合粗略热点。 | + +SVG 因空间限制可能截断长 frame;需要确认完整 symbol 时看 `stack.folded`。 + +## marker/window + +推荐所有 workload profile 使用 marker,避免 boot 样本污染: + +```bash +cargo starry perf \ + --case blk-read \ + --full-stack \ + --start-marker QPERF_BEGIN \ + --stop-marker QPERF_END \ + --workload 'echo QPERF_BEGIN:blk-read; dd if=/usr/bin/lto-dump of=/dev/null bs=64k; echo QPERF_END:blk-read' +``` + +`report.json.window` 会记录: + +* `start_time` +* `stop_time` +* `duration_sec` +* `boot_samples_excluded` +* `post_window_samples_excluded` +* `warnings` + +当前 window 过滤是 postprocess 级别过滤,不是 QEMU plugin runtime pause/resume。 + +## 聚焦 virtio/block 路径 + +```bash +cargo starry perf \ + --case blk-virtio \ + --full-stack \ + --qperf-metrics \ + --focus 'virtio|VirtQueue|block|memcpy|memmove' \ + --start-marker QPERF_BEGIN \ + --stop-marker QPERF_END \ + --workload 'echo reset > /proc/qperf_metrics; echo QPERF_BEGIN:blk; dd if=/usr/bin/lto-dump of=/dev/null bs=64k; cat /proc/qperf_metrics; echo QPERF_END:blk' +``` + +典型深栈应能看到类似路径: + +```text +starry_kernel::syscall::fs::io::sys_read + -> ax_fs_ng / rsext4 + -> ax_driver::block::binding::Block::read_blocks_wait + -> rd_block::CmdQueue::read_blocks_blocking + -> ax_driver::virtio::block::BlockQueue::submit_request + -> virtio_drivers::queue::VirtQueue::add_notify_wait_pop +``` + +## 聚焦 net 路径 + +先启动 host HTTP server: + +```bash +python3 -m http.server 8000 --bind 0.0.0.0 +``` + +另一个终端运行: + +```bash +cargo starry perf \ + --case net-full-stack \ + --full-stack \ + --qperf-metrics \ + --timeout 300 \ + --workload-timeout 240 \ + --start-marker QPERF_BEGIN \ + --stop-marker QPERF_END \ + --workload 'echo reset > /proc/qperf_metrics; echo QPERF_BEGIN:net; wget -O /dev/null http://10.0.2.2:8000/tmp/axbuild/rootfs/rootfs-riscv64-alpine.img.tar.xz; cat /proc/qperf_metrics; echo QPERF_END:net' +``` + +典型深栈应能看到: + +```text +starry_kernel::syscall::fs::io::sys_readv + -> ax_net_ng::SocketOps::recv + -> ax_net_ng::poll_interfaces + -> RdNetDriver::prefetch_rx_packets + -> rd_net::RxQueue + -> compiler_builtins::mem::memcpy / memmove +``` + +## 当前验证数据 + +本轮验证产物位于 `target/qperf-callchain-validation/`: + +| case | callchain | 多帧样本 | raw max depth | folded symbol depth | +| --- | --- | ---: | ---: | ---: | +| blk leaf | `leaf` | 0 / 577 | 1 | 1 | +| blk full-stack | `fp` | 578 / 579 | 18 | 最高 72 | +| net full-stack | `fp` | 652 / 661 | 17 | 最高 78 | + +详细报告见 `docs/qperf-callchain-validation-report.md`。 + +## 技术边界 + +* qperf 仍是 QEMU TCG plugin 采样,不是 guest PMU。 +* `fp` 模式依赖 frame pointer;没有 `-Cforce-frame-pointers=yes` 时无法保证深栈。 +* 当前只解析 kernel ELF,用户态符号尚未纳入。 +* trap、异常入口、任务切换、汇编 trampoline 可能截断调用链。 +* inline frame 会让 folded symbol 层数大于 raw FP 地址层数;两者都是真实信息,但含义不同。 +* `hotspot_categories.csv` 是 inclusive stack 分类,不是互斥 CPU 时间分解。 diff --git a/docs/qperf-host-rerun-virtio-bottleneck-report.md b/docs/qperf-host-rerun-virtio-bottleneck-report.md new file mode 100644 index 0000000000..d02cfbba32 --- /dev/null +++ b/docs/qperf-host-rerun-virtio-bottleneck-report.md @@ -0,0 +1,413 @@ +# qperf 宿主 QEMU 重跑与 virtio 瓶颈分析报告 + +## 1. 结论摘要 + +本轮使用宿主侧 `qemu-system-riscv64` 重新跑了 qperf profile,并用 marker window 与 `qperf-metrics` 重新验证 virtio 相关瓶颈。结论如下: + +| 子系统 | 主要瓶颈 | 证据强度 | 结论 | +| --- | --- | --- | --- | +| virtio-blk | 同步 `VirtQueue::add_notify_wait_pop`,近 4 KiB 粒度频繁 submit/notify/wait/pop | 高 | blk 读路径没有持续利用 queue depth,应优先做 pending read / async completion / 批量 notify | +| virtio-blk | `memcpy` 和 ext4/data block cache 管理 | 中 | copy 是真实热点,但当前 profile 不能证明所有 copy 都来自 blk driver | +| virtio-net | RX `copy_within()` 等 copy 开销 | 高 | RX 收包后把 header 后面的 packet 前移,copy bytes 与下载字节数同量级 | +| virtio-net | TX staging copy | 中 | 计数明确存在,但本次下载 workload 以 RX 为主,TX 字节较小 | +| virtio-net | inflight `BTreeMap` 管理规模 | 中 | counters 显示每 60.6 MiB 下载有约 4.6 万级 insert/remove/get;分类器当前没有把它聚成热点类别 | + +最值得优先做 A/B 的优化: + +1. blk:把同步 read path 改成 pending read / async queue 原型,降低 `add_notify_wait_pop_count` 与 notify/kick per MB。 +2. net:先做 RX 去 `copy_within()`,目标是让 `virtio_net_rx_copy_within_bytes` 明显下降。 +3. net:把 inflight `BTreeMap` 替换为固定数组/slab/token-indexed table,观察 allocator、BTree/inflight counters 与吞吐变化。 + +## 2. 验证环境与数据来源 + +宿主侧 QEMU 已安装到用户目录: + +```text +qemu-system-riscv64: /home/cg24/.cargo/bin/qemu-system-riscv64 +QEMU version: 10.2.1 +``` + +本轮没有通过 Docker 执行 QEMU;完整 workload profile 使用宿主 QEMU 与 harness: + +```bash +python3 tools/starry-syscall-harness/harness.py perf-profile --no-docker ... +``` + +主要证据路径: + +| 用例 | 结果目录 | +| --- | --- | +| blk | `target/qperf-host-rerun/blk-harness/perf/riscv64/latest/` | +| net | `target/qperf-host-rerun/net-harness-ok/perf/riscv64/latest/` | + +重要文件: + +| 文件 | 说明 | +| --- | --- | +| `report.json` | qperf 机器可读报告 | +| `report.md` | qperf 自动生成 Markdown 报告 | +| `hotspots.csv` | symbol hotspot | +| `hotspot_categories.csv` | 工程归因类别 | +| `qperf/flamegraph.workload.svg` | workload window 火焰图 | +| `qperf/stack.folded` | folded stack | +| `profile.stdout` | guest stdout,含 marker、workload 输出、`QPERF_METRIC` | + +本报告引用的 PNG 是从最新 workload SVG 转换得到: + +| PNG | SVG 来源 | +| --- | --- | +| `docs/flamegraphs/qperf-host-rerun-blk-workload.png` | `target/qperf-host-rerun/blk-harness/perf/riscv64/latest/qperf/flamegraph.workload.svg` | +| `docs/flamegraphs/qperf-host-rerun-blk-focus.png` | `target/qperf-host-rerun/blk-harness/perf/riscv64/latest/qperf/flamegraph.focus.svg` | +| `docs/flamegraphs/qperf-host-rerun-net-workload.png` | `target/qperf-host-rerun/net-harness-ok/perf/riscv64/latest/qperf/flamegraph.workload.svg` | + +## 3. 工具状态说明 + +`cargo starry perf` 已经能在宿主找到 QEMU 并启动 qperf QEMU,但本轮该路径在 StarryOS root device detection 阶段 panic: + +```text +failed to determine root device from available block devices +``` + +因此,本轮完整 workload profile 改用 harness 的 `perf-profile --no-docker` 路径。这个路径仍然使用宿主 `qemu-system-riscv64`,且 blk/net workload 均进入 marker window。 + +net 用例的最终 `report.json.result` 为 `incomplete`,但 workload 数据有效。原因是 stop marker 之后没有 post-window 样本,后处理尝试生成 `flamegraph.post.svg` 时返回: + +```text +No stack counts found +``` + +这属于 qperf 后处理边界,不是 wget 失败。net 的 `profile.stdout` 中有 `'/dev/null' saved`、`QPERF_END` 和完整 `QPERF_METRIC` 输出。 + +## 4. 火焰图说明 + +当前 qperf workload flamegraph 高度只有 123px,说明本轮采样恢复出的调用链仍较浅。它可以直观看到宽热点分布,但不能替代 `hotspot_categories.csv` 与 counters。瓶颈判断以三类证据交叉确认: + +1. 火焰图宽热点。 +2. `hotspots.csv` / `hotspot_categories.csv` 采样占比。 +3. `/proc/qperf_metrics` 导出的 driver-visible counters。 + +## 5. virtio-blk 分析 + +### 5.1 workload 与窗口 + +blk workload: + +```bash +echo reset > /proc/qperf_metrics +echo QPERF_BEGIN:blk-read +dd if=/usr/bin/lto-dump of=/dev/null bs=64k +cat /proc/qperf_metrics +echo QPERF_END:blk-read +``` + +执行结果: + +| 字段 | 数值 | +| --- | ---: | +| qperf result | `ok` | +| dd bytes | 53,601,104 | +| dd elapsed | 6.136393 s | +| dd throughput | 8,734,952.93 B/s | +| workload window | 6.299259501 s | +| boot samples excluded | 174 | +| post-window samples excluded | 495 | +| samples per MB | 11.622895 | +| host elapsed sec per MB | 0.243827 | + +### 5.2 blk workload 火焰图 + +![blk workload flamegraph](flamegraphs/qperf-host-rerun-blk-workload.png) + +blk focused 火焰图: + +![blk focused flamegraph](flamegraphs/qperf-host-rerun-blk-focus.png) + +图中能看到 `memcpy` 与 `VirtQueue::add_notify_wait_pop` 都是宽热点。由于当前 stack 较浅,具体归因应看下面的分类表和 counters。 + +### 5.3 工程分类热点 + +`hotspot_categories.csv` 的 top categories: + +| category | samples | percent | +| --- | ---: | ---: | +| `memcpy` | 177 | 28.4109% | +| `virtio_notify_kick` | 174 | 27.9294% | +| `virtqueue_add_notify_wait_pop` | 171 | 27.4478% | +| `block_io_path` | 117 | 18.7801% | +| `allocator` | 89 | 14.2857% | + +`hotspots.csv` 的 top functions: + +| function | samples | percent | +| --- | ---: | ---: | +| `compiler_builtins::mem::memcpy+0x4a` | 169 | 27.1268% | +| `VirtQueue::add_notify_wait_pop::+0xcc` | 84 | 13.4831% | +| `VirtQueue::add_notify_wait_pop::+0xc8` | 81 | 13.0016% | +| `DataBlockCache::evict_lru::+0x68` | 14 | 2.2472% | +| `DataBlockCache::evict_lru::+0x6a` | 10 | 1.6051% | + +### 5.4 blk virtio counters + +`/proc/qperf_metrics` 导出的关键计数: + +| counter | value | +| --- | ---: | +| `virtqueue_add_notify_wait_pop_count` | 14,354 | +| `virtqueue_add_count` | 14,421 | +| `virtio_notify_kick_count` | 14,421 | +| `virtqueue_pop_complete_count` | 14,357 | +| `virtqueue_depth_max` | 63 | +| `virtio_blk_read_requests` | 13,629 | +| `virtio_blk_read_bytes` | 55,813,632 | +| `virtio_blk_write_requests` | 725 | +| `virtio_blk_write_bytes` | 2,973,696 | + +派生指标: + +| 指标 | 数值 | +| --- | ---: | +| `add_notify_wait_pop` per MB | 267.79 | +| notify/kick per MB | 269.04 | +| average blk read request size | 4,095.21 bytes | + +这里最关键的是平均 read request size。guest 命令使用 `bs=64k`,但 driver-visible read request 平均仍约 4 KiB,说明上层 read 没有变成更少、更大的 virtio request。 + +### 5.5 blk 代码对应关系 + +相关代码在 `drivers/ax-driver/src/virtio/block.rs`: + +| 代码位置 | 现象 | +| --- | --- | +| `VirtIoBlkDevice::new()` | 调用 `raw.disable_interrupts()` | +| `BlockQueue::submit_request()` read 分支 | 直接调用 `self.raw.raw.read_blocks(request.block_id, &mut buffer)` | +| `BlockQueue::poll_request()` | 当前直接 `Ok(())`,没有真正完成异步轮询 | + +这意味着当前 blk submit 是同步完成语义。qperf 的 `VirtQueue::add_notify_wait_pop` 热点和 counters 正好对应这个实现。 + +### 5.6 blk 瓶颈判断 + +blk 的主瓶颈是: + +**大量约 4 KiB 粒度的同步 virtqueue 读请求,每个请求接近一次 add/notify/wait/pop,queue depth 没有被稳定用于隐藏等待成本。** + +证据链: + +* `virtqueue_add_notify_wait_pop` category 占 27.4478%。 +* `virtio_notify_kick` category 占 27.9294%。 +* `virtqueue_add_notify_wait_pop_count = 14,354`,`virtio_notify_kick_count = 14,421`。 +* `virtio_blk_read_bytes / virtio_blk_read_requests = 4095.21 bytes`。 +* `BlockQueue::submit_request()` 调用同步 `read_blocks()`,`poll_request()` 没有异步完成逻辑。 + +次级瓶颈是 copy 与 ext4/data block cache 管理: + +* `memcpy` 占 28.4109%。 +* `block_io_path` 占 18.7801%。 +* `allocator` 占 14.2857%。 + +但当前 qperf 还不能把所有 copy 精确拆分到 FS cache、用户/内核 buffer、driver DMA buffer,因此 copy 优化应在 blk async 原型之后用更细 counters 继续定位。 + +## 6. virtio-net 分析 + +### 6.1 workload 与窗口 + +net workload: + +```bash +echo reset > /proc/qperf_metrics +echo QPERF_BEGIN:net-wget +wget -O /dev/null http://10.0.2.2:8000/target/qperf-host-rerun/blk-read/perf/riscv64/latest/axbuild-tmp/rootfs/rootfs-riscv64-alpine.img.tar.xz +cat /proc/qperf_metrics +echo QPERF_END:net-wget +``` + +执行结果: + +| 字段 | 数值 | +| --- | ---: | +| wget bytes | 63,543,705 | +| wget saved | `true` | +| wget elapsed | 7.778458149 s | +| wget throughput | 8,169,190.32 B/s | +| workload window | 7.778458149 s | +| boot samples excluded | 171 | +| post-window samples excluded | 0 | +| samples per MB | 12.101907 | +| guest instructions per MB | 19,153,281.10 | +| guest blocks per MB | 2,978,337.95 | +| host elapsed sec per MB | 0.151217 | + +### 6.2 net workload 火焰图 + +![net workload flamegraph](flamegraphs/qperf-host-rerun-net-workload.png) + +火焰图中 `memcpy` 仍是最宽热点之一,右侧可以看到 virtio queue / net path 相关 frame。由于栈较浅,net 结论主要依赖 category 与 counters。 + +### 6.3 工程分类热点 + +`hotspot_categories.csv` 的 top categories: + +| category | samples | percent | +| --- | ---: | ---: | +| `memcpy` | 204 | 26.5280% | +| `allocator` | 165 | 21.4564% | +| `net_rx_tx_path` | 149 | 19.3758% | +| `memmove` | 55 | 7.1521% | +| `scheduler_wait_preempt` | 18 | 2.3407% | + +`hotspots.csv` 的 top functions: + +| function | samples | percent | +| --- | ---: | ---: | +| `compiler_builtins::mem::memcpy+0x4a` | 100 | 13.0039% | +| `compiler_builtins::mem::memcpy+0x10c` | 55 | 7.1521% | +| `NetRxQueue::submit+0x22c` | 35 | 4.5514% | +| `PercpuSlab::alloc+0xfa` | 32 | 4.1612% | +| `_head+0x11a2` | 29 | 3.7711% | + +### 6.4 net virtio counters + +`/proc/qperf_metrics` 导出的关键计数: + +| counter | value | +| --- | ---: | +| `virtqueue_add_count` | 47,858 | +| `virtio_notify_kick_count` | 47,858 | +| `virtqueue_pop_complete_count` | 47,794 | +| `virtqueue_add_notify_wait_pop_count` | 1,177 | +| `virtqueue_depth_max` | 63 | +| `virtio_net_rx_packets` | 44,140 | +| `virtio_net_rx_bytes` | 65,937,048 | +| `virtio_net_rx_copy_within_count` | 44,140 | +| `virtio_net_rx_copy_within_bytes` | 65,937,048 | +| `virtio_net_tx_packets` | 2,478 | +| `virtio_net_tx_bytes` | 149,375 | +| `virtio_net_tx_staging_copy_count` | 2,478 | +| `virtio_net_tx_staging_copy_bytes` | 149,375 | +| `virtio_net_inflight_insert_count` | 46,681 | +| `virtio_net_inflight_remove_count` | 46,617 | +| `virtio_net_inflight_get_count` | 46,617 | + +派生指标: + +| 指标 | 数值 | +| --- | ---: | +| RX copy bytes / wget bytes | 1.0377 | +| inflight insert+remove+get per MB | 2,201.87 | +| notify/kick per MB | 753.15 | + +### 6.5 net 代码对应关系 + +相关代码在 `drivers/ax-driver/src/virtio/net.rs`: + +| 代码位置 | 现象 | +| --- | --- | +| `NetInner` | 使用 `BTreeMap` 与 `BTreeMap` 管理 inflight | +| `submit_tx()` | 创建 `staging = vec![0; header + packet]`,再 `copy_from_slice(packet)` | +| `submit_tx()` | 将 token 插入 `tx_inflight` | +| `submit_rx()` | 将 RX buffer token 插入 `rx_inflight` | +| `reclaim_rx()` | `rx_inflight.remove(&token)` 后调用 `receive_complete()` | +| `reclaim_rx()` | `buffer.copy_within(header_len..header_len + packet_len, 0)` | + +这些代码路径与 counters 对应: + +* `virtio_net_rx_copy_within_count = virtio_net_rx_packets = 44,140`。 +* `virtio_net_rx_copy_within_bytes = virtio_net_rx_bytes = 65,937,048`。 +* `virtio_net_tx_staging_copy_count = virtio_net_tx_packets = 2,478`。 +* `virtio_net_inflight_insert/remove/get` 都是 4.6 万级。 + +### 6.6 net 瓶颈判断 + +net 的主瓶颈是: + +**RX 收包路径对几乎全部接收字节执行 `copy_within()`,copy bytes 与下载大小同量级,并且 `memcpy/memmove` 采样占比合计超过 33%。** + +证据链: + +* `memcpy` category 占 26.5280%。 +* `memmove` category 占 7.1521%。 +* `net_rx_tx_path` category 占 19.3758%。 +* `virtio_net_rx_copy_within_bytes = 65,937,048`,wget bytes 为 63,543,705,比例为 1.0377。 +* `reclaim_rx()` 中明确执行 `buffer.copy_within(header_len..header_len + packet_len, 0)`。 + +net 的次级瓶颈是 allocator 与 inflight 管理: + +* `allocator` category 占 21.4564%。 +* `virtio_net_inflight_insert_count = 46,681`。 +* `virtio_net_inflight_remove_count = 46,617`。 +* `virtio_net_inflight_get_count = 46,617`。 +* `NetInner` 使用 `BTreeMap` 管理 token 到 buffer 的映射。 + +需要注意:本轮 `hotspot_categories.csv` 中 `net_inflight_btree` 仍为 0。这不表示 inflight 没有成本,而是分类规则没有命中当前 demangled symbol 或成本被 allocator/copy/net path 分类覆盖。counters 已经证明 inflight 操作规模足够大,后续应补强分类规则或增加更细的 BTree/slab counters。 + +## 7. 综合瓶颈排序 + +| 优先级 | 方向 | 为什么先做 | +| --- | --- | --- | +| P0 | blk pending read / async queue | blk 的同步 queue 热点与 counters 同时非常强,优化目标清晰 | +| P0 | net RX 去 `copy_within()` | RX copy bytes 与下载 bytes 同量级,`memcpy/memmove` 合计占比高 | +| P1 | net inflight BTreeMap 替换 | counters 显示 4.6 万级 token map 操作,可能贡献 allocator 与路径开销 | +| P1 | net TX buffer/staging pool | 本次 TX 字节小,但代码中每次 TX 都有 staging Vec copy | +| P2 | blk/fs copy 来源细分 | `memcpy` 是 blk top category,但需要更多 counters 区分 FS cache 和 driver copy | + +## 8. 建议的 A/B 验证指标 + +### 8.1 blk pending read / async queue + +优化前后对比以下字段: + +| 指标 | 期望变化 | +| --- | --- | +| `virtqueue_add_notify_wait_pop_count` | 明显下降 | +| `virtio_notify_kick_count` per MB | 明显下降 | +| `virtio_blk_read_requests` per MB | 如有 request merge,应下降 | +| `virtqueue_depth_hist_*` | 低 depth 计数下降,中高 depth 更稳定 | +| `virtqueue_add_notify_wait_pop` category percent | 下降 | +| dd throughput | 上升 | +| host elapsed sec per MB | 下降 | + +### 8.2 net RX 去 `copy_within()` + +优化前后对比以下字段: + +| 指标 | 期望变化 | +| --- | --- | +| `virtio_net_rx_copy_within_bytes` | 明显下降,最好接近 0 | +| `virtio_net_rx_copy_within_count` | 明显下降,最好接近 0 | +| `memcpy` / `memmove` category percent | 下降 | +| `net_rx_tx_path` category percent | 下降或路径更分散 | +| wget throughput | 上升 | +| guest instructions per MB | 下降 | + +### 8.3 net inflight map 替换 + +优化前后对比以下字段: + +| 指标 | 期望变化 | +| --- | --- | +| `virtio_net_inflight_insert/remove/get_count` | 操作次数可能相同,但每次成本应下降 | +| allocator category percent | 下降 | +| `net_rx_tx_path` category percent | 下降 | +| BTreeMap 相关 symbol | 消失或下降 | +| wget throughput | 上升 | +| host elapsed sec per MB | 下降 | + +## 9. 当前 qperf 局限 + +本报告的结论已经足以指导下一轮 A/B 优化,但仍有以下边界: + +* marker window 是后处理 timestamp filter,不是 runtime pause/resume。 +* virtio counters 是 driver-visible 近似值,不是 ring-level 精确事件。 +* 火焰图纵向较浅,说明当前 frame pointer / QEMU plugin 采样链不能稳定恢复完整 Rust 调用栈。 +* net `result: incomplete` 来自 post-window 空样本 flamegraph 生成失败,workload 数据有效,但工具应进一步修复该返回码策略。 +* host perf 未启用,blk 的 guest instructions/blocks per MB 为空;net 有 guest instruction/block 归一化值。 +* `net_inflight_btree` 分类规则当前没有命中,但 counters 已能证明 inflight 操作规模。 + +## 10. 下一步任务建议 + +建议下一轮按以下顺序执行: + +1. 实现 net RX 去 `copy_within()` 最小补丁,跑 baseline/candidate A/B。 +2. 实现 net inflight `BTreeMap` 到固定数组/slab 的替换原型,跑 A/B。 +3. 实现 blk pending read / async completion 最小原型,跑 A/B。 +4. 修复 qperf post-window 空样本时返回 `incomplete` 的问题。 +5. 增加更接近 `virtio-drivers` ring 的精确 counters:avail depth、used depth、notify skipped、wait time、per-queue counters。 diff --git a/docs/qperf-marker-and-metrics-usage.md b/docs/qperf-marker-and-metrics-usage.md new file mode 100644 index 0000000000..6d701c3a63 --- /dev/null +++ b/docs/qperf-marker-and-metrics-usage.md @@ -0,0 +1,152 @@ +# qperf Marker And Metrics Usage + +`cargo starry perf` is now the preferred entrypoint for local qperf runs. The +lower-level harness commands below remain supported for Docker-wrapped syscall +harness workflows and compatibility. + +```bash +cargo starry perf \ + --case blk-read \ + --qperf-metrics \ + --start-marker QPERF_BEGIN \ + --stop-marker QPERF_END \ + --workload 'echo reset > /proc/qperf_metrics; echo QPERF_BEGIN:blk-read; dd if=/usr/bin/lto-dump of=/dev/null bs=64k; cat /proc/qperf_metrics; echo QPERF_END:blk-read' +``` + +See also `docs/qperf-cargo-starry-integration.md` and +`docs/qperf-flamegraph-guide.md`. + +## Basic Marker Run + +Use explicit guest stdout markers around the workload: + +```bash +python3 tools/starry-syscall-harness/harness.py perf-profile \ + --arch riscv64 \ + --timeout 60 \ + --start-marker QPERF_BEGIN \ + --stop-marker QPERF_END \ + --workload-timeout 30 \ + --shell-init-cmd 'echo QPERF_BEGIN:blk-read; dd if=/usr/bin/lto-dump of=/dev/null bs=64k; echo QPERF_END:blk-read' +``` + +The report window is written to `report.json.window` and `qperf/window.json`. + +Important fields: + +- `window.start_marker` +- `window.stop_marker` +- `window.start_time` +- `window.stop_time` +- `window.duration_sec` +- `window.truncated_by_timeout` +- `window.boot_samples_excluded` +- `window.warnings` + +If the start marker is missing, the report includes a warning because boot samples may still be present. If the stop marker is missing, the window extends until QEMU exits or times out. + +## Virtio Counter Run + +Enable driver counters with `--qperf-metrics`, reset before the workload, and print `/proc/qperf_metrics` before the stop marker: + +```bash +python3 tools/starry-syscall-harness/harness.py perf-profile \ + --arch riscv64 \ + --timeout 60 \ + --qperf-metrics \ + --start-marker QPERF_BEGIN \ + --stop-marker QPERF_END \ + --workload-timeout 30 \ + --shell-init-cmd 'echo reset > /proc/qperf_metrics; echo QPERF_BEGIN:blk-read; dd if=/usr/bin/lto-dump of=/dev/null bs=64k; cat /proc/qperf_metrics; echo QPERF_END:blk-read' +``` + +For net: + +```bash +python3 tools/starry-syscall-harness/harness.py perf-profile \ + --arch riscv64 \ + --timeout 90 \ + --qperf-metrics \ + --start-marker QPERF_BEGIN \ + --stop-marker QPERF_END \ + --workload-timeout 45 \ + --shell-init-cmd 'echo reset > /proc/qperf_metrics; echo QPERF_BEGIN:net-wget; wget -O /dev/null http://10.0.2.2:8000/tmp/axbuild/rootfs/rootfs-riscv64-alpine.img.tar.xz; cat /proc/qperf_metrics; echo QPERF_END:net-wget' +``` + +When this command is run through the default Docker wrapper, the HTTP server for +`10.0.2.2:8000` must be inside the same container namespace as QEMU. One usable +pattern is to start `python3 -m http.server 8000 --bind 0.0.0.0` in the wrapper +before invoking `harness.py --no-docker`. + +The parser merges `QPERF_METRIC key=value` fields into `report.json.workload_metrics.values`. + +## Counter Interpretation + +The current counters are driver-visible counters exported by StarryOS through +`/proc/qperf_metrics`. They are useful for A/B validation, but they should not +be described as exact virtqueue ring-level accounting. + +Important blk counters: + +- `virtqueue_add_notify_wait_pop_count`: synchronous virtqueue submit/notify/wait/pop path count. +- `virtqueue_add_count`: driver-visible virtqueue add count. +- `virtio_notify_kick_count`: driver-visible notify/kick count. +- `virtqueue_pop_complete_count`: driver-visible completion pop count. +- `virtqueue_depth_max` and `virtqueue_depth_hist_*`: approximate queue depth observation. +- `virtio_blk_read_requests` and `virtio_blk_read_bytes`: blk read request count and bytes recorded by the driver. + +One existing marker-aware blk profile at +`target/qperf-validation/blk/perf/riscv64/latest/report.json` reported: + +| metric | value | +| --- | ---: | +| `dd` bytes | 53,601,104 | +| `dd` elapsed | 5.794463 s | +| `virtqueue_add_notify_wait_pop_count` | 13,780 | +| `virtio_notify_kick_count` | 13,847 | +| `virtio_blk_read_requests` | 13,478 | +| `virtio_blk_read_bytes` | 55,195,136 | +| average blk read request size | 4,095.20 bytes | + +This is a useful bottleneck signal: even when the guest command uses +`bs=64k`, the driver-visible blk request size is still about 4 KiB and the +number of notify/kick events is close to the number of virtqueue adds. See +`docs/qperf-current-blk-bottleneck-analysis.md` for the full analysis. + +## Host Perf + +Host perf is opt-in: + +```bash +python3 tools/starry-syscall-harness/harness.py perf-profile \ + --arch riscv64 \ + --host-time \ + --host-perf \ + --host-perf-events task-clock,cycles,instructions,cache-references,cache-misses +``` + +These counters measure the host QEMU process. They are not guest PMU counters. + +## A/B Compare + +```bash +python3 tools/starry-syscall-harness/harness.py perf-compare \ + --baseline target/starry-syscall-harness/perf/riscv64/baseline/report.json \ + --candidate target/starry-syscall-harness/perf/riscv64/candidate/report.json \ + --name blk-read-ab +``` + +The comparison output is under: + +```text +target/starry-syscall-harness/perf-compare/blk-read-ab/ +``` + +`compare.md` gives an automatic conclusion: `明显改善`, `基本无变化`, `退化`, or `数据不足`. + +## Limitations + +- Runtime qperf plugin enable/disable is not implemented; filtering is done by sample timestamps during analyzer postprocess. +- Driver-visible queue depth and notify/kick counters are approximate. Exact ring-level accounting requires adding counters inside `virtio-drivers`. +- Place `cat /proc/qperf_metrics` before the stop marker. The harness asks QEMU to quit once the stop marker is observed. +- If `/dev/vhost-vsock` is missing on the host, vsock experiments should record the environment blocker and must not fabricate vsock throughput or counters. diff --git a/docs/qperf-sampling-debug-notes.md b/docs/qperf-sampling-debug-notes.md new file mode 100644 index 0000000000..90f1b66531 --- /dev/null +++ b/docs/qperf-sampling-debug-notes.md @@ -0,0 +1,557 @@ +# StarryOS qperf 采样问题处理记录 + +本文记录在把 qperf 接入 StarryOS harness 过程中实际遇到的采样、符号解析、火焰图和自动化运行问题,以及背后的 OS 语义。这里的重点不是“怎么跑出一张图”,而是说明为什么这些图一开始会不可信,以及如何让它们变成可用于定位内核瓶颈的证据。 + +当前 qperf 链路如下: + +```text +StarryOS build/rootfs + -> QEMU system-mode run + -> QEMU TCG plugin callbacks from tools/qperf + -> qperf.bin raw guest stack samples + -> qperf-analyzer symbolization + -> stack.folded / flamegraph.svg / report.json + -> harness report and optional Web UI +``` + +这条链路不是 host `perf`。host `perf` 看到的主要是 QEMU 进程、TCG dispatch、host libc 和模拟器内部函数;qperf 看到的是 QEMU 暴露出来的 guest PC 和 guest 栈。因此,qperf 的核心问题是 OS instrumentation,而不是普通应用 profiler 集成。 + +## 1. 为什么不能直接用 host perf + +### 现象 + +如果直接在宿主机上 profile QEMU,热点会落到 QEMU 自身,例如 TCG 翻译缓存、dispatch loop、helper 函数或 host libc。这样的结果回答的是: + +```text +QEMU 这个宿主进程在哪里耗时? +``` + +但我们真正想回答的是: + +```text +StarryOS 这个 guest kernel 在哪些内核路径上执行得最多? +``` + +### OS 语义 + +StarryOS 运行在 QEMU system-mode 里。guest kernel 的函数不是 host 进程里的 native symbol。QEMU 把 guest basic block 翻译成 host code cache 后执行,host PC 指向的是 QEMU 生成的代码;真正有意义的 StarryOS PC 是 guest PC。 + +因此采样点必须放在 QEMU TCG plugin 层:既不能太高,只看到 host QEMU;也不能太低,丢失 guest OS 的函数语义。 + +### 处理方式 + +`cargo xtask starry perf` 在 QEMU 命令里注入: + +```text +qemu-system- -plugin libqperf.so,... +``` + +qperf 通过 translation block 或 instruction callback 采 guest IP,再由 analyzer 按 StarryOS kernel ELF 解析符号。 + +## 2. guest IP 不一定等于 ELF 链接地址 + +### 现象 + +早期 qperf 输出里出现过这类热点: + +```text +70.10% _start+0x1000 +7.75% 0x800065ae +0.56% 0x800004f8 +``` + +这说明采样不是空的,但符号化质量很差。火焰图也会被 `_start+offset` 或裸地址占据,无法定位到真正的 Rust/内核函数。 + +### 根因 + +StarryOS kernel ELF 按 kernel virtual base 链接,符号表和 DWARF 都以虚拟链接地址为基准。但 QEMU plugin callback 中拿到的 guest IP 可能落在 kernel `.text` 的物理别名范围。 + +从 CPU/MMU 的角度看,这些地址都可能指向同一段内核代码;但从 ELF symbolizer 的角度看,只有链接时的虚拟地址能直接查到函数名。 + +这是典型内核 profiling 问题:运行时执行地址、物理装载地址、虚拟链接地址不是同一个概念。 + +### 修复 + +`scripts/axbuild/src/starry/perf.rs` 现在会检测: + +- kernel ELF 的 `.text` 虚拟范围; +- `plat.kernel-base-vaddr`; +- `plat.kernel-base-paddr`; +- `.text` 对应的物理别名范围; +- 从物理别名映射回 ELF 虚拟地址所需的 offset。 + +然后把这些参数传给 qperf plugin: + +```text +filter_start=0x +filter_end=0x +filter_alias_start=0x +filter_alias_end=0x +filter_alias_offset=0x +``` + +plugin 采样时做 canonicalization: + +```text +physical .text alias + (kernel_vaddr - kernel_paddr) -> ELF virtual address +``` + +这样 analyzer 收到的地址才和 ELF/DWARF 的地址空间一致。 + +### OS 结论 + +内核性能分析必须先解决地址空间语义。没有这一步,profile 文件可能格式正确、样本数量也不少,但语义上是错的。 + +## 3. 过早 kernel filter 会丢掉真实样本 + +### 现象 + +开启 kernel-only filter 后,有时 `stack.folded` 样本很少,甚至看起来像没有采到内核热点。 + +### 根因 + +如果只按 ELF 虚拟 `.text` 范围过滤,就默认 QEMU 回调中的所有 kernel PC 都落在虚拟地址范围。但物理 alias 存在时,合法 kernel 样本可能先以物理地址出现。如果在 canonicalize 前把它丢掉,就永远无法恢复。 + +### 修复 + +harness 默认不强制 kernel-only filter,而是先广泛采样,再对已知 kernel `.text` alias 做地址规范化。只有显式传入 `--kernel-filter` 时才过滤,而且过滤条件同时接受: + +- `.text` virtual range; +- `.text` physical alias range。 + +### OS 结论 + +对内核来说,“这是不是 kernel text”不能只看一个地址区间。需要同时知道物理装载、虚拟映射和链接地址三者之间的关系。 + +## 4. TB 采样和 instruction 采样的取舍 + +### 现象 + +instruction mode 更细,但 QEMU 明显更慢;TB mode 开销低,但粒度更粗。 + +### 根因 + +QEMU TCG 的 translation block 是一段 guest 指令的翻译单元。对每条指令注册 callback 会显著增加回调次数。对于内核 workload,这会改变 guest 的运行节奏,影响调度、时钟中断、I/O 批处理和锁竞争。 + +### 处理方式 + +qperf 支持两种模式: + +```text +mode=tb +mode=insn +``` + +harness 默认使用 `tb`。它足够发现大块热点,例如锁、copy、VirtIO、页表或文件系统路径。`insn` 保留给短时间、针对性更强的调查。 + +### OS 结论 + +profile 不能变成 workload 本身。一个 profiler 如果改变了 guest kernel 的阻塞点、调度点或 I/O 时序,就可能制造出它正在报告的瓶颈。 + +## 5. 采样频率会和 guest 周期行为混叠 + +### 现象 + +某些整数频率下,热点看起来异常稳定地集中在少量路径上,像是采样总打在同一个运行阶段。 + +### 根因 + +采样频率如果和 guest timer tick、QEMU 调度间隔或 workload 周期对齐,就会发生 sampling aliasing。采样结果会过度代表某个相位。 + +### 处理方式 + +默认频率使用 `99 Hz`,避免最简单的 `100 Hz` 周期锁定。harness 同时暴露 `--freq`,当结果可疑时可以换一个频率复跑。 + +### OS 结论 + +采样 profile 是统计证据,不是精确 trace。要考虑偏差、方差和观测者效应。 + +## 6. 栈回溯依赖 ABI、frame pointer 和页表可见性 + +### 现象 + +部分样本只能解析 top frame;有些 stack 很短,甚至中间断掉。 + +### 根因 + +qperf 的 stack unwind 不是读 DWARF unwind info,而是读取 guest frame pointer 并沿 guest stack 走 frame record。这依赖: + +- 目标架构 ABI; +- 编译器是否保留 frame pointer; +- kernel stack 当前是否通过 guest virtual address 可读; +- frame record 中 saved FP / saved RA 的布局; +- 当前执行点是否处于普通函数栈帧中。 + +以 RISC-V 为例,`s0/fp` 是常用 frame pointer。plugin 通过 QEMU register API 读 FP,再用 `qemu_plugin_read_memory_vaddr` 读 guest 栈内存。如果 FP 指向未映射地址、栈帧损坏、进入异常路径或优化破坏了常规 frame layout,回溯就必须停止。 + +### 修复 + +`tools/qperf/src/profiler.rs` 里做了保守检查: + +- 使用 target-specific register/frame 描述; +- 要求 FP 对齐; +- 用 `seen_fps` 防止循环; +- next FP 必须向前推进; +- guest memory 读取失败就停止; +- saved return address 读不到可执行地址就停止; +- 用 `max_depth` 限制最大深度。 + +这里宁可少给一层 stack,也不能伪造错误的调用链。 + +### OS 结论 + +内核栈只是按 ABI 解释的一段内存。profiler 走栈时,本质上也是 MMU/page table 和 ABI 的使用者。 + +## 7. return address 符号化需要 IP 修正 + +### 现象 + +caller frame 有时会解析到 call 之后的位置,甚至落到相邻符号。 + +### 根因 + +保存的 return address 指向 call 返回后的下一条指令。符号化 caller 时,更有意义的是 call site,因此通常要用 `return_address - 1`。但 top frame 是当前采样 PC,不应该减 1。 + +### 修复 + +`qperf-analyzer` 中: + +- 第一个 IP 作为当前 PC 原样解析; +- 非 top frame 用 `ip - 1` 查符号。 + +这不是为了精确还原指令长度,而是把地址拉回 call 指令所在的符号范围。 + +## 8. DWARF 不足时需要 symtab fallback + +### 现象 + +即使地址已经规范化,仍然会出现裸地址或 `??`。 + +### 根因 + +release build 更接近真实性能,但 debug info 可能不完整;Rust 泛型、内联、monomorphization 和链接优化也会让 `addr2line` 无法给出完整函数名。 + +### 修复 + +analyzer 解析顺序: + +```text +addr2line frame lookup + -> 失败或为空时,查 ELF symtab 中 <= IP 的最近 text symbol + -> 输出 symbol+offset + -> 仍失败时,输出 0x +``` + +这样即使没有完整行号,也尽量保留函数级定位能力。 + +### OS 结论 + +原始 IP 是事实,函数名是解释。内核性能分析要把符号化结果当作 best effort,而不是绝对真相。 + +## 9. timeout 会截断 raw sample + +### 现象 + +QEMU 被 timeout 停掉时,可能有 `qperf.bin`,但没有完整 plugin summary;或者 analyzer 在文件尾部 decode 失败。 + +### 根因 + +自动化 harness 必须有 timeout,否则 agent 可能卡死。但 timeout 终止 QEMU 不等于 guest 正常关机: + +- QEMU plugin shutdown 可能来不及完成; +- writer thread 可能没写完 summary; +- 最后一个 bincode record 可能只写了一半; +- QEMU 返回非零退出码,但已经产生了有效样本。 + +### 修复 + +链路上做了几层容错: + +- plugin writer 每写一个 sample 就 flush; +- plugin 正常退出时写 `qperf.summary.txt`; +- `cargo xtask starry perf` 在 QEMU 非零退出但 raw sample 非空时继续分析; +- analyzer 如果已经解出至少一个 record,则把尾部 decode error 当作 partial tail; +- summary 中显式记录 plugin summary 是否缺失。 + +### OS 结论 + +性能 harness 是系统程序,必须有 timeout-aware artifact 语义。部分 profile 只要被明确标注,就比整次样本丢失更有价值。 + +## 10. callback 路径不能阻塞 vCPU + +### 现象 + +如果直接在 callback 中写文件,QEMU vCPU 会被 I/O 阻塞,profile 会明显扰动 guest。 + +### 根因 + +QEMU plugin callback 位于 guest translated code 执行路径上。它类似一个 probe/interrupt path:不能做重 I/O,不能长时间持锁,也不能在高频路径上产生不可控分配。 + +### 修复 + +plugin callback 只把 stack sample `try_send` 到 bounded channel,后台 writer thread 负责写 `qperf.bin`。队列满时丢样本,并记录 `dropped_samples`。 + +当前队列大小: + +```text +queue_size = 4096 +``` + +这个设计的原则是:宁可丢样本,也不能把 guest CPU 卡在 profiler 上。 + +### OS 结论 + +采样路径要像中断路径一样短。丢事件是可度量误差;阻塞 vCPU 会改变系统行为。 + +## 11. raw sample 编码必须版本一致 + +### 现象 + +review 中指出 qperf plugin 和 analyzer 不应分别硬编码 `bincode = "2.0.1"`。 + +### 根因 + +`qperf.bin` 是 plugin 写、analyzer 读的私有二进制格式。如果编码库版本或配置漂移,结果可能无法解析,或者更糟糕地被错误解析。 + +### 修复 + +两个 qperf crate 都使用 workspace 依赖: + +```toml +bincode.workspace = true +``` + +同时 summary 中保留 `qperf_format_version = 1`,给后续格式演进留入口。 + +### OS 结论 + +profiling artifact 是工具链 ABI。producer 和 consumer 的格式一致性应该像 syscall ABI 一样被认真维护。 + +## 12. analyzer 没启用 feature 时不会生成 flamegraph + +### 现象 + +`--format all` 跑完后有 folded stack,但前端性能页没有 flame graph。 + +### 根因 + +内置 flamegraph 依赖 analyzer 的 `flamegraph` feature。如果 `qperf-analyzer` 构建时没启用这个 feature,传入 `--flamegraph` 也不会产生 SVG,只能依赖外部 `flamegraph.pl` 或 `inferno-flamegraph`。 + +在容器化 harness 里,依赖外部命令很脆弱。 + +### 修复 + +当 `cargo xtask starry perf` 的输出格式是 `svg` 或 `all` 时,构建 analyzer 会自动加: + +```text +--features flamegraph +``` + +外部 generator 仍作为 fallback,但主路径已经自包含。 + +## 13. 火焰图有了,但视觉上挤在一起 + +### 现象 + +SVG 能生成,但前端展示时 frame 很窄,多个路径挤在一起,不容易看出调用层级。 + +### 根因 + +短时间 qperf run 里,样本可能集中在几个大 bucket,同时有许多小 stack。默认 flamegraph 参数会把这些 frame 压缩到较窄画布里,视觉上像是所有东西堆在一起。 + +### 修复 + +analyzer 使用更适合本场景的 inferno 参数: + +```text +image_width = 3200 +frame_height = 24 +font_size = 13 +min_width = 0.35 +hash = true +deterministic = true +``` + +UI 按 SVG 自身宽度展示,并允许横向滚动,而不是强行缩放进 viewport。 + +### OS 结论 + +可视化也是 measurement pipeline 的一部分。如果 UI 把 stack 结构压没了,后续优化就容易对错路径下手。 + +## 14. stale StarryOS defconfig 会让 qperf 跑错机器 + +### 现象 + +rebase 到 dynamic platform 相关改动后,qperf 路径曾经因为旧生成配置引用了已经不存在的 QEMU feature 而失败。 + +### 根因 + +`tmp/axbuild` 下的配置是生成状态。平台配置变更后,如果继续复用旧 defconfig/build config,实际构建出来的内核配置可能不是当前源码期望的配置。 + +对 qperf 来说,这非常危险:profile 必须绑定明确的机器模型、设备和内核配置。 + +### 修复 + +harness 在 rootfs 和 `starry perf` 前刷新 `qemu-*` defconfig。 + +### OS 结论 + +profiling 前必须固定 boot/configuration state。用旧平台配置跑出来的 profile,本质上是在 profile 另一台机器。 + +## 15. release 和 debug 回答的是不同问题 + +### 现象 + +debug build 符号更多,但热点不代表真实性能;release build 更真实,但符号化难度更高。 + +### 根因 + +编译优化会改变: + +- 函数边界; +- 内联; +- 寄存器分配; +- 锁和 copy fast path; +- 栈帧形态; +- panic/debug 路径的存在感。 + +debug profile 往往在观察“可调试内核”,release profile 才更接近“实际运行内核”。 + +### 处理方式 + +harness 默认使用 release profile。`--debug` 只用于调查符号化、栈形态或构建问题,不用于最终性能结论。 + +### OS 结论 + +内核性能结论必须来自接近真实运行状态的二进制。debug 信息多不等于性能证据强。 + +## 16. qperf profile 不是 Linux baseline + +### 现象 + +有了 StarryOS flamegraph 后,很容易误以为这已经能说明“和 Linux 对齐”。 + +### 根因 + +qperf profile 表示 StarryOS 在 QEMU TCG 下的 guest sample 分布。Linux 对齐需要可比较 workload 和 baseline。单次 StarryOS profile 只能说明 StarryOS 自己的热点形状,不能直接说明 Linux 同 workload 下会怎样。 + +### 处理方式 + +harness report 中明确保留: + +```text +linux_alignment.status = baseline_required +``` + +性能优化闭环应该是: + +```text +baseline profile + -> patch + -> candidate profile + -> perf-diff + -> code inspection + -> rerun +``` + +### OS 结论 + +性能是比较问题。火焰图是生成假设的工具,不是证明 OS 已经达到 Linux 性能水平的结论。 + +## 17. 如何判断一份 qperf 报告是否可信 + +在根据热点改代码前,应先检查: + +1. `samples` 是否大于 0。 +2. `dropped_samples` 是否很高;高丢样本说明 profile 可能偏。 +3. `plugin_summary` 是否存在;缺失通常表示 QEMU 被 timeout 停掉。 +4. top functions 是真实函数名,还是 `_start+offset` / 裸地址。 +5. stderr/summary 里 `.text` virtual range 和 physical alias 是否合理。 +6. 当前是 release 还是 debug build。 +7. 是否可能和 guest timer/workload 周期混叠;可换 `--freq` 复跑。 +8. 是否开启了 `--kernel-filter`;若开启,需要确认 alias mapping 没把样本过滤掉。 +9. rule-based fix candidate 只当 triage,不直接当结论。 +10. 修改后必须用下一次 qperf profile 和 `perf-diff` 验证。 + +## 18. 产物语义 + +harness 性能 run 的关键文件: + +```text +target/starry-syscall-harness/perf//latest/ + report.json + report.md + hotspots.csv + profile.stdout + profile.stderr + qperf/ + qperf.bin + qperf.summary.txt + summary.txt + stack.folded + flamegraph.svg +``` + +各文件含义: + +- `qperf.bin`:plugin 写出的原始 guest stack sample stream。 +- `qperf.summary.txt`:plugin 正常 shutdown 时写出的采样统计。 +- `summary.txt`:`cargo xtask starry perf` 写出的运行级摘要。 +- `stack.folded`:analyzer 输出的 folded stack,是 flamegraph 和 diff 的输入。 +- `hotspots.csv`:便于脚本或表格处理的热点列表。 +- `report.json`:harness 级机器可读报告,给 MCP/agent/UI 使用。 +- `profile.stdout` / `profile.stderr`:保留完整底层命令输出,用于排查 QEMU、地址范围、符号化和 feature 构建问题。 + +## 19. 推荐命令 + +常规 profile: + +```bash +python3 tools/starry-syscall-harness/harness.py perf-profile \ + --arch riscv64 \ + --timeout 20 \ + --format all \ + --freq 99 \ + --max-depth 64 \ + --mode tb \ + --top 20 +``` + +短时间 instruction mode profile: + +```bash +python3 tools/starry-syscall-harness/harness.py perf-profile \ + --arch riscv64 \ + --timeout 10 \ + --format folded \ + --freq 101 \ + --max-depth 64 \ + --mode insn \ + --top 20 +``` + +比较两次 profile: + +```bash +python3 tools/starry-syscall-harness/harness.py perf-diff \ + --baseline target/starry-syscall-harness/perf/riscv64/baseline \ + --compare target/starry-syscall-harness/perf/riscv64/latest \ + --top 20 +``` + +所有 StarryOS/QEMU/qperf 运行仍应通过 harness 进入 Docker,不应直接在宿主机跑 StarryOS 测试。 + +## 20. 总结 + +这次 qperf 接入中,真正关键的问题不是“生成 flamegraph”,而是让 flamegraph 的每一层都有正确 OS 语义: + +- IP 属于 guest,不属于 host QEMU; +- guest IP 需要映射回 kernel ELF 的虚拟链接地址; +- kernel text 可能有物理 alias; +- stack unwind 依赖 ABI、frame pointer 和 guest 页表可读性; +- callback 路径不能阻塞 guest vCPU; +- timeout 会造成 partial artifact,工具链必须能诚实处理; +- release/debug profile 不能混为一谈; +- StarryOS profile 不是 Linux baseline,只能作为对齐流程中的一环。 + +处理完这些问题后,qperf 才能成为自动化性能优化闭环的一部分:采样 guest kernel,解析内核调用路径,生成可视化和结构化热点,提出候选瓶颈,修改代码,再用下一次 profile 和 diff 验证。 diff --git a/docs/qperf-tooling-improvement-report.md b/docs/qperf-tooling-improvement-report.md new file mode 100644 index 0000000000..a07419e62b --- /dev/null +++ b/docs/qperf-tooling-improvement-report.md @@ -0,0 +1,331 @@ +# qperf Tooling Improvement Report + +## 当前问题复盘 + +原 qperf 更接近“从 QEMU 启动到退出的栈采样器”。对 virtio-blk/net/vsock 做性能归因时有三个直接问题: + +- 采样窗口默认覆盖 boot,PCI probe、调度、allocator、rootfs 初始化会混入数据面结论。 +- 输出主要是 folded stack、火焰图和符号热点,不能直接回答 queue depth、notify/kick、copy bytes、inflight 操作次数等工程问题。 +- 优化前后需要人工翻多个报告,缺少字段级 delta、百分比变化和数据不足提示。 + +## 改造目标 + +本轮改造的目标是形成一个最小可闭环的实验工具: + +- 用 guest stdout marker 定义 workload 窗口,默认避免 boot 污染。 +- 保留原有 qperf 输出,同时增加类别归因、workload metrics、归一化指标。 +- 用 feature-gated 轻量 counter 记录 virtio-blk/net 的关键路径事件。 +- 增加 A/B compare,支撑优化验证。 +- 对 vsock 环境阻塞显式记录,不伪造吞吐或 counter。 + +## 实现方案 + +### marker/window + +`cargo xtask starry perf` 与 `harness.py perf-profile` 新增: + +- `--start-marker TEXT` +- `--stop-marker TEXT` +- `--workload-timeout SECONDS` +- `--qperf-metrics` + +qperf plugin raw record 升级为带 `elapsed_ns` 的 v2 格式。`qperf-analyzer resolve` 新增 `--start-sec`、`--stop-sec`、`--stats`,按 marker 时间在 postprocess 阶段过滤 folded stack 和 flamegraph。旧 raw 格式仍可解析,但不能做时间窗口过滤。 + +marker 模式下,harness 会在 shell prompt 出现后注入 workload,并先关闭串口回显,避免 shell 把整行命令回显出来导致 `QPERF_END` 被提前匹配。stop marker 出现后,harness 优先通过 QMP `quit` 停 QEMU,失败再退回 SIGINT。 + +### 分类聚合 + +报告新增 `hotspot_categories.csv`,并在 `report.json.hotspots.category_totals` 和 `report.md` 写入 inclusive category 聚合。当前类别包括: + +- `virtqueue_add_notify_wait_pop` +- `virtqueue_add` +- `virtqueue_pop_complete` +- `virtio_notify_kick` +- `memcpy` +- `memmove` +- `allocator` +- `scheduler_wait_preempt` +- `lock_mutex_wait` +- `pci_probe_transport` +- `net_inflight_btree` +- `block_io_path` +- `net_rx_tx_path` +- `vsock_tx_rx_path` + +类别是工程归因视角,和符号热点并列展示;一个栈可以同时计入 subsystem 和 bottleneck 类别。 + +### workload metrics + +harness 解析 guest stdout: + +- `dd`:bytes、seconds、reported MB/s、派生 B/s。 +- `wget`:saved 状态、BusyBox 进度条里的大小;若 wget 不输出耗时,则使用 marker window duration 作为 `elapsed_source=marker_window`。 +- `QPERF_METRIC key=value`:合入 `report.json.workload_metrics.values`。 + +新增归一化字段: + +- `guest_instructions_per_MB` +- `guest_blocks_per_MB` +- `host_elapsed_sec_per_MB` +- `samples_per_MB` +- `category_samples_per_MB` + +本轮示例未启用 `--host-perf`,报告中明确记录 `未启用 host perf`。 + +### virtio counters + +`ax-driver` 新增默认关闭的 `qperf-metrics` feature。启用后通过 `AtomicU64` 记录 driver-visible counter,并由 StarryOS `/proc/qperf_metrics` 导出 `QPERF_METRIC`: + +- virtqueue add/notify/pop/add_notify_wait_pop 近似计数。 +- driver 可见 inflight depth max 和 histogram。 +- blk read/write request count 和 bytes。 +- net RX/TX packet count 和 bytes。 +- net RX `copy_within` count 和 bytes。 +- net TX staging copy count 和 bytes。 +- net inflight map insert/remove/get count。 + +这些 counter 是 driver glue 层视角的近似值。精确 descriptor-ring depth、精确 notify/kick 和 `VirtQueue::add_notify_wait_pop()` 内部事件仍需要在 `virtio-drivers` crate 内增加 instrumentation。 + +### A/B compare + +新增: + +```bash +python3 tools/starry-syscall-harness/harness.py perf-compare \ + --baseline \ + --candidate \ + --name +``` + +输出: + +- `compare.json` +- `compare.md` +- `compare.csv` + +对比字段包括 workload throughput/elapsed、guest executed instructions/blocks、host elapsed/user/sys、hotspot categories、virtio counters、copy bytes、notify/kick count、queue depth max/histogram。缺失字段显示 `N/A`。 + +已做 smoke test: + +```text +target/qperf-tooling-experiments/blk/compare-self/perf-compare/blk-self-smoke/compare.md +``` + +结论为 `基本无变化`,这是同一份 blk report 自比较的预期结果。 + +## 新增 JSON 字段说明 + +`report.json.window`: + +- `start_marker` / `stop_marker`:marker 文本。 +- `start_time` / `stop_time`:相对 QEMU 启动的秒数。 +- `duration_sec`:workload 窗口时长。 +- `workload_timeout`:窗口超时配置。 +- `truncated_by_timeout`:是否由 workload timeout 截断。 +- `boot_samples_excluded`:过滤掉的 start marker 之前样本数。 +- `post_window_samples_excluded`:过滤掉的 stop marker 之后样本数。 +- `stop_method`:如 `qmp_quit`。 +- `warnings`:marker 缺失、旧 raw 格式等风险。 + +`report.json.workload_metrics`: + +- `dd[]` +- `wget[]` +- `custom[]` +- `values` +- `raw_metric_lines` + +`report.json.normalized_metrics`: + +- `workload_bytes` +- `workload_elapsed_seconds` +- `samples_per_MB` +- `host_elapsed_sec_per_MB` +- `guest_instructions_per_MB` +- `guest_blocks_per_MB` +- `category_samples_per_MB` + +## 示例实验结果 + +实验环境: + +- arch: `riscv64` +- qperf freq: `99` +- mode: `tb` +- `--host-time` enabled +- `--host-perf` disabled +- `--qperf-metrics` enabled +- net 用例在同一个 Docker 容器内启动临时 `python3 -m http.server 8000`,确保 guest 的 `10.0.2.2:8000` 可达。 + +### blk focused workload + +命令: + +```bash +python3 tools/starry-syscall-harness/harness.py perf-profile \ + --arch riscv64 \ + --timeout 90 \ + --format folded \ + --top 20 \ + --host-time \ + --qperf-metrics \ + --start-marker QPERF_BEGIN \ + --stop-marker QPERF_END \ + --workload-timeout 45 \ + --output-dir target/qperf-tooling-experiments/blk \ + --shell-init-cmd 'echo reset > /proc/qperf_metrics; echo QPERF_BEGIN:blk-read; dd if=/usr/bin/lto-dump of=/dev/null bs=64k; cat /proc/qperf_metrics; echo QPERF_END:blk-read' +``` + +产物: + +```text +target/qperf-tooling-experiments/blk/perf/riscv64/latest/report.json +``` + +实际结果: + +- samples: `589` +- window: `1.58549195 -> 7.539382377`, duration `5.953890427s` +- boot samples excluded: `156` +- post-window samples excluded: `496` +- dd: `53601104 bytes`, `5.805581s`, `9232685.58 B/s` +- host elapsed: `12.552265s` +- samples_per_MB: `10.98858` +- host_elapsed_sec_per_MB: `0.234179` + +主要类别: + +| Category | Samples | Percent | +|---|---:|---:| +| `memcpy` | 166 | 28.18% | +| `virtio_notify_kick` | 145 | 24.62% | +| `virtqueue_add_notify_wait_pop` | 144 | 24.45% | +| `block_io_path` | 115 | 19.52% | +| `allocator` | 89 | 15.11% | + +关键 counter: + +| Counter | Value | +|---|---:| +| `virtqueue_add_notify_wait_pop_count` | 13780 | +| `virtqueue_add_count` | 13847 | +| `virtio_notify_kick_count` | 13847 | +| `virtqueue_pop_complete_count` | 13783 | +| `virtqueue_depth_max` | 63 | +| `virtio_blk_read_requests` | 13478 | +| `virtio_blk_read_bytes` | 55195136 | +| `virtio_blk_write_requests` | 302 | +| `virtio_blk_write_bytes` | 1236992 | + +结论:blk 数据面窗口里 `add_notify_wait_pop` 和 notify/kick 占比明确可见,且 counter 显示 read request 数与同步等待次数基本同量级,支持继续验证异步化、批处理和更高 queue depth 的优化方向。 + +### net focused workload + +命令核心: + +```bash +python3 tools/starry-syscall-harness/harness.py perf-profile \ + --arch riscv64 \ + --timeout 120 \ + --format folded \ + --top 20 \ + --host-time \ + --qperf-metrics \ + --start-marker QPERF_BEGIN \ + --stop-marker QPERF_END \ + --workload-timeout 60 \ + --output-dir target/qperf-tooling-experiments/net \ + --shell-init-cmd 'echo reset > /proc/qperf_metrics; echo QPERF_BEGIN:net-wget; wget -O /dev/null http://10.0.2.2:8000/tmp/axbuild/rootfs/rootfs-riscv64-alpine.img.tar.xz; cat /proc/qperf_metrics; echo QPERF_END:net-wget' +``` + +产物: + +```text +target/qperf-tooling-experiments/net/perf/riscv64/latest/report.json +``` + +实际结果: + +- samples: `719` +- window: `1.566331117 -> 8.825886896`, duration `7.259555779s` +- boot samples excluded: `154` +- post-window samples excluded: `494` +- wget: BusyBox progress `60.6M`, parsed as `63543705 bytes` +- wget elapsed source: `marker_window` +- wget throughput: `8753112.03 B/s` +- host elapsed: `13.836669s` +- samples_per_MB: `11.315047` +- host_elapsed_sec_per_MB: `0.21775` + +主要类别: + +| Category | Samples | Percent | +|---|---:|---:| +| `memcpy` | 231 | 32.13% | +| `net_rx_tx_path` | 169 | 23.50% | +| `allocator` | 117 | 16.27% | +| `memmove` | 53 | 7.37% | +| `scheduler_wait_preempt` | 24 | 3.34% | + +关键 counter: + +| Counter | Value | +|---|---:| +| `virtqueue_add_notify_wait_pop_count` | 605 | +| `virtqueue_add_count` | 47289 | +| `virtio_notify_kick_count` | 47289 | +| `virtqueue_pop_complete_count` | 47225 | +| `virtqueue_depth_max` | 63 | +| `virtio_net_rx_packets` | 44141 | +| `virtio_net_rx_bytes` | 65937102 | +| `virtio_net_rx_copy_within_bytes` | 65937102 | +| `virtio_net_tx_staging_copy_bytes` | 149442 | +| `virtio_net_inflight_insert_count` | 46684 | +| `virtio_net_inflight_remove_count` | 46620 | +| `virtio_net_inflight_get_count` | 46620 | + +结论:net 数据面里的 copy 成本已被同时体现在符号热点、类别聚合和 counter 中。RX `copy_within` bytes 与 RX bytes 同量级,说明 RX 路径每包仍有完整搬移;TX staging copy 相对下载流量较小。inflight map 操作次数和包数同量级,后续应针对该结构做替换或减少访问频率的 A/B 验证。 + +## 新旧报告对比 + +旧报告只能回答“哪些 guest 函数/栈采样最多”,且默认混入 boot-to-exit 样本。新报告可以直接看到: + +- marker window 起止时间、时长、boot/post-window 排除样本数。 +- 符号热点与工程类别热点分离展示。 +- workload bytes、elapsed、throughput 和 per-MB 归一化指标。 +- virtio counter 与 copy bytes。 +- host perf 未启用时的显式说明。 +- A/B compare 的 delta、百分比变化和 `N/A` 缺失字段。 + +本轮没有生成“旧工具同 workload”的历史 baseline,因此没有伪造旧版数字。已有 `blk-self-smoke` compare 只用于验证 compare 工具输出路径和缺失字段处理。 + +## 局限性 + +- qperf plugin 仍未支持运行时暂停/恢复;当前是 timestamped raw sample + analyzer postprocess 过滤。 +- driver-visible queue depth/notify/kick 是近似 counter,不等价于 virtio ring 内部精确事件。 +- `guest_instructions_per_MB` 和 `guest_blocks_per_MB` 当前为 `N/A`,需要 qperf summary 稳定导出 executed instruction/block 字段后才能归一化。 +- net wget 的 BusyBox 输出没有真实下载耗时,本轮用 marker window duration 派生 elapsed/throughput,并在 JSON 中记录 `elapsed_source=marker_window`。 +- host perf 本轮未启用;报告只合入 host wall/user/sys time。 +- 当前宿主机没有 `/dev/vhost-vsock`:`ls /dev/vhost-vsock` 返回 `No such file or directory`。因此本轮没有 vsock 吞吐数据,也没有编造 vsock counter。 +- `target/qperf-tooling-experiments` 曾由 Docker root 创建,直接写顶层 compare 目录会遇到权限问题;后续可统一在 wrapper 里 chown 输出根目录。 + +## 后续优化建议 + +virtio-blk: + +- 将同步 `add_notify_wait_pop` 路径改为可批处理或异步 completion,先用 `virtqueue_add_notify_wait_pop_count`、throughput 和 `block_io_path` category 做 A/B。 +- 对连续 read 请求做合并或更大块提交,观察 request count、notify/kick count 是否下降。 +- 在 `virtio-drivers` 内加入精确 ring depth 和 kick counter,校准 driver-visible 近似值。 + +virtio-net: + +- 优先减少 RX `copy_within`,目标是让 `virtio_net_rx_copy_within_bytes / virtio_net_rx_bytes` 明显下降。 +- 减少 TX staging Vec copy,观察 `virtio_net_tx_staging_copy_bytes` 和 `memcpy` category。 +- 替换或减少 inflight `BTreeMap` 操作,使用 counter 和 `net_inflight_btree` category 做验证。 +- 将 RX/TX queue lock 拆分或缩短锁内 copy,观察 `net_rx_tx_path`、allocator、scheduler 类别变化。 + +virtio-vsock: + +- 先补齐 `/dev/vhost-vsock` 环境和可重复 workload。 +- 环境不可用时,report 应保留 blocker 字段或 stdout marker 说明,不输出吞吐。 +- 可用后按 net 的方式增加 vsock TX/RX bytes、packet、copy、queue counter,并纳入 compare。 diff --git a/docs/qperf-tooling-redesign.md b/docs/qperf-tooling-redesign.md new file mode 100644 index 0000000000..da0b01a6cd --- /dev/null +++ b/docs/qperf-tooling-redesign.md @@ -0,0 +1,117 @@ +# qperf Tooling Redesign + +## Goals + +This redesign turns qperf from a boot-to-exit stack sampler into a workload-oriented experiment tool for virtio-blk, virtio-net, and virtio-vsock attribution. + +The main changes are: + +- workload windows driven by guest stdout markers; +- timestamped qperf samples and analyzer-side time filtering; +- hotspot category aggregation in addition to symbol hotspots; +- workload stdout metric parsing for `dd`, `wget`, and `QPERF_METRIC`; +- feature-gated virtio counters exported through `/proc/qperf_metrics`; +- report-level A/B comparison for baseline and candidate runs. + +## Sampling Window + +`cargo xtask starry perf` and `harness.py perf-profile` accept: + +- `--start-marker TEXT` +- `--stop-marker TEXT` +- `--workload-timeout SECONDS` + +When a start marker is observed in guest stdout, the host records elapsed time since QEMU launch. When a stop marker is observed, qperf asks QEMU to quit through QMP, falling back to SIGINT if QMP is unavailable. + +For shell-injected workloads, the monitor disables shell echo before sending the command so marker matching is driven by workload output rather than by the echoed command line. + +The qperf plugin now writes raw records as format version 2: + +- `elapsed_ns` +- stack IP trace + +`qperf-analyzer resolve` accepts `--start-sec`, `--stop-sec`, and `--stats`. The generated folded stack and flamegraph are filtered to the marker window when timestamps are available. Older raw files are still accepted, but elapsed-time filtering cannot be applied to format version 1 samples. + +## Attribution Categories + +The harness parses `qperf/stack.folded` and writes inclusive category totals to: + +- `hotspot_categories.csv` +- `report.json.hotspots.category_totals` +- `report.md` + +The current category set is: + +- `virtqueue_add_notify_wait_pop` +- `virtqueue_add` +- `virtqueue_pop_complete` +- `virtio_notify_kick` +- `memcpy` +- `memmove` +- `allocator` +- `scheduler_wait_preempt` +- `lock_mutex_wait` +- `pci_probe_transport` +- `net_inflight_btree` +- `block_io_path` +- `net_rx_tx_path` +- `vsock_tx_rx_path` + +Categories are inclusive and non-exclusive: one stack can contribute to both a subsystem category, such as `net_rx_tx_path`, and a bottleneck category, such as `memmove`. + +## Workload Metrics + +The harness parses guest stdout for: + +- `dd` byte count, elapsed seconds, and throughput; +- `wget` length/saved byte count and elapsed seconds when visible; +- custom `QPERF_METRIC key=value` fields. + +Parsed values are stored in: + +- `report.json.workload_metrics` +- `report.json.normalized_metrics` + +Normalized fields include: + +- `guest_instructions_per_MB` +- `guest_blocks_per_MB` +- `host_elapsed_sec_per_MB` +- `samples_per_MB` +- `category_samples_per_MB` + +Host perf stat output is included only when `--host-perf` is enabled. Otherwise the report explicitly records `未启用 host perf`. + +## Virtio Counters + +The `qperf-metrics` feature is off by default. When enabled, `ax-driver` records lightweight `AtomicU64` counters in the virtio glue layer: + +- blk read/write request count and bytes; +- net RX/TX packet count and bytes; +- net RX `copy_within` count and bytes; +- net TX staging copy count and bytes; +- inflight map insert/remove/get count; +- approximate virtqueue add/notify/pop counts from driver submit/reclaim points; +- approximate queue depth max and histogram from driver-visible inflight depth. + +The counters are exported by StarryOS at `/proc/qperf_metrics` as `QPERF_METRIC` lines. Writing `reset` clears the counters. + +These counters are intentionally described as driver-visible approximations. Exact descriptor-ring depth, exact notify/kick count, and `VirtQueue::add_notify_wait_pop()` internals require instrumentation inside the `virtio-drivers` crate. + +## A/B Compare + +Use: + +```bash +python3 tools/starry-syscall-harness/harness.py perf-compare \ + --baseline target/starry-syscall-harness/perf/riscv64/baseline \ + --candidate target/starry-syscall-harness/perf/riscv64/candidate +``` + +Inputs can be a `report.json`, a profile directory, a qperf directory, or a folded stack file. Outputs are: + +- `compare.json` +- `compare.md` +- `compare.csv` + +The comparison includes workload throughput/elapsed time, guest executed instructions/blocks, host time/perf metrics, hotspot categories, virtio counters, copy bytes, notify/kick count, and queue depth fields when present. Missing fields are rendered as `N/A` instead of failing. diff --git a/docs/qperf-tooling-validation-report.md b/docs/qperf-tooling-validation-report.md new file mode 100644 index 0000000000..e956bc2bc2 --- /dev/null +++ b/docs/qperf-tooling-validation-report.md @@ -0,0 +1,262 @@ +# qperf 工具改造验收报告 + +## 1. 验收目标 + +本轮验收验证 qperf 工具改造是否已经从“启动即采样的火焰图工具”升级为可支撑 virtio-blk、virtio-net、virtio-vsock 性能归因和优化 A/B 验证的实验工具。重点回答: + +* 是否解决 boot 阶段样本污染 workload 数据面的问题。 +* 是否具备 marker 驱动的 workload window。 +* 是否具备工程分类热点,而不只是 symbol hotspot。 +* 是否具备 virtio-aware counters,并能进入最终 report。 +* 是否具备 A/B compare 输出。 +* 是否保持旧 perf-profile 命令兼容。 +* 是否足以支撑下一轮 virtio 优化验证。 + +## 2. 验收环境 + +| 项目 | 值 | +| --- | --- | +| 仓库 commit | `6e748d6b7a5b3a8e90e2cba3b030ea0ca9c3e617` | +| 分支 | `fix/starry-syscall-harness` | +| git status | 工作区非干净,包含本轮 qperf 改造文件和若干既有未跟踪文档;本报告未覆盖已有实验结果 | +| Host kernel | `Linux LAPTOP-SAOPKIGH 5.15.167.4-microsoft-standard-WSL2 x86_64` | +| CPU | Intel Core i7-14650HX, 24 vCPU, WSL2 | +| Docker image | `ghcr.io/rcore-os/tgoskits-container:latest`, image id `sha256:b7c4600e825dcb474d1f6a6bc51b8e6616ada23a24d048fc45522a58f76eb162` | +| Guest arch | `riscv64` | +| QEMU | `qemu-system-riscv64`, `virt` machine, 512 MiB, virtio-blk-pci, virtio-net-pci user net, qperf plugin, QMP unix socket | +| qperf 参数 | marker runs 使用 `--host-time --qperf-metrics --start-marker QPERF_BEGIN --stop-marker QPERF_END --workload-timeout 45` | +| qperf-metrics | blk/net marker 用例启用;兼容性旧命令未启用 | +| host perf | 未启用;报告中显示 `未启用 host perf` | + +构建检查: + +* `python3 -m py_compile tools/starry-syscall-harness/harness.py`:PASS。 +* `cargo clippy -p ax-driver --no-default-features --features 'plat-dyn,virtio-blk,virtio-net,virtio-socket,qperf-metrics' -- -D warnings`:PASS。 +* `cargo clippy -p ax-driver --no-default-features --features 'plat-dyn,virtio-blk,virtio-net,virtio-socket' -- -D warnings`:PASS。 + +## 3. 验收矩阵 + +| 模块 | 验收项 | 结果 | 证据文件 | 备注 | +| --- | --- | --- | --- | --- | +| harness/window | start/stop marker | PASS | `target/qperf-validation/blk/perf/riscv64/latest/report.json` | window start/stop/duration 已记录 | +| harness/window | boot/post-window 样本排除 | PASS | `target/qperf-validation/blk/perf/riscv64/latest/report.json` | blk boot 排除 164,post-window 排除 492 | +| harness/window | marker missing warning | PASS | `target/qperf-validation/missing-stop/perf/riscv64/latest/report.json` | 超时截断并记录 warning | +| qperf/report | required report artifacts | PASS | `target/qperf-validation/blk/perf/riscv64/latest/` | report/json/md、csv、folded、flamegraph、stdout/stderr 存在 | +| qperf/report | plugin summary / guest instr | PARTIAL | `target/qperf-validation/blk/perf/riscv64/latest/report.json` | blk 缺少 `qperf/qperf.summary.txt`,guest instr/blocks per MB 为 N/A | +| qperf/report | hotspot_categories.csv | PASS | `target/qperf-validation/blk/perf/riscv64/latest/hotspot_categories.csv` | 分类非空,包含 memcpy、virtqueue、block path 等 | +| qperf/report | dd parser | PASS | `target/qperf-validation/blk/perf/riscv64/latest/report.json` | 解析 53,601,104 bytes、5.794463s | +| qperf/report | wget parser | PASS | `target/qperf-validation/net-container/perf/riscv64/latest/report.json` | container 内 HTTP server 用例解析成功 | +| qperf/report | 用户给定 net 命令 | FAIL | `target/qperf-validation/net/perf/riscv64/latest/profile.stdout` | Docker/WSL 拓扑下 `10.0.2.2:8000` connection refused | +| virtio counters | feature 默认关闭 | PASS | `drivers/ax-driver/Cargo.toml`,clippy 输出 | 默认 feature 未强制开启 instrumentation | +| virtio counters | blk counters | PASS | `target/qperf-validation/blk/perf/riscv64/latest/report.json` | blk read bytes/request、virtqueue、notify/kick 计数进入 report | +| virtio counters | net counters | PASS | `target/qperf-validation/net-container/perf/riscv64/latest/report.json` | RX/TX bytes、copy bytes、inflight 操作进入 report | +| virtio counters | reset counters | PARTIAL | marker workload shell 命令与 `/proc/qperf_metrics` 代码 | 已执行 `echo reset`,但未做单独 before/after 定量隔离 | +| compare | self compare | PASS | `target/qperf-validation/blk/compare-self/perf-compare/blk-self-smoke/compare.md` | 主要指标 delta 为 0,结论“基本无变化” | +| compare | cross compare | PASS | `target/qperf-validation/blk/compare-cross/perf-compare/blk-vs-net-cross/compare.md` | 不 crash,缺失字段显示 N/A;跨 workload 结论不应用作优化判断 | +| compatibility | old command | PASS | `target/qperf-validation/compat-old/perf/riscv64/latest/report.json` | 未传 marker/qperf-metrics 时仍可运行 | +| vsock | vhost-vsock 环境 | BLOCKED | `/dev/vhost-vsock` 检查 | 当前 host 无该设备,未做定量结论 | + +本轮发现并做了一个最小修复:`report.json` 的 artifacts 列表原先缺少 `profile.stdout`、`profile.stderr`、raw sample、summary、QEMU config 等已生成文件。已在 `tools/starry-syscall-harness/harness.py` 中补充,并通过 py_compile 与旧命令兼容性 smoke test。 + +## 4. blk 验证结果 + +命令: + +```bash +python3 tools/starry-syscall-harness/harness.py perf-profile \ + --arch riscv64 \ + --host-time \ + --qperf-metrics \ + --start-marker QPERF_BEGIN \ + --stop-marker QPERF_END \ + --workload-timeout 45 \ + --shell-init-cmd 'echo reset > /proc/qperf_metrics; echo QPERF_BEGIN:blk-read; dd if=/usr/bin/lto-dump of=/dev/null bs=64k; cat /proc/qperf_metrics; echo QPERF_END:blk-read' \ + --output-dir target/qperf-validation/blk +``` + +证据:`target/qperf-validation/blk/perf/riscv64/latest/report.json` + +| 指标 | 值 | +| --- | --- | +| dd bytes | `53601104` | +| dd elapsed | `5.794463` s | +| dd throughput | `9250400.597950146` B/s,约 `8.8 MB/s` | +| marker window duration | `5.951667225` s | +| boot samples excluded | `164` | +| post-window samples excluded | `492` | +| total workload samples | `590` | +| samples per MB | `11.007236` | +| instructions per MB | N/A | +| blocks per MB | N/A | +| host elapsed per MB | `0.235666` s/MB | +| host elapsed/user/sys | `12.631965` / `14.222615` / `0.750295` s | + +Top hotspot categories: + +| category | samples | percent | +| --- | ---: | ---: | +| `memcpy` | 173 | 29.3220% | +| `virtio_notify_kick` | 154 | 26.1017% | +| `virtqueue_add_notify_wait_pop` | 151 | 25.5932% | +| `block_io_path` | 108 | 18.3051% | +| `allocator` | 79 | 13.3898% | +| `scheduler_wait_preempt` | 10 | 1.6949% | + +Virtio/block counters: + +| counter | value | +| --- | ---: | +| `virtqueue_add_notify_wait_pop_count` | 13,780 | +| `virtqueue_add_count` | 13,847 | +| `virtio_notify_kick_count` | 13,847 | +| `virtqueue_pop_complete_count` | 13,783 | +| `virtqueue_depth_max` | 63 | +| `virtio_blk_read_requests` | 13,478 | +| `virtio_blk_read_bytes` | 55,195,136 | +| `virtio_blk_write_requests` | 302 | +| `virtio_blk_write_bytes` | 1,236,992 | + +判断:blk 已能支撑后续“同步 `add_notify_wait_pop` 是否下降、queue depth 是否被利用、blk read bytes/request 是否匹配 workload”的 A/B 验证。但当前 blk 报告缺少 `qperf/qperf.summary.txt`,导致 guest instructions/blocks per MB 为 N/A;这会削弱严肃的指令级归一化判断,需要修复 plugin summary 落盘或 QEMU 退出流程。 + +## 5. net 验证结果 + +用户给定命令在当前 Docker/WSL 环境下失败:host HTTP server 启动在 WSL host,guest 访问 Docker 内 QEMU slirp 的 `10.0.2.2:8000`,结果为 connection refused。失败证据:`target/qperf-validation/net/perf/riscv64/latest/profile.stdout`。 + +为验证工具本身,补跑了 container 内 HTTP server 版本,使 guest 的 `10.0.2.2:8000` 指向同一个 Docker 网络命名空间内的服务。证据:`target/qperf-validation/net-container/perf/riscv64/latest/report.json`。 + +| 指标 | 值 | +| --- | --- | +| wget bytes | `63543705` | +| wget elapsed | `7.299213151` s,来源为 marker window | +| wget throughput | `8705555.473646423` B/s | +| marker window duration | `7.299213151` s | +| boot samples excluded | `155` | +| post-window samples excluded | `0` | +| total workload samples | `722` | +| samples per MB | `11.362258` | +| instructions per MB | `18821395.746439` | +| blocks per MB | `2875126.497581` | +| host elapsed per MB | `0.141124` s/MB | +| host elapsed/user/sys | `8.967565` / `9.559295` / `0.818735` s | + +Top hotspot categories: + +| category | samples | percent | +| --- | ---: | ---: | +| `memcpy` | 220 | 30.4709% | +| `net_rx_tx_path` | 158 | 21.8837% | +| `allocator` | 114 | 15.7895% | +| `memmove` | 81 | 11.2188% | +| `scheduler_wait_preempt` | 21 | 2.9086% | +| `block_io_path` | 2 | 0.2770% | + +Virtio/net counters: + +| counter | value | +| --- | ---: | +| `virtio_net_rx_packets` | 44,141 | +| `virtio_net_rx_bytes` | 65,937,102 | +| `virtio_net_rx_copy_within_count` | 44,141 | +| `virtio_net_rx_copy_within_bytes` | 65,937,102 | +| `virtio_net_tx_packets` | 2,478 | +| `virtio_net_tx_bytes` | 149,322 | +| `virtio_net_tx_staging_copy_count` | 2,478 | +| `virtio_net_tx_staging_copy_bytes` | 149,322 | +| `virtio_net_inflight_insert_count` | 46,682 | +| `virtio_net_inflight_remove_count` | 46,618 | +| `virtio_net_inflight_get_count` | 46,618 | +| `virtqueue_depth_max` | 63 | + +判断:net 工具链已经能支撑 RX 去 `copy_within()`、TX staging copy 优化、inflight map 替换的 A/B 验证。需要注意,当前用户文档中的 host server 启动方式在 Docker/WSL 下不可复现,应改为 container 内 server、host 网络模式,或显式说明网络拓扑。 + +## 6. compare 验证结果 + +Self compare 命令: + +```bash +python3 tools/starry-syscall-harness/harness.py perf-compare \ + --baseline target/qperf-validation/blk/perf/riscv64/latest/report.json \ + --candidate target/qperf-validation/blk/perf/riscv64/latest/report.json \ + --name blk-self-smoke \ + --output-dir target/qperf-validation/blk/compare-self +``` + +输出: + +* `target/qperf-validation/blk/compare-self/perf-compare/blk-self-smoke/compare.json` +* `target/qperf-validation/blk/compare-self/perf-compare/blk-self-smoke/compare.md` +* `target/qperf-validation/blk/compare-self/perf-compare/blk-self-smoke/compare.csv` + +Self compare 结果为“基本无变化”,可比字段 delta 为 0。由于 blk 报告本身缺 guest instructions/blocks,相关字段显示 N/A。 + +Cross compare 命令: + +```bash +python3 tools/starry-syscall-harness/harness.py perf-compare \ + --baseline target/qperf-validation/blk/perf/riscv64/latest/report.json \ + --candidate target/qperf-validation/net-container/perf/riscv64/latest/report.json \ + --name blk-vs-net-cross \ + --output-dir target/qperf-validation/blk/compare-cross +``` + +输出: + +* `target/qperf-validation/blk/compare-cross/perf-compare/blk-vs-net-cross/compare.json` +* `target/qperf-validation/blk/compare-cross/perf-compare/blk-vs-net-cross/compare.md` +* `target/qperf-validation/blk/compare-cross/perf-compare/blk-vs-net-cross/compare.csv` + +Cross compare 不 crash,Markdown 中缺失字段显示 N/A,说明 compare 对 schema 缺口有容错。但跨 workload 的自动结论显示“退化”,这不应解释为真实优化回归;compare 目前不校验 baseline/candidate 是否同一 workload、同一输入大小。 + +初次将 compare 输出写到 `target/qperf-validation/compare-self` 时失败,原因是该目录由 Docker/root 创建,host 用户无写权限。改写到 `target/qperf-validation/blk/compare-self` 后通过。后续应避免 Docker 创建 root-owned 顶层验证目录,或在 harness 中修正 uid/gid。 + +## 7. vsock 状态 + +当前 host 缺少 `/dev/vhost-vsock`: + +```text +ls: cannot access '/dev/vhost-vsock': No such file or directory +``` + +因此本轮未做 virtio-vsock 定量结论,也未伪造 vsock 指标。具备 vhost-vsock 的 Linux host 上应补测: + +```bash +python3 tools/starry-syscall-harness/harness.py perf-profile \ + --arch riscv64 \ + --host-time \ + --qperf-metrics \ + --start-marker QPERF_BEGIN \ + --stop-marker QPERF_END \ + --workload-timeout 45 \ + --shell-init-cmd 'echo reset > /proc/qperf_metrics; echo QPERF_BEGIN:vsock; ; cat /proc/qperf_metrics; echo QPERF_END:vsock' \ + --output-dir target/qperf-validation/vsock +``` + +补测时应在报告中记录 `/dev/vhost-vsock` 权限、QEMU vsock 参数、CID/port、workload bytes 与 elapsed。 + +## 8. 未达标项与风险 + +* runtime pause/resume 仍未验证为真实启停采样;当前能力主要依赖 timestamp 后处理过滤和 marker window 标注。结论应表述为“boot samples excluded by postprocess”,不能声称采样器运行时暂停。 +* blk 用例缺失 `qperf/qperf.summary.txt`,导致 guest instructions per MB 与 guest blocks per MB 为 N/A。这是归一化指标的关键缺口。 +* queue depth、notify/kick、pop/complete 计数是 driver-visible 近似统计,不是 virtqueue ring-level 精确硬件事件计数;当前使用 relaxed atomics,snapshot 不是强一致事务。 +* host perf 未启用,PMU 级 cycles/cache-miss 等 host 指标不存在。报告有明确 `未启用 host perf` 说明。 +* 用户给定 net 命令在当前 Docker/WSL 网络拓扑下失败。工具可用,但示例命令需要改成 container 内 HTTP server 或明确网络前提。 +* compare 对跨 workload 输入没有 guard,可能给出形式上的“退化/改善”结论;实际 A/B 应只比较同 workload、同输入、同 qperf 参数。 +* compare CSV 中缺失字段为空值,Markdown 显示 N/A;若后续自动消费 CSV,建议也输出显式 N/A。 +* `/proc/qperf_metrics reset` 已在 workload 中执行,但本轮未做独立 before/after 断言;建议补一个微型读写 reset 单测或 harness smoke。 +* 顶层 `target/qperf-validation` 可能被 Docker 创建为 root-owned,导致 host-side compare 输出 PermissionError。 + +## 9. 总体结论 + +结论:**PARTIAL**。 + +本轮改造达到 qperf 工具 MVP 的主要方向:marker window 可用,boot/post-window 样本能从 workload 报告中排除;工程分类热点、dd/wget/QPERF_METRIC parser、virtio-blk/net counters、A/B compare 都有可复现实验文件支撑。blk 和 net 的关键候选瓶颈已经能在 report 中直接看到。 + +但仍存在关键缺口:blk 运行缺 guest instruction/block summary,用户给定 net 命令在当前 Docker/WSL 拓扑下不可复现,采样窗口仍是后处理过滤而不是运行时 pause/resume,virtio counters 是 driver-visible 近似值。它可以支撑下一轮小规模 virtio 优化 A/B 验证,但报告必须保留这些限制,不能把当前数据解释为完整 PMU/virtqueue ring 级精确观测。 + +## 10. 下一步建议 + +1. net RX 去 `copy_within()` 的 A/B 优化验证:使用 `target/qperf-validation/net-container` 同样的 container 内 HTTP server 拓扑,比较 `virtio_net_rx_copy_within_bytes`、`memmove` category、throughput、samples per MB。 +2. net inflight `BTreeMap` 替换固定数组/slab 的 A/B 优化验证:比较 `virtio_net_inflight_insert/remove/get_count`、`net_inflight_btree` category、allocator category、host elapsed per MB。 +3. blk `read_blocks_nb()` / `complete_read_blocks()` 最小 pending-read 原型验证:比较 `virtqueue_add_notify_wait_pop_count`、`virtio_notify_kick_count`、`virtqueue_depth_max`、blk throughput、samples per MB。 +4. 修复 blk `qperf.summary.txt` 缺失问题后重跑 blk;要求 `guest_instructions_per_MB` 和 `guest_blocks_per_MB` 不再是 N/A。 +5. 在具备 `/dev/vhost-vsock` 的 Linux host 上补测 vsock,并把环境阻塞、CID/port、bytes、elapsed、vsock counters 明确写入 report。 diff --git a/docs/qperf-virtio-blk-deepstack-optimization-report.md b/docs/qperf-virtio-blk-deepstack-optimization-report.md new file mode 100644 index 0000000000..701a4fac68 --- /dev/null +++ b/docs/qperf-virtio-blk-deepstack-optimization-report.md @@ -0,0 +1,335 @@ +# qperf virtio-blk 深栈采样与优化报告 + +## 1. 目标 + +本轮目标是使用已经支持 RISC-V frame-pointer callchain 的新版 qperf,重新采样 virtio-blk 路径,生成可以纵向展开的深栈火焰图,并基于 qperf 的实际证据实现一个可验证的性能优化。 + +本报告只使用本轮真实命令产物中的数字,不使用示例值。 + +## 2. 环境与命令 + +| 项目 | 值 | +| --- | --- | +| 运行环境 | 宿主 WSL2,非 Docker | +| QEMU | `qemu-system-riscv64` 10.2.1 | +| guest arch | `riscv64` | +| qperf callchain | `fp`,通过 `cargo starry perf --full-stack` 启用 | +| workload | `dd if=/usr/bin/lto-dump of=/dev/null bs=64k` | +| marker | `QPERF_BEGIN` / `QPERF_END` | +| metrics | `--qperf-metrics`,读取 `/proc/qperf_metrics` | + +baseline 命令: + +```bash +cargo starry perf \ + --case blk-baseline \ + --output-dir target/qperf-virtio-blk-opt/baseline \ + --full-stack \ + --qperf-metrics \ + --host-time \ + --timeout 240 \ + --workload-timeout 160 \ + --start-marker QPERF_BEGIN \ + --stop-marker QPERF_END \ + --shell-init-cmd 'echo reset > /proc/qperf_metrics; echo QPERF_BEGIN:blk; dd if=/usr/bin/lto-dump of=/dev/null bs=64k; cat /proc/qperf_metrics; echo QPERF_END:blk' \ + --no-truncate +``` + +最终 candidate 命令: + +```bash +cargo starry perf \ + --case blk-direct-readahead \ + --output-dir target/qperf-virtio-blk-opt/candidate-readahead \ + --full-stack \ + --qperf-metrics \ + --host-time \ + --timeout 240 \ + --workload-timeout 160 \ + --start-marker QPERF_BEGIN \ + --stop-marker QPERF_END \ + --shell-init-cmd 'echo reset > /proc/qperf_metrics; echo QPERF_BEGIN:blk; dd if=/usr/bin/lto-dump of=/dev/null bs=64k; cat /proc/qperf_metrics; echo QPERF_END:blk' \ + --no-truncate +``` + +A/B compare 命令: + +```bash +python3 tools/starry-syscall-harness/harness.py perf-compare \ + --baseline target/qperf-virtio-blk-opt/baseline/perf/riscv64/latest/report.json \ + --candidate target/qperf-virtio-blk-opt/candidate-readahead/perf/riscv64/latest/report.json \ + --name blk-readahead \ + --output-dir target/qperf-virtio-blk-opt/compare-readahead +``` + +## 3. 深栈火焰图 + +baseline 深栈火焰图: + +![baseline full-stack flamegraph](flamegraphs/qperf-virtio-blk-baseline-fullstack.png) + +candidate 深栈火焰图: + +![candidate full-stack flamegraph](flamegraphs/qperf-virtio-blk-readahead-fullstack.png) + +原始 SVG 和 folded stack 位置: + +| case | flamegraph.svg | stack.folded | depth summary | +| --- | --- | --- | --- | +| baseline | `target/qperf-virtio-blk-opt/baseline/perf/riscv64/latest/qperf/flamegraph.svg` | `target/qperf-virtio-blk-opt/baseline/perf/riscv64/latest/qperf/stack.folded` | `target/qperf-virtio-blk-opt/baseline/perf/riscv64/latest/qperf/stack-depth-summary.csv` | +| candidate | `target/qperf-virtio-blk-opt/candidate-readahead/perf/riscv64/latest/qperf/flamegraph.svg` | `target/qperf-virtio-blk-opt/candidate-readahead/perf/riscv64/latest/qperf/stack.folded` | `target/qperf-virtio-blk-opt/candidate-readahead/perf/riscv64/latest/qperf/stack-depth-summary.csv` | + +深度分布: + +| depth | baseline samples | candidate samples | +| ---: | ---: | ---: | +| 1 | 1 | 10 | +| 3 | 0 | 2 | +| 4 | 4 | 1 | +| 5 | 2 | 2 | +| 6 | 21 | 41 | +| 7 | 2 | 4 | +| 8 | 19 | 7 | +| 9 | 43 | 48 | +| 10 | 59 | 66 | +| 11 | 57 | 75 | +| 12 | 94 | 108 | +| 13 | 55 | 79 | +| 14 | 62 | 9 | +| 15 | 212 | 69 | +| 16 | 11 | 5 | +| 17 | 0 | 1 | +| 20 | 0 | 1 | + +这说明本轮 flamegraph 不是 leaf-only。baseline 与 candidate 都保留了 syscall 到 fs、rsext4、ax-driver、virtio queue 的深调用链。 + +baseline 中可见的典型路径: + +```text +starry_kernel::syscall::fs::io::sys_read + -> ax_fs_ng::highlevel::file::CachedFile::read_at + -> rsext4::cache::data_block::DataBlockCache::get_or_load + -> DataBlockCache::load_block + -> Jbd2Dev::read_block + -> ax_driver::block::binding::Block::read_blocks_wait + -> rd_block::CmdQueue::read_blocks_blocking + -> ax_driver::virtio::block::BlockQueue::submit_request + -> VirtIOBlk::read_blocks + -> VirtQueue::add_notify_wait_pop +``` + +candidate 中路径变为: + +```text +starry_kernel::syscall::fs::io::sys_read + -> ax_fs_ng::highlevel::file::CachedFile::read_at + -> rsext4::cache::data_block::DataBlockCache::get_or_load + -> DataBlockCache::load_readahead + -> Jbd2Dev::read_blocks + -> ax_driver::block::binding::Block::read_block + -> rd_block::CmdQueue::read_blocks_direct + -> ax_driver::virtio::block::BlockQueue::read_blocks_direct + -> VirtIOBlk::read_blocks + -> VirtQueue::add_notify_wait_pop +``` + +## 4. qperf 识别出的瓶颈 + +baseline 结果: + +| 指标 | 值 | +| --- | ---: | +| dd bytes | 53,601,104 | +| dd elapsed | 6.367021 s | +| throughput | 8,418,553 B/s | +| marker window | 6.529766005 s | +| callchain avg symbol depth | 43.306853583 | +| raw max depth | 16 | +| samples | 642 | + +baseline counters: + +| counter | 值 | +| --- | ---: | +| virtio_blk_read_requests | 13,629 | +| virtio_blk_read_bytes | 55,813,632 | +| virtqueue_add_count | 14,417 | +| virtio_notify_kick_count | 14,417 | +| virtqueue_add_notify_wait_pop_count | 14,354 | +| virtqueue_pop_complete_count | 14,354 | + +baseline hotspot categories: + +| category | samples | percent | +| --- | ---: | ---: | +| block_io_path | 487 | 75.8567% | +| virtio_notify_kick | 211 | 32.8660% | +| virtqueue_add_notify_wait_pop | 205 | 31.9315% | +| memcpy | 181 | 28.1931% | +| lock_mutex_wait | 68 | 10.5919% | + +结论: + +* 每次 53.6 MB 顺序读触发 13,629 次 blk read request,平均每个 read request 约 4 KiB。 +* `virtqueue_depth_hist_0` 和 `virtqueue_depth_hist_1` 与 request 数量几乎同量级,说明大多数 I/O 都是同步提交、立即等待完成。 +* `VirtQueue::add_notify_wait_pop` 和 `virtio_notify_kick` 在深栈中出现在约三分之一 workload 样本里,是 blk 路径的主要工程瓶颈。 +* `memcpy` 也显著,但仅减少 copy 不足以解决主瓶颈;关键是减少同步小 I/O 次数。 + +## 5. 优化实现 + +本轮实现了两个小步,第一步作为失败尝试保留证据,第二步作为最终优化: + +### 5.1 direct read 快路径 + +修改文件: + +* `drivers/interface/rdif-block/src/lib.rs` +* `drivers/blk/rd-block/src/lib.rs` +* `drivers/ax-driver/src/block/binding.rs` +* `drivers/ax-driver/src/virtio/block.rs` +* `drivers/ax-driver/src/qperf_metrics.rs` + +内容: + +* 在 `rdif_block::IQueue` 增加默认 `read_blocks_direct()`。 +* `ax_driver::block::Block::read_block()` 优先尝试 direct path。 +* virtio-blk 对物理连续 buffer 调用 `VirtIOBlk::read_blocks()` 直接 DMA 到目标 buffer。 +* qperf metrics 新增 `virtio_blk_direct_read_requests`、`virtio_blk_direct_read_bytes`。 + +direct-only 结果: + +| 指标 | baseline | direct-only | +| --- | ---: | ---: | +| throughput | 8,418,553 B/s | 6,889,660 B/s | +| workload elapsed | 6.367021 s | 7.779933 s | +| virtqueue_add_notify_wait_pop_count | 14,354 | 14,354 | + +结论:direct-only 命中了全部 read request,但没有减少同步 virtqueue 次数,A/B compare 判定为退化。因此 direct-only 不是有效优化。 + +### 5.2 rsext4 data block readahead + +修改文件: + +* `components/rsext4/src/cache/data_block.rs` + +内容: + +* 在 `DataBlockCache::get_or_load()` miss 时,最多读取 8 个连续 filesystem block。 +* 使用已有 `Jbd2Dev::read_blocks()` 批量读入。 +* 将批量读取的数据拆成 `CachedBlock` 放入 data block cache。 +* 如果后续 block 已在 cache 中,则停止本次 readahead,避免覆盖已有缓存。 +* 仍按 LRU 容量约束驱逐,保持缓存上限。 + +这与 qperf 识别出的瓶颈直接对应:顺序读场景下,把多次 4 KiB `read_block -> add_notify_wait_pop` 合并成更少的批量 read。 + +## 6. A/B 结果 + +最终 compare 文件: + +* `target/qperf-virtio-blk-opt/compare-readahead/perf-compare/blk-readahead/compare.md` +* `target/qperf-virtio-blk-opt/compare-readahead/perf-compare/blk-readahead/compare.csv` +* `target/qperf-virtio-blk-opt/compare-readahead/perf-compare/blk-readahead/compare.json` + +compare 结论:`明显改善`。 + +| 指标 | baseline | candidate | 变化 | +| --- | ---: | ---: | ---: | +| throughput_bytes_per_second | 8,418,553 | 10,551,346 | +25.3344% | +| workload elapsed | 6.367021 s | 5.080025 s | -20.2135% | +| samples.total_samples | 642 | 528 | -17.7570% | +| virtio_blk_read_requests | 13,629 | 2,111 | -84.5110% | +| virtio_notify_kick_count | 14,417 | 2,899 | -79.8918% | +| virtqueue_add_count | 14,417 | 2,899 | -79.8918% | +| virtqueue_add_notify_wait_pop_count | 14,354 | 2,836 | -80.2424% | +| virtqueue_pop_complete_count | 14,354 | 2,836 | -80.2424% | + +hotspot category 对比: + +| category | baseline | candidate | delta | +| --- | ---: | ---: | ---: | +| virtio_notify_kick | 32.8660% | 14.2045% | -18.6615 pp | +| virtqueue_add_notify_wait_pop | 31.9315% | 13.4470% | -18.4845 pp | +| block_io_path | 75.8567% | 66.2879% | -9.5688 pp | +| memcpy | 28.1931% | 31.0606% | +2.8675 pp | +| lock_mutex_wait | 10.5919% | 10.4167% | -0.1752 pp | + +函数变化中最关键的是: + +| function | baseline | candidate | 说明 | +| --- | ---: | ---: | --- | +| `DataBlockCache::load_block` | 1.1869% | 0.0048% | 单块读基本消失 | +| `DataBlockCache::load_readahead` | 0.0000% | 1.1720% | 新批量读路径出现 | +| `Block::read_blocks_wait` | 0.8884% | 0.0000% | 旧同步 wrapper 热点消失 | +| `rd_block::CmdQueue::read_blocks_blocking` | 0.8884% | 0.0000% | 旧阻塞 future 路径消失 | +| `BlockQueue::submit_request` | 0.7409% | 0.0048% | 旧 request 提交路径基本消失 | +| `BlockQueue::read_blocks_direct` | 0.0000% | 0.3349% | direct 批量读路径出现 | +| `VirtQueue::add_notify_wait_pop` | 0.7373% | 0.3396% | leaf 函数占比下降 | + +## 7. 重要说明 + +candidate 的 `report.json.result` 是 `incomplete`,原因是 QEMU 在 stop marker 后通过 QMP 请求退出,但最终被 SIGKILL 清理。该问题会影响 host elapsed 和 guest instruction/block summary: + +* candidate `host.elapsed_seconds` 被拉长到 27.689356 s,不适合用于性能结论。 +* candidate `guest.executed_instructions` 与 `guest.executed_blocks` 为 N/A。 +* marker window、dd 输出、qperf raw sample、folded stack、hotspot_categories 和 QPERF_METRIC counters 均已生成。 + +因此本轮结论基于: + +* guest stdout 中的 `dd` bytes / elapsed / throughput。 +* marker window 内 qperf samples。 +* `/proc/qperf_metrics` 导出的 virtio counters。 +* `hotspot_categories.csv` 和 deep stack folded path。 + +## 8. 本轮验证命令 + +已执行: + +```bash +cargo fmt +cargo clippy -p rdif-block -- -D warnings +cargo clippy -p rd-block -- -D warnings +cargo clippy -p rsext4 -- -D warnings +cargo clippy -p ax-driver --no-default-features --features 'plat-dyn,virtio-blk,virtio-net,virtio-socket,qperf-metrics' -- -D warnings +``` + +SVG 转 PNG: + +```bash +convert -background white \ + target/qperf-virtio-blk-opt/baseline/perf/riscv64/latest/qperf/flamegraph.svg \ + docs/flamegraphs/qperf-virtio-blk-baseline-fullstack.png + +convert -background white \ + target/qperf-virtio-blk-opt/candidate-readahead/perf/riscv64/latest/qperf/flamegraph.svg \ + docs/flamegraphs/qperf-virtio-blk-readahead-fullstack.png +``` + +## 9. 结论 + +本轮 qperf 深栈采样确认 virtio-blk 的主要瓶颈是同步小块 I/O: + +```text +sys_read + -> rsext4 DataBlockCache::load_block + -> ax_driver Block::read_blocks_wait + -> rd_block::read_blocks_blocking + -> virtio_blk submit_request + -> VirtQueue::add_notify_wait_pop +``` + +最终优化通过 rsext4 data block readahead 与 virtio-blk direct read,把顺序读中的单块 miss 合并为批量读: + +* workload 吞吐提升 25.3344%。 +* blk read request 数下降 84.5110%。 +* notify/kick 数下降 79.8918%。 +* `add_notify_wait_pop` 计数下降 80.2424%。 +* `virtqueue_add_notify_wait_pop` category 从 31.9315% 降到 13.4470%。 + +这说明新版 qperf 已经可以支撑“发现瓶颈 -> 实现优化 -> A/B 验证”的闭环。 + +## 10. 后续工作 + +* 修复 QMP stop 后偶发 SIGKILL,保证 candidate `result=ok` 并保留完整 plugin summary。 +* 将 readahead 策略做成可调参数,例如根据顺序命中率动态选择 1/4/8/16 blocks。 +* 进一步减少 `DataBlockCache::load_readahead` 内部的 `Vec` 分块复制。 +* 继续推进真正异步 pending read,让 virtqueue depth 不只通过减少请求数改善,而能真正并发利用 queue depth。 diff --git a/docs/qperf-virtio-drivers-performance-report.md b/docs/qperf-virtio-drivers-performance-report.md new file mode 100644 index 0000000000..d7a202f414 --- /dev/null +++ b/docs/qperf-virtio-drivers-performance-report.md @@ -0,0 +1,352 @@ +# qperf virtio-drivers 性能测试与瓶颈定位报告 + +## 背景与目标 + +本次使用本仓库新的 `tools/starry-syscall-harness` 和 `tools/qperf`,对 StarryOS 在 QEMU riscv64 环境中集成的 `virtio-drivers` 路径做性能采样和瓶颈定位。目标不是做理论方案,而是保留可复现实验命令、原始输出、qperf 火焰图和由数据支持的优化方向。 + +需要特别说明测试对象: + +- 本仓库当前锁定依赖为 crates.io `virtio-drivers 0.13.0`,见根 `Cargo.toml` 的 `virtio-drivers = { version = "0.13.0", default-features = false }` 和 `Cargo.lock` 的 registry source。 +- GitHub `rcore-os/virtio-drivers` 上游 `master` 在测试时为 `d6818a8731b9422dbd06032f2fb232b6ea477814`。本次没有把依赖临时切换到该 HEAD,因为上游 master 与 crates.io 0.13.0 已存在源码差异,即使版本号相同,直接 patch 依赖会改变本仓库可复现基线。 +- 因此本报告的性能数据代表“本仓库当前集成的 `virtio-drivers 0.13.0`”。上游 HEAD 作为源码对照和后续优化方向参考。 + +## 实验环境 + +| 项目 | 值 | +| --- | --- | +| 日期 | 2026-05-29 Asia/Shanghai | +| 本仓库 commit | `6e748d6b7` | +| 上游 virtio-drivers | `rcore-os/virtio-drivers` `master` `d6818a8731b9422dbd06032f2fb232b6ea477814` | +| Host kernel | `Linux LAPTOP-SAOPKIGH 5.15.167.4-microsoft-standard-WSL2 #1 SMP Tue Nov 5 00:21:55 UTC 2024 x86_64` | +| CPU | Intel Core i7-14650HX, 24 logical CPUs | +| Hypervisor | Microsoft WSL2, VT-x exposed | +| Docker image | `ghcr.io/rcore-os/tgoskits-container:latest` `sha256:b7c4600e825dcb474d1f6a6bc51b8e6616ada23a24d048fc45522a58f76eb162`, created `2026-05-08T07:18:59.511877974Z` | +| Guest arch | `riscv64` | +| QEMU devices | `virtio-blk-pci` rootfs, `virtio-net-pci` user net | +| qperf mode | QEMU TCG plugin, `mode=tb`, `freq=99`, `max_depth=64`, `queue_size=4096`, `format=all` | + +qperf 是 QEMU TCG plugin。这里的 `executed_instructions`、`executed_blocks` 是 QEMU guest 执行回调统计,不是 guest PMU 的硬件 cycles/cache-miss。`--host-time` 记录 host 侧 QEMU wrapper 的 wall/user/sys CPU 时间。本轮未启用 `--host-perf`,因此没有 host `perf stat` 计数。 + +## qperf/harness 使用方法 + +基础命令模式如下: + +```bash +python3 tools/starry-syscall-harness/harness.py perf-profile \ + --repo-root /work \ + --arch riscv64 \ + --timeout 45 \ + --format all \ + --freq 99 \ + --max-depth 64 \ + --mode tb \ + --top 60 \ + --min-percent 0.5 \ + --host-time \ + --shell-init-cmd '' \ + --output-dir target/qperf-virtio-drivers/ \ + --no-docker +``` + +外层用 Docker 固定工具链: + +```bash +docker run --rm -v "$PWD":/work -w /work \ + -e STARRY_SYSCALL_HARNESS_IN_DOCKER=1 \ + ghcr.io/rcore-os/tgoskits-container:latest bash -lc '' +``` + +每个成功 profile 生成: + +- `report.json`: harness 汇总结果。 +- `report.md`: harness 自动报告。 +- `hotspots.csv`: top symbol 表。 +- `qperf/stack.folded`: folded stack 原始输入。 +- `qperf/flamegraph.svg`: 火焰图。 +- `qperf/summary.txt`: qperf 参数和采样统计。 +- `profile.stdout` / `profile.stderr`: guest 输出和 QEMU/qperf 命令输出。 + +## 实验设计 + +| 用例 | 目的 | guest workload | +| --- | --- | --- | +| `boot` | 设备枚举、PCI transport、virtio-blk/net init 基线 | 无额外 workload,profile 到 timeout | +| `blk-read` | 文件读触发 virtio-blk read path | `echo QPERF_BLK_READ; time dd if=/usr/bin/lto-dump of=/dev/null bs=64k; sleep 1` | +| `net-wget` | HTTP 下载触发 virtio-net RX path | `echo QPERF_NET_WGET; time wget -O /dev/null http://10.0.2.2:8000/tmp/axbuild/rootfs/rootfs-riscv64-alpine.img.tar.xz; sleep 1` | +| `blk-read-focused` | 缩短采样窗口,减少 workload 结束后的 idle 稀释 | `echo QPERF_BLK_READ_FOCUSED; time dd ...; sync; poweroff -f` | +| `net-wget-focused` | 缩短采样窗口,观察 net 数据面 copy/memmove | `echo QPERF_NET_WGET_FOCUSED; time wget ...; sync; poweroff -f` | +| `vsock-probe` | 尝试启用 `vhost-vsock-pci` | `--qemu-arg=-device --qemu-arg=vhost-vsock-pci,guest-cid=3` | + +`poweroff -f` 在当前 StarryOS guest 中最终触发 `Unimplemented syscall: reboot`,因此 QEMU 仍由 timeout 停止。focused 用例仍有价值,因为 timeout 从 45s 缩短为 25s,数据面热点被稀释得更少。 + +## 结果文件 + +| 用例 | report | folded stack | flamegraph | +| --- | --- | --- | --- | +| boot | `target/qperf-virtio-drivers/boot/perf/riscv64/latest/report.json` | `target/qperf-virtio-drivers/boot/perf/riscv64/latest/qperf/stack.folded` | `target/qperf-virtio-drivers/boot/perf/riscv64/latest/qperf/flamegraph.svg` | +| blk-read | `target/qperf-virtio-drivers/blk-read/perf/riscv64/latest/report.json` | `target/qperf-virtio-drivers/blk-read/perf/riscv64/latest/qperf/stack.folded` | `target/qperf-virtio-drivers/blk-read/perf/riscv64/latest/qperf/flamegraph.svg` | +| net-wget | `target/qperf-virtio-drivers/net-wget/perf/riscv64/latest/report.json` | `target/qperf-virtio-drivers/net-wget/perf/riscv64/latest/qperf/stack.folded` | `target/qperf-virtio-drivers/net-wget/perf/riscv64/latest/qperf/flamegraph.svg` | +| blk-read-focused | `target/qperf-virtio-drivers/blk-read-focused/perf/riscv64/latest/report.json` | `target/qperf-virtio-drivers/blk-read-focused/perf/riscv64/latest/qperf/stack.folded` | `target/qperf-virtio-drivers/blk-read-focused/perf/riscv64/latest/qperf/flamegraph.svg` | +| net-wget-focused | `target/qperf-virtio-drivers/net-wget-focused/perf/riscv64/latest/report.json` | `target/qperf-virtio-drivers/net-wget-focused/perf/riscv64/latest/qperf/stack.folded` | `target/qperf-virtio-drivers/net-wget-focused/perf/riscv64/latest/qperf/flamegraph.svg` | +| vsock-probe | `target/qperf-virtio-drivers/vsock-probe/perf/riscv64/latest/report.json` | 未生成 | 未生成 | + +火焰图文件大小:boot 56 KiB,blk-read 50 KiB,net-wget 49 KiB,blk-read-focused 47 KiB,net-wget-focused 44 KiB。 + +## Baseline 数据 + +### qperf 运行统计 + +| 用例 | result | samples | dropped | failures | guest executed instructions | guest executed blocks | host elapsed | host user | host sys | +| --- | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: | +| boot | ok | 1976 | 0 | 0 | 1,825,991,247 | 392,723,472 | 20.054893s | 22.224841s | 0.156351s | +| blk-read | ok | 4454 | 0 | 0 | 4,185,872,192 | 905,971,235 | 45.054700s | 50.170774s | 1.088724s | +| net-wget | ok | 4454 | 0 | 0 | 4,408,078,862 | 871,425,485 | 45.054578s | 49.912610s | 1.003815s | +| blk-read-focused | ok | 2474 | 0 | 0 | 2,327,694,436 | 508,696,929 | 25.055819s | 27.984471s | 0.858122s | +| net-wget-focused | ok | 2474 | 0 | 0 | 2,657,789,635 | 496,566,438 | 25.054676s | 27.591356s | 0.812188s | +| vsock-probe | incomplete | 0 | 0 | 0 | 0 | 0 | 0.060224s | 0.000608s | 0.009832s | + +### workload 输出 + +| 用例 | guest 原始输出摘要 | 说明 | +| --- | --- | --- | +| blk-read | `53601104 bytes (51.1MB) copied, 5.897731 seconds, 8.7MB/s`; `real 0m 5.95s`; `sys 0m 0.1717986s` | 来自 `profile.stdout` | +| blk-read-focused | `53601104 bytes (51.1MB) copied, 6.018606 seconds, 8.5MB/s`; `real 0m 6.08s`; `sys 0m 0.1717986s` | `poweroff -f` 后出现 `Function not implemented` | +| net-wget | `'/dev/null' saved`; `real 0m 7.66s`; `sys 0m 0.1717986s` | 下载对象为 `rootfs-riscv64-alpine.img.tar.xz`,host 文件大小 63,552,204 bytes,折算约 8.30 MB/s | +| net-wget-focused | `'/dev/null' saved`; `real 0m 7.51s`; `sys 0m 0.1717986s` | 同一文件,折算约 8.46 MB/s | +| vsock-probe | `Could not open '/dev/vhost-vsock': No such file or directory` | host/WSL2 环境没有 vhost-vsock 设备 | + +## 火焰图与热点 + +### boot + +Top symbols: + +| percent | samples | symbol | +| ---: | ---: | --- | +| 4.200% | 83 | `ax_driver::pci::fdt::probe_generic_ecam+0x710` | +| 3.492% | 69 | `ax_task::wait_queue::WaitQueue::wait_until...RawMutex...+0x466` | +| 2.227% | 44 | `ax_task::wait_queue::WaitQueue::wait_until...RawMutex...+0x45a` | +| 1.771% | 35 | `_head+0x4f8` | +| 1.569% | 31 | `TaskInner::current_check_preempt_pending+0x38` | + +boot 火焰图显示 profile 从内核启动开始采样,PCI ECAM probe、任务调度/等待和 allocator 是主要背景成本。后续 blk/net 用例中这些启动成本仍然存在,因此报告分析以 focused 用例的相对变化为主。 + +### virtio-blk + +`blk-read-focused` top symbols: + +| percent | samples | symbol | +| ---: | ---: | --- | +| 6.669% | 165 | `compiler_builtins::mem::memcpy+0x4a` | +| 3.072% | 76 | `virtio_drivers::queue::VirtQueue::add_notify_wait_pop+0xcc` | +| 2.910% | 72 | `ax_driver::pci::fdt::probe_generic_ecam+0x710` | +| 2.789% | 69 | `ax_task::wait_queue::WaitQueue::wait_until...RawMutex...+0x45a` | +| 2.749% | 68 | `ax_task::wait_queue::WaitQueue::wait_until...RawMutex...+0x466` | +| 2.627% | 65 | `virtio_drivers::queue::VirtQueue::add_notify_wait_pop+0xc8` | + +按 folded stack 子串聚合: + +| category | blk-read | blk-read-focused | +| --- | ---: | ---: | +| scheduler yield/preempt | 16.861% | 12.490% | +| PCI probe/transport | 9.026% | 11.318% | +| allocator | 7.544% | 8.407% | +| task wait/mutex | 8.577% | 7.922% | +| memcpy | 4.064% | 7.559% | +| virtqueue `add_notify_wait_pop` | 3.323% | 6.427% | +| net inflight BTree | 3.817% | 3.355% | + +结论: + +- `VirtQueue::add_notify_wait_pop` 在 blk 读路径中是明确热点。focused 窗口中两个偏移合计已经接近 5.7%,按子串聚合为 6.427%。 +- 当前 `virtio-drivers` blk API 的同步路径为 `VirtIOBlk::read_blocks()` -> `request_read()` -> `VirtQueue::add_notify_wait_pop()`。该函数每个请求执行 add、notify、busy-spin 等待、pop,天然限制队列深度。 +- 本仓库 glue 层 `drivers/ax-driver/src/virtio/block.rs` 的 `BlockQueue::submit_request()` 直接调用同步 `read_blocks()` / `write_blocks()`,`poll_request()` 直接返回 Ok,没有使用 `virtio-drivers` 已提供的 `read_blocks_nb()` / `complete_read_blocks()`。 +- qperf 中的 `memcpy` 占比更高,但它包含文件系统、页缓存、用户缓冲和块层复制,不应全部归因于 `virtio-drivers`。它仍然说明 blk workload 的端到端开销被 copy 明显影响。 + +相关源码: + +- `virtio-drivers` `queue.rs`: `VirtQueue::add()` 构造 descriptor 并写 avail ring,`fence(Ordering::SeqCst)` 后更新 idx;`add_notify_wait_pop()` 负责同步 notify 和 busy-spin 等待。 +- `virtio-drivers` `device/blk.rs`: `QUEUE_SIZE = 16`,同步 `read_blocks()` 进入 `request_read()`。 +- `drivers/ax-driver/src/virtio/block.rs`: glue 层同步提交,未暴露异步队列深度。 + +### virtio-net + +`net-wget-focused` top symbols: + +| percent | samples | symbol | +| ---: | ---: | --- | +| 5.416% | 134 | `compiler_builtins::mem::memcpy+0x4a` | +| 3.436% | 85 | `ax_task::wait_queue::WaitQueue::wait_until...RawMutex...+0x45a` | +| 3.355% | 83 | `ax_driver::pci::fdt::probe_generic_ecam+0x710` | +| 2.870% | 71 | `compiler_builtins::mem::memcpy+0x10c` | +| 2.749% | 68 | `ax_task::wait_queue::WaitQueue::wait_until...RawMutex...+0x466` | +| 1.738% | 43 | `compiler_builtins::mem::memmove+0x2a4` | + +按 folded stack 子串聚合: + +| category | net-wget | net-wget-focused | +| --- | ---: | ---: | +| scheduler yield/preempt | 15.402% | 12.975% | +| memcpy | 5.770% | 9.984% | +| allocator | 7.432% | 8.892% | +| task wait/mutex | 8.442% | 8.488% | +| PCI probe/transport | 7.454% | 7.639% | +| net inflight BTree | 4.176% | 3.395% | +| memmove | 1.796% | 3.072% | +| net RX submit/complete | 1.325% | 2.264% | +| virtqueue add/notify/pop | 0.403% | 0.526% | + +结论: + +- net 下载路径的主要数据面热点是 copy/move,而不是 `VirtQueue::add_notify_wait_pop`。focused 窗口中 `memcpy` 聚合 9.984%,`memmove` 聚合 3.072%。 +- 本仓库 glue 层 RX 回收在 `NetInner::reclaim_rx()` 中调用 `VirtIONetRaw::receive_complete()` 后执行 `buffer.copy_within(header_len..header_len + packet_len, 0)`,这会把 virtio-net header 后面的包体整体前移。 +- TX 路径 `submit_tx()` 为每包分配 staging `Vec`,填 virtio header 后 `extend_from_slice(packet)`,这也是一条固定 copy 路径。 +- token/inflight 管理使用 `BTreeMap`。qperf 聚合中 `RxInflight`/`TxInflight` BTree 相关符号在 net focused 中为 3.395%,说明在 QUEUE_SIZE 仅 64 的场景下,通用 BTree 结构可能不是最合适的数据结构。 +- `VirtIONetRaw::receive_begin()` / `transmit_begin()` 每次 packet 提交都会 `add` 并判断 `should_notify()`。本次 profile 中 virtqueue add/notify/pop 占比低于 copy 和 BTree,但仍可作为后续高 PPS workload 的观察点。 + +相关源码: + +- `virtio-drivers` `device/net/dev_raw.rs`: `transmit_begin()`、`receive_begin()` 调用 virtqueue add 并按 `should_notify()` notify。 +- `drivers/ax-driver/src/virtio/net.rs`: `submit_tx()` staging Vec copy,`reclaim_rx()` `copy_within()`,`BTreeMap`。 + +### virtio-vsock + +本轮未获得 vsock 数据面 profile。原因是 QEMU 启动 `vhost-vsock-pci` 时失败: + +```text +qemu-system-riscv64: -device vhost-vsock-pci,guest-cid=3: Could not open '/dev/vhost-vsock': No such file or directory +Error: qperf QEMU run failed before producing samples: exit status: 1 +``` + +因此本报告不对 vsock 性能下定量结论。只能基于源码记录后续需要验证的风险点: + +- `virtio-drivers` vsock `QUEUE_SIZE = 8`。 +- `send_packet_to_tx_queue()` 对每个包调用 `tx.add_notify_wait_pop()`,数据面可能和 blk 同样受同步 notify/wait 限制。 +- 需要在具备 `/dev/vhost-vsock` 的 host 上重新运行 vsock connect/send/recv workload,才能确认。 + +## 公共瓶颈分析 + +### 1. 采样窗口从 boot 开始,启动成本会污染数据面结论 + +所有 profile 都从 QEMU 启动开始采样。`probe_generic_ecam` 在 boot、blk、net 中都稳定出现,focused 用例仍有 7% 到 11% 的 PCI probe/transport 聚合占比。这是设备枚举和初始化成本,不等价于运行期吞吐瓶颈。 + +下一步最好扩展 harness/qperf 支持 guest shell prompt 后再开始采样,或者支持 workload 结束后由 harness 主动停止 QEMU。当前 guest `poweroff -f` 失败,不能作为结束信号。 + +### 2. blk 的同步队列模型值得优先优化 + +证据: + +- `blk-read-focused` 中 `VirtQueue::add_notify_wait_pop` 聚合 6.427%。 +- 同步 blk glue 层没有利用 non-blocking API,导致请求不能自然形成队列深度。 +- `VirtIOBlk` 内部队列大小为 16,但同步路径每次只提交一个请求,队列大小没有被利用。 + +低风险验证方向: + +1. 在 `ax-driver` blk glue 层建立最小 pending request 表,使用 `read_blocks_nb()` / `complete_read_blocks()` 做 A/B。 +2. 先只支持读请求并保持 fallback 到同步路径,避免一次性改写整个 block queue contract。 +3. 用同一 `dd` workload 复测 `add_notify_wait_pop` 占比、host elapsed、guest executed instructions 和 guest real time。 + +### 3. net 的 copy/move 和 inflight 管理是当前最明确的数据面热点 + +证据: + +- `net-wget-focused` 中 `memcpy` 聚合 9.984%,`memmove` 聚合 3.072%。 +- `NetInner::reclaim_rx()` 明确执行 `copy_within()` 去除 virtio-net header。 +- `submit_tx()` 每包创建 staging Vec 并复制 payload。 +- `RxInflight`/`TxInflight` BTree 聚合 3.395%。 + +低风险验证方向: + +1. 如果上层 `rd_net` API 允许,RX buffer 保留 headroom 或返回 packet offset,避免 `copy_within()`。 +2. TX 侧改为复用 per-queue staging buffer 池,或让上层 DMA buffer 预留 virtio-net header 空间。 +3. 将 QUEUE_SIZE=64 的 token 映射从 `BTreeMap` 替换为固定数组或 slab,A/B 观察 `RxInflight`/`TxInflight` 聚合占比。 + +### 4. PCI notify 有明确源码 TODO,但本轮不是最大热点 + +`virtio-drivers` PCI transport `notify()` 每次写 queue select 后读 `queue_notify_off`,源码中已有 `TODO: Consider caching this somewhere (per queue).`。本轮 profile 中 notify 没有单独成为 top symbol,但它是低风险、局部的优化候选。需要为 notify 次数增加计数或在高 PPS workload 下复测后再改。 + +### 5. qperf 目前不能替代硬件 PMU + +本轮使用的 qperf 能回答“guest 内哪些函数/栈占用采样最多”,但不能直接回答: + +- 精确 guest cycles。 +- guest cache misses。 +- guest PMU retired instructions。 +- virtqueue 队列深度时间序列。 +- notify/kick 次数。 +- copy 字节数。 +- alloc/free 次数。 +- lock wait time。 + +这些指标需要后续在 qperf plugin、virtio-drivers 或 glue 层增加轻量计数器,或结合 host perf/ftrace/bpftrace。 + +## 结论 + +1. 本仓库当前 `virtio-drivers 0.13.0` 集成路径可被新的 harness/qperf 稳定采样,boot、virtio-blk、virtio-net 均生成了 `report.json`、folded stack 和 SVG 火焰图,采样 dropped/failures 均为 0。 +2. virtio-blk 的首要瓶颈候选是同步 `add_notify_wait_pop` 路径和没有利用 queue depth 的 glue 层。`blk-read-focused` 中该路径聚合为 6.427%。 +3. virtio-net 的首要瓶颈候选是 copy/move 和 inflight BTree 管理。`net-wget-focused` 中 `memcpy` 为 9.984%,`memmove` 为 3.072%,net inflight BTree 为 3.395%。 +4. vsock 在当前 WSL2 host 上无法测试,阻塞点是 `/dev/vhost-vsock` 缺失。本报告不编造 vsock 数据面数字。 +5. 下一步最值得做的小补丁是 net RX 去 `copy_within()` 或 token map 固定数组化;blk 的异步队列化收益可能更大,但改动面和接口风险也更高,应先做最小 pending-read 原型。 + +## 复现命令 + +boot: + +```bash +docker run --rm -v "$PWD":/work -w /work \ + -e STARRY_SYSCALL_HARNESS_IN_DOCKER=1 \ + ghcr.io/rcore-os/tgoskits-container:latest bash -lc ' +python3 tools/starry-syscall-harness/harness.py perf-profile \ + --repo-root /work --arch riscv64 --timeout 20 --format all \ + --freq 99 --max-depth 64 --mode tb --top 50 --min-percent 0.5 \ + --host-time --output-dir target/qperf-virtio-drivers/boot --no-docker +' +``` + +blk: + +```bash +docker run --rm -v "$PWD":/work -w /work \ + -e STARRY_SYSCALL_HARNESS_IN_DOCKER=1 \ + ghcr.io/rcore-os/tgoskits-container:latest bash -lc ' +python3 tools/starry-syscall-harness/harness.py perf-profile \ + --repo-root /work --arch riscv64 --timeout 25 --format all \ + --freq 99 --max-depth 64 --mode tb --top 80 --min-percent 0.3 \ + --host-time \ + --shell-init-cmd "echo QPERF_BLK_READ_FOCUSED; time dd if=/usr/bin/lto-dump of=/dev/null bs=64k; sync; poweroff -f" \ + --output-dir target/qperf-virtio-drivers/blk-read-focused --no-docker +' +``` + +net: + +```bash +docker run --rm -v "$PWD":/work -w /work \ + -e STARRY_SYSCALL_HARNESS_IN_DOCKER=1 \ + ghcr.io/rcore-os/tgoskits-container:latest bash -lc ' +python3 -m http.server 8000 --bind 0.0.0.0 >/tmp/qperf-http.log 2>&1 & +server=$! +trap "kill $server 2>/dev/null || true" EXIT +python3 tools/starry-syscall-harness/harness.py perf-profile \ + --repo-root /work --arch riscv64 --timeout 25 --format all \ + --freq 99 --max-depth 64 --mode tb --top 80 --min-percent 0.3 \ + --host-time \ + --shell-init-cmd "echo QPERF_NET_WGET_FOCUSED; time wget -O /dev/null http://10.0.2.2:8000/tmp/axbuild/rootfs/rootfs-riscv64-alpine.img.tar.xz; sync; poweroff -f" \ + --output-dir target/qperf-virtio-drivers/net-wget-focused --no-docker +' +``` + +vsock probe: + +```bash +docker run --rm -v "$PWD":/work -w /work \ + -e STARRY_SYSCALL_HARNESS_IN_DOCKER=1 \ + ghcr.io/rcore-os/tgoskits-container:latest bash -lc ' +python3 tools/starry-syscall-harness/harness.py perf-profile \ + --repo-root /work --arch riscv64 --timeout 12 --format folded \ + --freq 99 --max-depth 64 --mode tb --top 30 --min-percent 0.5 \ + --host-time \ + --qemu-arg=-device --qemu-arg=vhost-vsock-pci,guest-cid=3 \ + --output-dir target/qperf-virtio-drivers/vsock-probe --no-docker +' +``` diff --git a/docs/qperf-virtio-optimization-report.md b/docs/qperf-virtio-optimization-report.md new file mode 100644 index 0000000000..5685a7a20a --- /dev/null +++ b/docs/qperf-virtio-optimization-report.md @@ -0,0 +1,433 @@ +# qperf VirtIO 优化实践报告 + +## 背景与目标 + +本报告记录基于 `docs/qperf-virtio-performance-analysis.md` 的实际优化尝试。目标是保持补丁小、风险低、可回滚,并尽量用本地 qperf 结果做 A/B 验证。 + +参考的 openKylin vsock 文档强调:优化前先把实验环境、命令、重复次数和指标固定;优化项要围绕真实瓶颈,例如 credit update、buffer、锁、copy、alloc、notify/kick 和队列行为;如果优化无效,也应记录原因。 + +首次分析时,本地 qperf 的主要限制是:`perf-profile` 只能跑 StarryOS 默认 boot profile,不能注入专门的 vsock/net/blk workload。因此早期补丁分为两类: + +- 已用 qperf 直接验证效果的 measurement 修正。 +- 已编译和 clippy 验证,但缺少专门 workload,暂不能声明吞吐/延迟收益的 data path 微优化。 + +随后已修复 qperf/harness 功能:`perf-profile` 支持 `--shell-init-cmd`、`--shell-prefix`、`--qemu-arg`,qperf plugin 在 QEMU timeout 退出时也能生成 `qperf.summary.txt`。本报告追加一轮 workload 复测,用于重新判断已有微优化是否有可量化依据。 + +## 实验环境 + +| 项目 | 值 | +| --- | --- | +| 日期 | 2026-05-29 Asia/Shanghai | +| 仓库 commit | `6e748d6b7` | +| 宿主系统 | `Linux LAPTOP-SAOPKIGH 5.15.167.4-microsoft-standard-WSL2` | +| CPU | Intel Core i7-14650HX, 24 logical CPUs | +| Docker image | `ghcr.io/rcore-os/tgoskits-container:latest` | +| QEMU | `/opt/qemu-10.2.1/bin/qemu-system-riscv64` | +| qperf 参数 | `--arch riscv64 --timeout 20 --format folded --freq 99 --max-depth 64 --mode tb --top 30 --min-percent 2.0` | +| QEMU 设备 | `virtio-blk-pci`, `virtio-net-pci`, user net | +| vsock 设备 | 未配置 | + +baseline 与 patched 均重复 3 次,输出位于: + +- `target/qperf-virtio-experiment/baseline-run{1,2,3}/perf/riscv64/latest` +- `target/qperf-virtio-experiment/patched-run{1,2,3}/perf/riscv64/latest` +- `target/qperf-virtio-experiment/diff-run{1,2,3}/perf-diff` + +## qperf/qpef 使用方法 + +baseline: + +```bash +for i in 1 2 3; do + python3 tools/starry-syscall-harness/harness.py perf-profile \ + --arch riscv64 \ + --timeout 20 \ + --format folded \ + --freq 99 \ + --max-depth 64 \ + --mode tb \ + --top 30 \ + --min-percent 2.0 \ + --output-dir "target/qperf-virtio-experiment/baseline-run${i}" +done +``` + +patched: + +```bash +for i in 1 2 3; do + python3 tools/starry-syscall-harness/harness.py perf-profile \ + --arch riscv64 \ + --timeout 20 \ + --format folded \ + --freq 99 \ + --max-depth 64 \ + --mode tb \ + --top 30 \ + --min-percent 2.0 \ + --output-dir "target/qperf-virtio-experiment/patched-run${i}" +done +``` + +diff: + +```bash +for i in 1 2 3; do + python3 tools/starry-syscall-harness/harness.py perf-diff \ + --baseline "target/qperf-virtio-experiment/baseline-run${i}/perf/riscv64/latest" \ + --compare "target/qperf-virtio-experiment/patched-run${i}/perf/riscv64/latest" \ + --top 20 \ + --output-dir "target/qperf-virtio-experiment/diff-run${i}" +done +``` + +注意:本仓库未发现单独的 `qpef` 命令,本报告按 `qperf` 工具记录。 + +## Baseline 数据 + +| run | result | samples | top1 | top2 | top3 | +| --- | --- | ---: | --- | --- | --- | +| baseline-1 | ok | 1976 | `0x8001359c` 76 / 3.8462% | `0x8000b04e` 72 / 3.6437% | `0x8000b05a` 63 / 3.1883% | +| baseline-2 | ok | 1979 | `0x8001359c` 94 / 4.7499% | `0x8000b04e` 73 / 3.6887% | `0x8000b05a` 58 / 2.9308% | +| baseline-3 | ok | 1979 | `0x8001359c` 91 / 4.5983% | `0x8000b04e` 72 / 3.6382% | `0x8000b05a` 58 / 2.9308% | + +baseline 暴露出测量瓶颈:top 热点多为 `0x800...` 裸地址,qperf 没有把 QEMU 采到的低地址物理别名映射到 StarryOS high-half kernel text。 + +## 瓶颈分析 + +本次 qperf 直接证明的问题: + +- qperf 只检测 `.text` high-half virtual range,缺少 `.head.text` 和低地址 physical alias,导致 baseline 不能解析主要热点。 +- boot profile 的稳定热点集中在启动、PCI/FDT probe、显示锁等待、调度检查,不是 VirtIO data path workload。 + +本次代码审阅发现但尚未被 workload 定量验证的问题: + +- virtio-net TX 路径先调用一次 `fill_buffer_header` 计算 header 长度,再分配并零填充 `header + packet`,随后再调用一次 `fill_buffer_header`,会带来额外 header 查询和 packet 大小的零填充。 +- block binding 的 `read_block`/`write_block` 先通过 `self.block_size()` 锁一次 queue,再为实际 I/O 锁一次 queue,每次调用多一次 `SpinNoIrq` lock/unlock。 +- vsock poll loop 每次 `poll_vsock_interfaces` 都先分配 4KiB 临时 buffer,即使没有 pending event 且 `poll_event()` 返回 `None`。 + +## 优化尝试 + +### Patch 1: qperf text/alias 检测修正 + +文件:`scripts/axbuild/src/starry/perf.rs` + +改动: + +- qperf kernel text range 从只看 `.text` 改为合并 `.head.text` 和 `.text`。 +- 如果 `AX_CONFIG_PATH` 没有提供物理基址,则为 high-half virtual text 增加低 32 位 physical alias fallback。 +- 生成 QEMU plugin 参数时传入 `filter_alias_start`、`filter_alias_end`、`filter_alias_offset`。 + +动机: + +- baseline 热点 `0x8001359c`、`0x8000b04e`、`0x8000b05a` 无法符号化,导致 qperf 输出不能指导 VirtIO 优化。 + +实测结果: + +- patched stderr 显示: + +```text +qperf: detected kernel text virtual range: 0xffffffff80000000..0xffffffff802a4dc2 +qperf: detected kernel text physical alias: 0x80000000..0x802a4dc2 +filter_alias_offset=0xffffffff00000000 +``` + +- patched top 热点从裸地址变为符号: + +| baseline 地址 | patched 符号 | +| --- | --- | +| `0x8001359c` | `ax_driver::pci::fdt::probe_generic_ecam+0x710` | +| `0x8000b04e` / `0x8000b05a` | `ax_task::wait_queue::WaitQueue::wait_until(... ax_display ... RawMutex::lock_after_prepare)` | +| `0x800004f8` | `_head+0x4f8` | + +收益: + +- qperf 报告从“地址列表”变成可定位的函数热点列表,这是后续 VirtIO 优化的前置条件。 + +风险: + +- low-32-bit alias 是 fallback,仅在 config 没有物理基址时启用;对非 high-half 或特殊映射平台可能不适用。 +- 该补丁只影响 qperf 测量路径,不改变内核运行逻辑。 + +### Patch 2: virtio-net TX staging 减少零填充和重复 header 查询 + +文件:`drivers/ax-driver/src/virtio/net.rs` + +改动: + +- 删除 `raw_header_len()`。 +- TX staging 使用 `Vec::with_capacity(16 + packet_len)`,先只 resize 16 字节给 `fill_buffer_header()` 写 header。 +- `truncate(header_len)` 后 `extend_from_slice(packet)`,避免把整个 packet 区域先零填充。 + +动机: + +- TX 数据路径中 packet payload 本来马上会被 copy 覆盖,按 `header + packet_len` 全量 `vec![0; ...]` 的零填充没有必要。 +- 原逻辑为了计算 header 长度额外调用一次 `fill_buffer_header()`。 + +本地验证: + +- 编译和 clippy 通过。 +- 当前 qperf 没有网络 TX workload,不能声明吞吐收益。 + +风险: + +- 依赖 virtio-net header 不超过 16 字节;旧实现的 `raw_header_len()` 也使用 `[0_u8; 16]`,因此行为边界与旧代码一致。 +- 仍然保留 staging copy,因为 `VirtIONetRaw::transmit_begin(&staging)` 后需要在 complete 时用同一 staging buffer。 + +### Patch 3: virtio-blk binding 避免重复 queue lock + +文件:`drivers/ax-driver/src/block/binding.rs` + +改动: + +- `read_block` 和 `write_block` 先取 `use_irq_completion()`,再锁 `self.queue`。 +- 在同一把 queue lock 内读取 `block_size()` 并提交 I/O,避免 `self.block_size()` 单独锁一次。 + +动机: + +- 每次 block read/write 少一次 `SpinNoIrq` lock/unlock。 +- 改动不改变请求切分、等待和错误处理。 + +本地验证: + +- 编译和 clippy 通过。 +- qperf 默认 boot profile 没有显著 virtio-blk data path top 热点,无法量化该补丁对吞吐/延迟的收益。 + +风险: + +- buffer 长度校验时 queue lock 持有时间略提前;校验本身很短,风险低。 + +### Patch 4: vsock poll loop 懒分配 RX 临时 buffer + +文件:`os/arceos/modules/axnet-ng/src/device/vsock.rs` + +改动: + +- `poll_vsock_interfaces()` 不再进入函数就分配 4KiB buffer。 +- 改为 `Option>`,只有处理 pending event 或 `poll_event()` 返回 event 时才分配一次,并在本轮事件处理内复用。 + +动机: + +- 空闲 poll 是高频路径,旧逻辑在没有事件时仍分配 4KiB 临时 buffer。 + +本地验证: + +- 编译和 clippy 通过。 +- 当前 riscv64 qperf QEMU 没有 vsock device,无法运行 vsock workload 验证。 + +风险: + +- 只改变 buffer 分配时机,不改变 `handle_vsock_event()` 和 `dev.recv()` 的数据语义。 + +## A/B 对比结果 + +patched 三次运行: + +| run | result | samples | top1 | top2 | top3 | +| --- | --- | ---: | --- | --- | --- | +| patched-1 | ok | 1979 | `probe_generic_ecam+0x710` 90 / 4.5478% | `RawMutex::lock_after_prepare+0x45a` 70 / 3.5371% | `RawMutex::lock_after_prepare+0x466` 63 / 3.1834% | +| patched-2 | ok | 1979 | `probe_generic_ecam+0x710` 84 / 4.2446% | `RawMutex::lock_after_prepare+0x45a` 52 / 2.6276% | `RawMutex::lock_after_prepare+0x466` 44 / 2.2233% | +| patched-3 | ok | 1979 | `probe_generic_ecam+0x710` 103 / 5.2046% | `RawMutex::lock_after_prepare+0x466` 68 / 3.4361% | `RawMutex::lock_after_prepare+0x45a` 67 / 3.3855% | + +由于 Patch 1 改变了符号化,直接 `perf-diff` 主要显示“裸地址消失、符号名出现”。例如 run1: + +```text ++4.55% probe_generic_ecam+0x710 (0.00% -> 4.55%) +-3.85% 0x8001359c (3.85% -> 0.00%) +-3.64% 0x8000b04e (3.64% -> 0.00%) ++3.54% RawMutex::lock_after_prepare+0x45a (0.00% -> 3.54%) +``` + +因此下面按同一热点别名分组比较: + +| group | baseline avg samples | baseline avg % | patched avg samples | patched avg % | 结论 | +| --- | ---: | ---: | ---: | ---: | --- | +| qperf total samples | 1978.00 +/- 1.73 | n/a | 1979.00 +/- 0.00 | n/a | 采样稳定 | +| PCI/FDT probe alias | 87.00 +/- 9.64 | 4.3981 +/- 0.4840 | 92.33 +/- 9.71 | 4.6657 +/- 0.4907 | 无稳定性能变化 | +| display RawMutex wait alias | 132.00 +/- 2.65 | 6.6735 +/- 0.1396 | 127.00 +/- 12.17 | 6.4173 +/- 0.6147 | 变化在波动内 | +| `_head+0x4f8` alias | 36.33 +/- 3.51 | 1.8370 +/- 0.1791 | 40.00 +/- 3.00 | 2.0212 +/- 0.1516 | 非 VirtIO 目标 | +| preempt check | 95.00 +/- 8.54 | 4.8026 +/- 0.4286 | 109.33 +/- 8.96 | 5.5247 +/- 0.4529 | 调度波动,非 data path 结论 | + +结论: + +- Patch 1 有明确收益:qperf 符号化可解释性提升,后续分析可以定位到函数。 +- Patch 2/3/4 是低风险微优化,但当前 boot-only qperf 不能证明吞吐或延迟收益。 +- 本次没有观察到 virtio-blk/net/vsock data path 在 top profile 中成为稳定瓶颈。 + +## workload 复测结果 + +复测命令使用新的 workload 注入入口,所有成功样本均为 `--timeout 30 --format folded --freq 99 --max-depth 64 --mode tb --top 40 --min-percent 0.5`,输出位于 `target/qperf-virtio-rerun`。成功样本的 `qperf.summary.txt` 均显示 `dropped_samples = 0`、`sample_failures = 0`。 + +### boot/idle + +| run | result | samples | top1 | +| --- | --- | ---: | --- | +| boot-1 | ok | 2969 | `probe_generic_ecam+0x710` 129 / 4.3449% | +| boot-2 | ok | 2969 | `probe_generic_ecam+0x710` 150 / 5.0522% | +| boot-3 | ok | 2969 | `probe_generic_ecam+0x710` 143 / 4.8164% | + +boot/idle 仍主要反映启动探测、显示 wait queue、调度和空闲路径,不适合作为 VirtIO 数据面优化收益依据。 + +### virtio-blk: rootfs 文件冷读 + +guest workload: + +```sh +time dd if=/usr/bin/lto-dump of=/dev/null bs=64k +``` + +原始结果: + +| run | bytes | dd seconds | throughput | real | +| --- | ---: | ---: | ---: | ---: | +| blk-read-1 | 53,601,104 | 4.299533s | 11.9MB/s | 4.35s | +| blk-read-2 | 53,601,104 | 4.369256s | 11.7MB/s | 4.41s | +| blk-read-3 | 53,601,104 | 4.160124s | 12.3MB/s | 4.21s | + +平均 `real = 4.323s`,标准差 `0.103s`。 + +qperf 归类结果: + +| category | avg | range | 判断 | +| --- | ---: | ---: | --- | +| `memcpy` | 4.199% | 3.806%-4.412% | 读后 copy 成本稳定可见 | +| `VirtQueue::add_notify_wait_pop` | 3.795% | 3.402%-4.178% | 同步 virtqueue submit/notify/wait/pop 是 blk-read 主要热点 | +| display wait lock | 8.837% | 8.690%-8.993% | 仍有控制台/显示噪声,但低于 boot | + +对已有 Patch 3 的判断:避免一次重复 queue lock 是正确的小优化,但这轮数据表明更大的成本在 `VirtIOBlk::read_blocks()` 内部的同步 virtqueue 完成路径,以及 `read_block()` 把 `BlockData` 再 copy 到目标 buffer 的路径。后续不应继续围绕单次 lock 微调,应优先评估批量/异步提交和减少 block copy。 + +### virtio-net/vnet: HTTP RX + +宿主容器启动: + +```bash +python3 -m http.server 8000 --bind 0.0.0.0 +``` + +guest workload: + +```sh +time wget -O /dev/null http://10.0.2.2:8000/tmp/axbuild/rootfs/rootfs-riscv64-alpine.img.tar.xz +``` + +原始结果: + +| run | transfer | real | +| --- | ---: | ---: | +| net-wget-1 | 60.6M | 5.65s | +| net-wget-2 | 60.6M | 5.57s | +| net-wget-3 | 60.6M | 5.73s | + +平均 `real = 5.650s`,标准差 `0.080s`。 + +qperf 归类结果: + +| category | avg | range | 判断 | +| --- | ---: | ---: | --- | +| `memcpy` | 5.345% | 5.086%-5.526% | RX 数据搬运是一阶热点 | +| `memmove` | 1.381% | 1.145%-1.550% | header 去除/packet 移动成本可见 | +| `NetRxQueue::submit` | 2.010% | 1.819%-2.190% | RX buffer 重新投递路径稳定出现 | +| `RxInflight` | 3.919% | 3.605%-4.109% | inflight 管理成本存在,但和 boot 噪声需继续拆分 | + +对已有 Patch 2 的判断:Patch 2 只优化 TX staging;本次 `wget` 是 RX 主导,不能证明 TX patch 的收益。新的数据指向 RX:`reclaim_rx()` 中 `buffer.copy_within(header_len..header_len + packet_len, 0)` 以及 `BTreeMap` 管理值得优先做小补丁验证。 + +### virtio-vsock + +使用新 `--qemu-arg` 探测: + +```bash +--qemu-arg=-device \ +--qemu-arg=vhost-vsock-pci,guest-cid=3 +``` + +QEMU 失败: + +```text +Could not open '/dev/vhost-vsock': No such file or directory +``` + +结论:当前宿主/Docker 环境不能创建 `vhost-vsock-pci`,vsock 数据面仍无法本地量化。已有 Patch 4 只能维持为“代码审阅支持的低风险空闲路径优化”,不能声明性能收益。 + +## 正确性验证 + +格式: + +```bash +cargo fmt --check +``` + +结果:通过。 + +clippy: + +```bash +docker run --rm -v "$PWD":/work -w /work ghcr.io/rcore-os/tgoskits-container:latest bash -lc ' +set -euo pipefail +cargo xtask clippy --package ax-driver +cargo xtask clippy --package ax-net-ng +cargo xtask clippy --package tg-xtask +' +``` + +结果: + +- `ax-driver`:39 个 clippy checks 全部通过。 +- `ax-net-ng`:2 个 clippy checks 全部通过。 +- `tg-xtask`:1 个 clippy check 通过。 + +qperf: + +- baseline 3 次 `result: ok`。 +- patched 3 次 `result: ok`。 +- patched 3 次 samples 均为 `1979`。 +- workload 复测中 boot/blk/net 共 9 次 `result: ok`,samples 为 `2968-2969`,`dropped_samples = 0`,`sample_failures = 0`。 +- blk-read 三次均完成 53,601,104 bytes 冷读;net-wget 三次均完成 60.6M HTTP RX。 +- vsock probe 未进入 guest,QEMU 失败原因为宿主/容器缺少 `/dev/vhost-vsock`。 +- QEMU 到达 StarryOS shell,`eth0` DHCP 成功。 +- 未发现 panic/oops/BUG/hang。 +- baseline 和 patched 都有既有的 `kprobe selftest failed` / `kretprobe selftest failed` 日志,非本次补丁新增。 + +宿主机直接运行 `cargo xtask starry perf --help` 时遇到 `~/.cargo` registry cache permission 问题;按项目约束,Starry/qperf 命令改在 Docker 内确认并执行。 + +## 代码改动清单 + +本次没有创建 git commit,改动保留为工作区 patch,便于继续拆分: + +1. `scripts/axbuild/src/starry/perf.rs` + - qperf measurement 修正。 +2. `drivers/ax-driver/src/virtio/net.rs` + - virtio-net TX staging 微优化。 +3. `drivers/ax-driver/src/block/binding.rs` + - virtio-blk/block binding lock 微优化。 +4. `os/arceos/modules/axnet-ng/src/device/vsock.rs` + - vsock poll lazy allocation 微优化。 + +建议提交拆分: + +- `fix(starry): map qperf low text aliases for StarryOS` +- `perf(ax-driver): reduce virtio-net tx staging work` +- `perf(ax-driver): avoid duplicate block queue locking` +- `perf(ax-net-ng): lazily allocate vsock poll buffer` + +## 结论和下一步建议 + +值得继续优化的路径: + +- qperf/harness 本身:workload 注入和 extra QEMU args 已可用;下一步应把常用 blk/net/vsock workload 固化为可复用 case,并记录 copy bytes、submit/completion、kick/notify 等结构化计数。 +- virtio-net RX:`wget` RX 负载已证明 copy/move、`NetRxQueue::submit` 和 `RxInflight` 管理是优先方向;TX staging patch 仍需要 TX workload 单独验证。 +- virtio-blk:`dd` 冷读已证明同步 `VirtQueue::add_notify_wait_pop` 和读后 copy 是主要热点;应优先评估批量提交、异步完成和减少中间 block copy。 +- virtio-vsock:先解决宿主/Docker `/dev/vhost-vsock` 透传,再建立 host/guest workload,之后评估 credit update、poll interval、buffer 和锁竞争。 + +本次无效或未能证明有效的点: + +- 默认 boot profile 不能证明 net/vsock/blk throughput 优化;必须使用 workload 注入后的 profile。 +- 当前 `perf-diff` 对 measurement 修正前后的比较会被符号化变化污染,不能直接作为性能收益。 +- vsock 路径在当前环境仍没有 runtime 覆盖,因为 QEMU 无法打开 `/dev/vhost-vsock`。 + +下一步最小可复现实验建议: + +1. 为 blk/net/vsock 各加一个不会引入新依赖的 guest microbench 或 busybox 命令脚本。 +2. 增加 `qemu-riscv64-vsock` 配置,文档化 `modprobe vhost_vsock`、`/dev/vhost-vsock` 和 guest CID。 +3. 在 driver 层临时加入可开关统计项:submit/completion 次数、kick/notify 次数、copy bytes、alloc count、poll idle/event 次数。 +4. 针对 net RX 的 `copy_within()` 和 `BTreeMap` 做 1-2 个最小补丁,并用 net-wget workload 3 次 A/B。 +5. 针对 blk 的同步 virtqueue wait/pop 和读后 copy 做 1-2 个最小补丁,并用 blk-read workload 3 次 A/B。 diff --git a/docs/qperf-virtio-performance-analysis.md b/docs/qperf-virtio-performance-analysis.md new file mode 100644 index 0000000000..fc1e0cc5fd --- /dev/null +++ b/docs/qperf-virtio-performance-analysis.md @@ -0,0 +1,408 @@ +# qperf VirtIO 性能分析报告 + +## 背景与目标 + +本报告记录一次在本仓库内使用本地 qperf 工具对 StarryOS VirtIO 路径进行的性能分析实践。目标不是给出泛泛方案,而是先确认本仓库 qperf/qpef 的实际入口、运行约束和可采样范围,再在可运行范围内建立 baseline,并据此选择最小可验证补丁。 + +参考资料: + +- +- + +参考文档的方法可以概括为: + +- 固定环境、命令、参数和重复次数,保留原始结果。 +- 先用采样和阶段统计定位热点,再讨论 tx/rx、credit、queue、copy、alloc、notify/kick、锁竞争等具体瓶颈。 +- 优化以小补丁为单位做 A/B 对比,允许记录无效或回退的尝试。 +- 对 vsock 这类异步/信用流控路径,优先关注 buffer 大小、credit update、事件通知频率、锁拆分、批处理和不必要分配。 + +本仓库未发现独立名为 `qpef` 的工具;实际可用入口是 `tools/qperf` 和 `tools/starry-syscall-harness/harness.py perf-profile`。下文按本仓库的 `qperf` 记录。 + +## 本地 qperf/qpef 使用方法 + +仓库内 qperf 相关入口: + +- `tools/qperf/`:QEMU TCG plugin 与 analyzer。 +- `scripts/axbuild/src/starry/perf.rs`:`cargo xtask starry perf` 的实现,负责构建 qperf、构建 StarryOS、准备 rootfs、生成 QEMU 参数、注入 `-plugin`、运行 analyzer。 +- `tools/starry-syscall-harness/harness.py perf-profile`:推荐入口,会在 Docker 中运行 StarryOS/qperf 并生成 `report.json`、`report.md`、`hotspots.csv`。 +- `tools/starry-syscall-harness/harness.py perf-diff`:比较两次 folded stack。 + +已确认的 help 输出: + +```text +python3 tools/starry-syscall-harness/harness.py perf-profile --help + +--arch {riscv64,loongarch64} +--timeout TIMEOUT +--format {folded,svg,pprof,all} +--freq FREQ +--max-depth MAX_DEPTH +--mode {tb,insn} +--top TOP +--min-percent MIN_PERCENT +--output-dir OUTPUT_DIR +--debug +--kernel-filter +``` + +容器内 `cargo xtask starry perf --help`: + +```text +Build and profile StarryOS with qperf + +Usage: tg-xtask starry perf [OPTIONS] + +Options: + --arch + --freq [default: 99] + --out + --format [default: all] [possible values: folded, svg, pprof, all] + --max-depth [default: 64] + --timeout [default: 20] + --mode [default: tb] [possible values: tb, insn] + --top [default: 20] + --debug + --kernel-filter +``` + +本次 baseline 命令: + +```bash +for i in 1 2 3; do + python3 tools/starry-syscall-harness/harness.py perf-profile \ + --arch riscv64 \ + --timeout 20 \ + --format folded \ + --freq 99 \ + --max-depth 64 \ + --mode tb \ + --top 30 \ + --min-percent 2.0 \ + --output-dir "target/qperf-virtio-experiment/baseline-run${i}" +done +``` + +本次 patched 命令与 baseline 参数一致,仅输出目录改为 `patched-run${i}`。 + +## 实验环境 + +| 项目 | 值 | +| --- | --- | +| 日期 | 2026-05-29 Asia/Shanghai | +| 仓库 commit | `6e748d6b7` | +| 宿主系统 | `Linux LAPTOP-SAOPKIGH 5.15.167.4-microsoft-standard-WSL2` | +| CPU | Intel Core i7-14650HX, 24 logical CPUs | +| 虚拟化 | WSL2, Microsoft hypervisor, VT-x | +| Docker image | `ghcr.io/rcore-os/tgoskits-container:latest` | +| 容器工具 | `/usr/sbin/debugfs`, `riscv64-linux-musl-gcc`, `/opt/qemu-10.2.1/bin/qemu-system-riscv64` | +| Cargo | `cargo 1.97.0-nightly (2026-04-24)` in container | +| Starry target | `riscv64gc-unknown-none-elf`, release build | +| qperf 参数 | `freq=99`, `mode=tb`, `max_depth=64`, `queue_size=4096`, `timeout=20s`, `format=folded` | +| QEMU | `-machine virt -m 512M -nographic -cpu rv64`, 1 vCPU | + +`harness.py doctor` 结果: + +```text +docker: ok +ghcr.io/rcore-os/tgoskits-container:latest: ok +container-tools: ok +repo_root: /home/cg24/tgoskits +``` + +QEMU 设备配置来自 `os/StarryOS/configs/qemu/qemu-riscv64.toml`: + +```toml +args = [ + "-m", "512M", + "-nographic", + "-cpu", "rv64", + "-device", "virtio-blk-pci,drive=disk0", + "-drive", "id=disk0,if=none,format=raw,file=${workspace}/tmp/axbuild/rootfs/rootfs-riscv64-alpine.img", + "-device", "virtio-net-pci,netdev=net0", + "-netdev", "user,id=net0", +] +``` + +StarryOS riscv64 build feature 包含: + +```toml +"ax-driver/virtio-blk" +"ax-driver/virtio-net" +"ax-driver/virtio-socket" +``` + +但本次 qperf QEMU 参数没有 `virtio-vsock` 或 `vhost-vsock` 设备,因此 vsock 代码被编译,但没有被本次 riscv64 qperf profile 运行时覆盖。 + +## 相关代码路径 + +本次检查的路径: + +- virtio-vsock driver:`drivers/ax-driver/src/virtio/vsock.rs` +- vsock runtime/poll:`os/arceos/modules/axnet-ng/src/device/vsock.rs` +- vsock connection manager:`os/arceos/modules/axnet-ng/src/vsock/connection_manager.rs` +- virtio-net:`drivers/ax-driver/src/virtio/net.rs` +- virtio-blk device:`drivers/ax-driver/src/virtio/block.rs` +- block binding/queue lock:`drivers/ax-driver/src/block/binding.rs` +- block async queue:`drivers/blk/rd-block/src/lib.rs` +- qperf Starry runner:`scripts/axbuild/src/starry/perf.rs` + +初步风险点: + +- vsock:poll loop 在空闲路径中的临时 buffer 分配、`VSOCK_DEVICE` 与 connection manager 锁、credit update 频率。 +- net/vnet:TX staging copy、packet buffer 零填充、TX/RX 共享 raw device 访问、queue size 64。 +- blk:`Block` 外层 `SpinNoIrq` 锁、每次请求的 block size 查询、同步等待路径、32 sector DMA buffer 上限。 +- qperf:guest 物理低地址和 high-half virtual text 的符号解析一致性。 + +## 实验设计与可运行性 + +| 路径 | 计划实验 | 当前本地结果 | +| --- | --- | --- | +| vsock | 配置 guest CID,host/guest 做 send/recv,采 tx/rx、credit、copy、锁热点 | 当前 riscv64 qperf QEMU 参数无 vsock 设备,harness 也没有 workload/shell 注入入口;未能实测 | +| net/vnet | DHCP 后运行 ping/iperf/wget 或 guest 内收发包循环,采 TX/RX data path | QEMU 有 virtio-net/user net,启动时 DHCP 成功;当前 qperf 只能采默认 boot/profile,未能注入网络吞吐 workload | +| blk | rootfs boot read baseline,进一步运行 guest 内读写 microbench | QEMU 有 virtio-blk/rootfs,boot 会覆盖 init/read 路径;当前 qperf 无专门 block workload 注入,未测吞吐/延迟 | + +以上是首次分析时的状态。随后 qperf/harness 已补齐 `--shell-init-cmd`、`--shell-prefix` 和 `--qemu-arg`,并修复 timeout 退出时 plugin summary 可能丢失的问题。因此本报告后续增加一轮基于 workload 注入的复测,用于重新判断 virtio-blk 和 virtio-net 数据面热点。vsock 仍受宿主 `/dev/vhost-vsock` 缺失阻塞。 + +## Baseline 数据 + +baseline 三次结果目录: + +- `target/qperf-virtio-experiment/baseline-run1/perf/riscv64/latest` +- `target/qperf-virtio-experiment/baseline-run2/perf/riscv64/latest` +- `target/qperf-virtio-experiment/baseline-run3/perf/riscv64/latest` + +运行结果: + +| run | result | samples | top1 | top2 | top3 | +| --- | --- | ---: | --- | --- | --- | +| baseline-1 | ok | 1976 | `0x8001359c` 76 / 3.8462% | `0x8000b04e` 72 / 3.6437% | `0x8000b05a` 63 / 3.1883% | +| baseline-2 | ok | 1979 | `0x8001359c` 94 / 4.7499% | `0x8000b04e` 73 / 3.6887% | `0x8000b05a` 58 / 2.9308% | +| baseline-3 | ok | 1979 | `0x8001359c` 91 / 4.5983% | `0x8000b04e` 72 / 3.6382% | `0x8000b05a` 58 / 2.9308% | + +采样总数平均值:`1978.00`,标准差:`1.73`。 + +baseline 的 `profile.stderr` 显示: + +```text +qperf: detected kernel .text virtual range: 0xffffffff80001000..0xffffffff802a4900 +QPerf arguments: filter_alias_start: None, filter_alias_end: None, filter_alias_offset: None +qemu-system-riscv64: terminating on signal 15 ... (timeout) +qperf: QEMU ended with exit status: 124 after producing samples +qperf-analyzer: stopped after 1976 records (0 bad records): UnexpectedEof +``` + +`timeout=20s` 是命令参数,QEMU 被 timeout 结束但已经产出 samples,harness 报告 `result: ok`。`UnexpectedEof` 来自 timeout 截断最后一条 raw record,analyzer 报告 `0 bad records`,本次按可用 profile 处理。 + +## 瓶颈分析 + +### 1. 首要问题是 qperf 符号化不可信 + +baseline top samples 主要是 `0x800...` 裸地址。StarryOS 运行后内核 text 位于 high-half virtual range,例如 `0xffffffff80001000..`,而 QEMU/plugin 采到的是低地址别名,例如 `0x8001359c`。baseline qperf 只检测 `.text` 的虚拟范围,没有传入物理别名,导致 analyzer 无法把这些地址解析到函数名。 + +这会直接阻断后续 VirtIO 优化判断:即使 top 地址稳定,也无法确定是 virtio-blk、virtio-net、vsock、调度、显示还是 PCI probe。 + +### 2. qperf boot profile 没有形成明确 VirtIO data path 热点 + +默认 boot profile 的明显事件包括: + +- virtio-blk rootfs 镜像作为磁盘设备挂载。 +- virtio-net user net 启动并 DHCP 成功:`eth0: DHCP acquired address 10.0.2.15/24`。 +- StarryOS 进入 shell。 + +但 baseline top 30 中没有可解释的 virtio-blk/net/vsock data path 符号。原因有两个: + +- baseline 符号化缺少物理别名。 +- 当前 qperf 没有 workload 注入,20s profile 大部分时间是启动、控制台、调度等待和空闲路径,而不是网络/块设备吞吐路径。 + +### 3. vsock 当前无法在本地 qperf riscv64 配置下实测 + +`qemu-riscv64` feature 包含 `ax-driver/virtio-socket`,但 QEMU args 没有 vsock device。要实测 vsock,需要至少补齐: + +- host 侧 `/dev/vhost-vsock` 和 `vhost_vsock` 模块。 +- QEMU args,例如 `-device vhost-vsock-pci,guest-cid=3`。 +- guest 内 AF_VSOCK workload 或 shell init 命令。 +- host/guest 对应 server/client。 + +这些步骤可能需要 root、内核模块和 VM 参数修改;当前环境没有直接执行。 + +## 对比口径 + +本次先做 measurement 修正补丁,再做 patched profile。由于修正了 qperf 的符号映射,`perf-diff` 中 baseline 的裸地址和 patched 的符号名会表现为一组地址消失、一组符号出现。这不是纯性能变化,不能直接解释为优化收益。 + +因此本报告采用两个口径: + +- 原始 qperf 结果:逐次列出 samples 和 top functions。 +- 人工归类对比:将 baseline 裸地址与 patched 符号化结果按别名归为同一类,观察大体波动。 + +patched 三次结果: + +| run | result | samples | top1 | top2 | top3 | +| --- | --- | ---: | --- | --- | --- | +| patched-1 | ok | 1979 | `probe_generic_ecam+0x710` 90 / 4.5478% | `RawMutex::lock_after_prepare+0x45a` 70 / 3.5371% | `RawMutex::lock_after_prepare+0x466` 63 / 3.1834% | +| patched-2 | ok | 1979 | `probe_generic_ecam+0x710` 84 / 4.2446% | `RawMutex::lock_after_prepare+0x45a` 52 / 2.6276% | `RawMutex::lock_after_prepare+0x466` 44 / 2.2233% | +| patched-3 | ok | 1979 | `probe_generic_ecam+0x710` 103 / 5.2046% | `RawMutex::lock_after_prepare+0x466` 68 / 3.4361% | `RawMutex::lock_after_prepare+0x45a` 67 / 3.3855% | + +patched 的 `profile.stderr` 显示物理别名已经生效: + +```text +qperf: detected kernel text virtual range: 0xffffffff80000000..0xffffffff802a4dc2 +qperf: detected kernel text physical alias: 0x80000000..0x802a4dc2 +filter_alias_start=0x80000000 +filter_alias_end=0x802a4dc2 +filter_alias_offset=0xffffffff00000000 +``` + +归类对比: + +| group | baseline avg samples | baseline avg % | patched avg samples | patched avg % | 结论 | +| --- | ---: | ---: | ---: | ---: | --- | +| qperf total samples | 1978.00 +/- 1.73 | n/a | 1979.00 +/- 0.00 | n/a | 采样量稳定 | +| PCI/FDT probe alias | 87.00 +/- 9.64 | 4.3981 +/- 0.4840 | 92.33 +/- 9.71 | 4.6657 +/- 0.4907 | boot 阶段热点,非 VirtIO data path | +| display RawMutex wait alias | 132.00 +/- 2.65 | 6.6735 +/- 0.1396 | 127.00 +/- 12.17 | 6.4173 +/- 0.6147 | 波动内变化,不能证明优化 | +| `_head+0x4f8` alias | 36.33 +/- 3.51 | 1.8370 +/- 0.1791 | 40.00 +/- 3.00 | 2.0212 +/- 0.1516 | 启动低层路径,非优化目标 | +| preempt check | 95.00 +/- 8.54 | 4.8026 +/- 0.4286 | 109.33 +/- 8.96 | 5.5247 +/- 0.4529 | 调度/等待波动,非 VirtIO 结论 | + +## workload 注入复测 + +复测日期:`2026-05-29T02:23:16+08:00`。 + +复测使用已修复的入口: + +```bash +python3 tools/starry-syscall-harness/harness.py perf-profile \ + --arch riscv64 \ + --timeout 30 \ + --format folded \ + --freq 99 \ + --max-depth 64 \ + --mode tb \ + --top 40 \ + --min-percent 0.5 \ + --shell-init-cmd '' \ + --output-dir target/qperf-virtio-rerun/ +``` + +复测结果目录: + +- `target/qperf-virtio-rerun/boot-run{1,2,3}/perf/riscv64/latest` +- `target/qperf-virtio-rerun/blk-read-run{1,2,3}/perf/riscv64/latest` +- `target/qperf-virtio-rerun/net-wget-run{1,2,3}/perf/riscv64/latest` +- `target/qperf-virtio-rerun/vsock-probe/perf/riscv64/latest` + +所有成功样本的 qperf plugin summary 均为 `dropped_samples = 0`、`sample_failures = 0`。`boot` 三次 samples 均为 `2969`;`blk-read` 为 `2968/2969/2969`;`net-wget` 为 `2968/2969/2968`。 + +### blk-read workload + +guest 命令: + +```sh +echo BLK_READ_BEGIN +time dd if=/usr/bin/lto-dump of=/dev/null bs=64k +sync +echo BLK_READ_END +sleep 1 +``` + +原始吞吐输出: + +| run | bytes | dd seconds | dd throughput | real | +| --- | ---: | ---: | ---: | ---: | +| blk-read-1 | 53,601,104 | 4.299533s | 11.9MB/s | 4.35s | +| blk-read-2 | 53,601,104 | 4.369256s | 11.7MB/s | 4.41s | +| blk-read-3 | 53,601,104 | 4.160124s | 12.3MB/s | 4.21s | + +`real` 平均值 `4.323s`,标准差 `0.103s`。 + +qperf 归类统计(基于完整 folded stack 中的函数名子串匹配): + +| category | boot avg | blk-read avg | blk-read range | 说明 | +| --- | ---: | ---: | ---: | --- | +| `memcpy` | 0.348% | 4.199% | 3.806%-4.412% | 文件读出和 block buffer copy 成本明显上升 | +| `VirtQueue::add_notify_wait_pop` | 未显著出现 | 3.795% | 3.402%-4.178% | virtio-blk 同步提交、notify、等待完成路径成为稳定热点 | +| `display wait lock` | 11.294% | 8.837% | 8.690%-8.993% | 仍有控制台/显示等待噪声,但占比低于 boot | + +定位到的代码路径: + +- `drivers/ax-driver/src/virtio/block.rs` 中 `submit_request()` 直接调用 `VirtIOBlk::read_blocks()` / `write_blocks()`,当前完成语义是同步的。 +- `drivers/ax-driver/src/block/binding.rs` 中 `read_block()` 持有 queue lock 后调用 `read_blocks_blocking()`,随后把每个 `BlockData` copy 到用户提供 buffer。 + +结论:当前 blk-read 的一阶瓶颈不是块设备节点吞吐工具本身,而是同步 virtqueue request/complete 路径与读后 copy。后续值得优先验证的方向是批量/异步提交、减少 per-block copy,以及更大的 DMA buffer 或顺序读合并。 + +### net-wget workload + +宿主容器内启动 HTTP server: + +```bash +python3 -m http.server 8000 --bind 0.0.0.0 +``` + +guest 命令: + +```sh +echo NET_WGET_BEGIN +time wget -O /dev/null http://10.0.2.2:8000/tmp/axbuild/rootfs/rootfs-riscv64-alpine.img.tar.xz +echo NET_WGET_END +sleep 1 +``` + +原始结果: + +| run | transfer | real | +| --- | ---: | ---: | +| net-wget-1 | 60.6M | 5.65s | +| net-wget-2 | 60.6M | 5.57s | +| net-wget-3 | 60.6M | 5.73s | + +`real` 平均值 `5.650s`,标准差 `0.080s`。 + +qperf 归类统计: + +| category | boot avg | net-wget avg | net-wget range | 说明 | +| --- | ---: | ---: | ---: | --- | +| `memcpy` | 0.348% | 5.345% | 5.086%-5.526% | RX 数据搬运成为最明显数据面成本 | +| `memmove` | 未显著出现 | 1.381% | 1.145%-1.550% | packet/header 移动成本可见 | +| `NetRxQueue::submit` | 未显著出现 | 2.010% | 1.819%-2.190% | RX buffer 重新投递路径被 workload 稳定打中 | +| `RxInflight` | 4.861% | 3.919% | 3.605%-4.109% | boot 和 net 都有 BTree/RxInflight 管理成本,需进一步拆分启动噪声 | +| `VirtQueue::add_notify_wait_pop` | 未显著出现 | 0.247% | 0.168%-0.337% | RX 主要不是同步 notify/wait 热点 | + +定位到的代码路径: + +- `drivers/ax-driver/src/virtio/net.rs` 使用 `BTreeMap` 管理 RX inflight buffer。 +- `NetRxQueue::submit()` 进入 `with_task()` 后调用 `submit_rx()`,最终 `receive_begin()` 投递 DMA buffer。 +- `reclaim_rx()` 在收到包后执行 `buffer.copy_within(header_len..header_len + packet_len, 0)`,这解释了 net-wget 中 `memmove`/copy 类热点。 + +结论:virtio-net RX 的主要可优化点是 RX packet 从 virtio header 后移到 packet 起点的 copy/move,以及 inflight buffer 管理结构和投递路径。TX 路径本次 workload 不敏感,之前的 TX staging 微优化不能用 net-wget 证明收益。 + +### vsock 探测 + +vsock 设备探测命令使用: + +```bash +--qemu-arg=-device \ +--qemu-arg=vhost-vsock-pci,guest-cid=3 +``` + +结果:`target/qperf-virtio-rerun/vsock-probe/perf/riscv64/latest/profile.stderr` 中 QEMU 直接失败: + +```text +qemu-system-riscv64: -device vhost-vsock-pci,guest-cid=3: Could not open '/dev/vhost-vsock': No such file or directory +``` + +因此当前本地环境无法进入 virtio-vsock/vhost-vsock 数据面。宿主存在 `/dev/vsock`,但没有 `/dev/vhost-vsock`,Docker 容器内也未提供 vhost-vsock 设备。vsock 只能记录为“设备环境阻塞”,不能给出性能结论。 + +## 结论与下一步 + +本次能够闭环验证的关键结论是:qperf 默认 boot profile 可运行、可重复;原 baseline 存在物理地址别名导致的符号化问题,修正后能把 `0x800...` low alias 映射回 high-half kernel text,热点解释性显著提升。进一步修复 workload 注入后,blk-read 和 net-wget 已经可以打到对应 VirtIO 数据面。 + +对 VirtIO 路径的性能结论需要谨慎: + +- virtio-blk:`dd` 冷读 51.1MB 平均 `4.323s`,`memcpy` 平均 `4.199%`,`VirtQueue::add_notify_wait_pop` 平均 `3.795%`;同步 virtqueue 提交/完成和读后 copy 是主要瓶颈。 +- virtio-net/vnet:`wget` RX 60.6M 平均 `5.650s`,`memcpy` 平均 `5.345%`,`NetRxQueue::submit` 平均 `2.010%`,`memmove` 平均 `1.381%`;RX copy/move 和 buffer 重新投递路径值得继续优化。 +- virtio-vsock:代码编译但当前 Docker/宿主缺少 `/dev/vhost-vsock`,QEMU 无法创建设备,本地 qperf 未覆盖运行时路径。 + +建议下一步基于已经可运行的 workload 做更小粒度的 A/B: + +- blk:验证更大 DMA buffer、顺序读合并、异步/批量提交是否能降低 `add_notify_wait_pop` 和 copy 占比。 +- net:验证 RX header offset 处理是否能避免 `copy_within()`,以及用数组/slab 替换 `BTreeMap` inflight 管理是否降低 RX submit/reclaim 成本。 +- vsock:先在宿主启用并透传 `/dev/vhost-vsock`,再建立 host/guest send/recv workload。 +- 在 workload 中补充 queue depth、kick/notify 次数、alloc/free、copy 字节数、IRQ/poll 次数等结构化计数,再结合 qperf flamegraph 做小补丁 A/B。 diff --git a/docs/qperf-work-handoff.md b/docs/qperf-work-handoff.md new file mode 100644 index 0000000000..286236e554 --- /dev/null +++ b/docs/qperf-work-handoff.md @@ -0,0 +1,648 @@ +# qperf / StarryOS 性能工具链交接文档 + +本文面向后续接手的工程 agent,用于快速理解本轮 qperf 工具链改造、验证实验、virtio-blk 性能瓶颈定位与优化结果。后续可直接基于本文撰写总结报告或制作 PPT。 + +## 1. 当前状态 + +| 项目 | 内容 | +| --- | --- | +| 仓库 | `/home/cg24/tgoskits` | +| 当前分支 | `fix/starry-syscall-harness` | +| 已推送远端 | `origin/fix/starry-syscall-harness` | +| 最新提交 | `2cfa4e3f5 perf(virtio-blk): reduce qperf sync read queue churn` | +| 主要目标 | 把 qperf 从“能出火焰图的采样器”改造成能支撑 StarryOS virtio-blk/net/vsock 性能归因、A/B 验证和深栈火焰图分析的工具链 | + +本轮工作包含两类成果: + +1. qperf 工具链能力建设:marker/window、工程分类、virtio counters、A/B compare、`cargo starry perf` 集成、RISC-V frame-pointer 深调用栈火焰图。 +2. 基于新版 qperf 的 virtio-blk 瓶颈分析与一个最小优化:rsext4 data block readahead + virtio-blk direct read fast path。 + +## 2. 关键提交 + +| 提交 | 标题 | 主要内容 | +| --- | --- | --- | +| `ea91bd04f` | `feat(qperf): add workload-aware profiling metrics` | workload marker/window、workload stdout parser、工程热点分类、virtio-aware counters、`/proc/qperf_metrics`、`perf-compare`、qperf 验收报告 | +| `34d0e92d5` | `feat(qperf): integrate cargo starry profiling workflow` | `cargo starry perf`、`cargo starry run --perf`、默认 qperf 参数、火焰图输出整理、smoke 脚本、集成文档 | +| `d94a25be7` | `feat(qperf): add RISC-V callchain flamegraphs` | qperf raw sample 扩展 PC/SP/FP、RISC-V frame-pointer unwinder、深栈 folded stack、stack depth summary、callchain 文档与验证 | +| `2cfa4e3f5` | `perf(virtio-blk): reduce qperf sync read queue churn` | 基于 qperf 结果实现 virtio-blk direct read fast path、rsext4 readahead、blk A/B 报告和 PNG 火焰图 | + +## 3. 工具链改造成果总览 + +### 3.1 harness / workload window + +主要文件: + +* `tools/starry-syscall-harness/harness.py` +* `tools/starry-syscall-harness/README.md` +* `tools/starry-syscall-harness/mcp_server.py` +* `tools/starry-syscall-harness/ui_server.py` +* `tools/starry-syscall-harness/web/*` + +新增能力: + +* `perf-profile` 支持 `--start-marker`、`--stop-marker`、`--workload-timeout`。 +* guest stdout 出现 marker 后,报告中记录 workload window。 +* 当前采样启停仍主要是 postprocess 层的 timestamp 过滤,报告中明确标注 `method: qperf_raw_elapsed_timestamp_filter`。 +* `report.json` 增加 `window` 字段:`start_marker`、`stop_marker`、`start_time`、`stop_time`、`duration_sec`、`boot_samples_excluded`、`post_window_samples_excluded`、`truncated_by_timeout`、`warnings`。 +* marker 缺失时报告 warning,避免把 boot 成本静默混入 workload 数据面结论。 +* workload 结束后 harness 侧通过 QMP quit / 进程终止机制主动收尾,减少对 guest `poweroff -f` 的依赖。 + +### 3.2 qperf postprocess / 工程归因指标 + +主要文件: + +* `tools/qperf/analyzer/src/main.rs` +* `tools/qperf/src/profiler.rs` +* `tools/starry-syscall-harness/harness.py` + +保留的基础产物: + +* `report.json` +* `report.md` +* `hotspots.csv` +* `hotspot_categories.csv` +* `qperf/stack.folded` +* `qperf/flamegraph.svg` +* `qperf/summary.txt` + +新增能力: + +* 工程热点分类:`virtqueue_add_notify_wait_pop`、`virtqueue_add`、`virtqueue_pop_complete`、`virtio_notify_kick`、`memcpy`、`memmove`、`allocator`、`scheduler_wait_preempt`、`lock_mutex_wait`、`pci_probe_transport`、`net_inflight_btree`、`block_io_path`、`net_rx_tx_path`、`vsock_tx_rx_path`。 +* workload stdout parser: + * 解析 `dd` 的 bytes、elapsed、throughput。 + * 解析 `wget` 的下载状态和可获得的吞吐信息。 + * 解析 `QPERF_METRIC key=value` 自定义指标。 +* 归一化指标: + * `guest_instructions_per_MB` + * `guest_blocks_per_MB` + * `host_elapsed_sec_per_MB` + * `samples_per_MB` + * `category_samples_per_MB` +* host perf: + * 启用 `--host-perf` 时合并 `perf stat`。 + * 未启用时在报告中明确写出“未启用 host perf”。 + +### 3.3 virtio-aware counters + +主要文件: + +* `drivers/ax-driver/Cargo.toml` +* `drivers/ax-driver/src/lib.rs` +* `drivers/ax-driver/src/qperf_metrics.rs` +* `drivers/ax-driver/src/virtio/block.rs` +* `drivers/ax-driver/src/virtio/net.rs` +* `os/StarryOS/kernel/src/pseudofs/proc.rs` +* `os/StarryOS/kernel/Cargo.toml` +* `os/StarryOS/starryos/Cargo.toml` + +新增能力: + +* feature-gated instrumentation:`qperf-metrics` 默认关闭。 +* `/proc/qperf_metrics` 支持: + * `cat /proc/qperf_metrics` 导出 `QPERF_METRIC key=value ...` + * `echo reset > /proc/qperf_metrics` 重置 counters +* virtio-blk counters: + * `virtio_blk_read_requests` + * `virtio_blk_read_bytes` + * `virtio_blk_write_requests` + * `virtio_blk_write_bytes` + * `virtio_blk_direct_read_requests` + * `virtio_blk_direct_read_bytes` +* virtqueue counters: + * `virtqueue_add_count` + * `virtio_notify_kick_count` + * `virtqueue_pop_complete_count` + * `virtqueue_add_notify_wait_pop_count` + * `virtqueue_depth_max` + * `virtqueue_depth_hist_*` +* virtio-net counters: + * `virtio_net_rx_packets` + * `virtio_net_tx_packets` + * `virtio_net_rx_bytes` + * `virtio_net_tx_bytes` + * `virtio_net_rx_copy_within_count` + * `virtio_net_rx_copy_within_bytes` + * `virtio_net_tx_staging_copy_count` + * `virtio_net_tx_staging_copy_bytes` + * `virtio_net_inflight_insert_count` + * `virtio_net_inflight_remove_count` + * `virtio_net_inflight_get_count` + +注意:这些 counters 是 driver-visible 近似统计,不是 virtqueue ring-level 精确硬件统计。 + +### 3.4 A/B compare + +主要文件: + +* `tools/starry-syscall-harness/harness.py` + +命令: + +```bash +python3 tools/starry-syscall-harness/harness.py perf-compare \ + --baseline \ + --candidate \ + --name \ + --output-dir +``` + +输出: + +* `compare.json` +* `compare.md` +* `compare.csv` + +覆盖内容: + +* workload throughput / elapsed +* guest executed instructions / blocks +* host elapsed / user / sys +* hotspot categories +* virtio counters +* copy bytes +* notify/kick count +* queue depth 字段 + +缺失字段显示 `N/A`,不会 crash。 + +### 3.5 `cargo starry perf` / `cargo starry run --perf` + +主要文件: + +* `scripts/axbuild/src/starry/mod.rs` +* `scripts/axbuild/src/starry/perf.rs` +* `scripts/axbuild/src/context/workspace.rs` +* `scripts/axbuild/src/lib.rs` +* `tools/starry-syscall-harness/scripts/qperf-smoke.sh` + +新增命令: + +```bash +cargo starry perf --case boot +``` + +blk 示例: + +```bash +cargo starry perf \ + --case blk-read \ + --qperf-metrics \ + --start-marker QPERF_BEGIN \ + --stop-marker QPERF_END \ + --workload 'echo reset > /proc/qperf_metrics; echo QPERF_BEGIN:blk; dd if=/usr/bin/lto-dump of=/dev/null bs=64k; cat /proc/qperf_metrics; echo QPERF_END:blk' +``` + +`run --perf` 示例: + +```bash +cargo starry run \ + --perf \ + --perf-case blk-read \ + --perf-workload 'echo QPERF_BEGIN:blk; dd if=/usr/bin/lto-dump of=/dev/null bs=64k; echo QPERF_END:blk' \ + --perf-start-marker QPERF_BEGIN \ + --perf-stop-marker QPERF_END \ + --perf-qperf-metrics +``` + +默认输出路径: + +```text +target/qperf//perf//latest/ +``` + +典型产物: + +```text +report.md +report.json +hotspots.csv +hotspot_categories.csv +profile.stdout +profile.stderr +qperf/flamegraph.svg +qperf/flamegraph.workload.svg +qperf/flamegraph.boot.svg +qperf/flamegraph.post.svg +qperf/flamegraph.focus.svg +qperf/stack.folded +qperf/stack-depth-summary.csv +qperf/summary.txt +qperf/resolve.stats.json +``` + +### 3.6 深调用栈火焰图 + +主要文件: + +* `tools/qperf/src/profiler.rs` +* `tools/qperf/src/reg.rs` +* `tools/qperf/analyzer/src/main.rs` +* `scripts/axbuild/src/starry/perf.rs` +* `tools/starry-syscall-harness/harness.py` + +新增能力: + +* qperf raw sample 记录 RISC-V `pc`、`sp`、`fp/s0`。 +* analyzer 支持基于 frame pointer 的 RISC-V kernel callchain 恢复。 +* `--full-stack` 自动启用 debuginfo、force-frame-pointers 和 `--perf-callchain fp`。 +* 支持 `--perf-callchain leaf|fp|logical`。 +* 支持 `--symbol-style full|module|short`。 +* folded stack 默认保留完整 demangled Rust 路径。 +* 新增 `qperf/stack-depth-summary.csv`。 +* 报告中新增 `callchain` 字段:`enabled`、`method`、`samples_with_fp`、`unwind_success`、`unwind_failed`、`avg_depth`、`max_depth`。 + +深栈能力的关键结论: + +* 旧火焰图浅的根因是 qperf 主要记录 guest PC/TB leaf hotspot,没有 callchain。 +* 新版在 `--full-stack` 下可以生成明显纵向展开的调用栈,例如 syscall -> fs -> rsext4 -> ax-driver -> virtio -> virtqueue。 +* 默认模式仍是 `leaf`,避免普通 profile 强制引入 frame pointer / debuginfo 的开销。 + +## 4. virtio-blk 瓶颈定位与优化 + +### 4.1 采样命令 + +baseline: + +```bash +cargo starry perf \ + --case blk-baseline \ + --output-dir target/qperf-virtio-blk-opt/baseline \ + --full-stack \ + --qperf-metrics \ + --host-time \ + --timeout 240 \ + --workload-timeout 160 \ + --start-marker QPERF_BEGIN \ + --stop-marker QPERF_END \ + --shell-init-cmd 'echo reset > /proc/qperf_metrics; echo QPERF_BEGIN:blk; dd if=/usr/bin/lto-dump of=/dev/null bs=64k; cat /proc/qperf_metrics; echo QPERF_END:blk' \ + --no-truncate +``` + +candidate: + +```bash +cargo starry perf \ + --case blk-direct-readahead \ + --output-dir target/qperf-virtio-blk-opt/candidate-readahead \ + --full-stack \ + --qperf-metrics \ + --host-time \ + --timeout 240 \ + --workload-timeout 160 \ + --start-marker QPERF_BEGIN \ + --stop-marker QPERF_END \ + --shell-init-cmd 'echo reset > /proc/qperf_metrics; echo QPERF_BEGIN:blk; dd if=/usr/bin/lto-dump of=/dev/null bs=64k; cat /proc/qperf_metrics; echo QPERF_END:blk' \ + --no-truncate +``` + +compare: + +```bash +python3 tools/starry-syscall-harness/harness.py perf-compare \ + --baseline target/qperf-virtio-blk-opt/baseline/perf/riscv64/latest/report.json \ + --candidate target/qperf-virtio-blk-opt/candidate-readahead/perf/riscv64/latest/report.json \ + --name blk-readahead \ + --output-dir target/qperf-virtio-blk-opt/compare-readahead +``` + +### 4.2 baseline 结论 + +baseline 报告: + +* `target/qperf-virtio-blk-opt/baseline/perf/riscv64/latest/report.json` +* `target/qperf-virtio-blk-opt/baseline/perf/riscv64/latest/report.md` +* `target/qperf-virtio-blk-opt/baseline/perf/riscv64/latest/qperf/flamegraph.svg` +* `target/qperf-virtio-blk-opt/baseline/perf/riscv64/latest/qperf/stack.folded` +* `target/qperf-virtio-blk-opt/baseline/perf/riscv64/latest/qperf/stack-depth-summary.csv` + +关键数据: + +| 指标 | baseline | +| --- | ---: | +| dd bytes | 53,601,104 | +| dd elapsed | 6.367021 s | +| throughput | 8,418,553 B/s | +| marker window | 6.529766005 s | +| samples | 642 | +| callchain avg symbol depth | 43.306853583 | +| raw max depth | 16 | +| virtio_blk_read_requests | 13,629 | +| virtio_blk_read_bytes | 55,813,632 | +| virtqueue_add_count | 14,417 | +| virtio_notify_kick_count | 14,417 | +| virtqueue_add_notify_wait_pop_count | 14,354 | +| virtqueue_pop_complete_count | 14,354 | + +baseline 工程热点: + +| category | percent | +| --- | ---: | +| block_io_path | 75.8567% | +| virtio_notify_kick | 32.8660% | +| virtqueue_add_notify_wait_pop | 31.9315% | +| memcpy | 28.1931% | +| lock_mutex_wait | 10.5919% | + +qperf 识别出的核心瓶颈: + +* 53.6 MB 顺序读触发 13,629 次 blk read request,平均每次约 4 KiB。 +* 每个小 read 基本都走一次同步 `VirtQueue::add_notify_wait_pop`。 +* `virtio_notify_kick_count` 和 `virtqueue_add_notify_wait_pop_count` 与 request 数同量级。 +* 深栈火焰图确认路径是:sys_read -> axfs/rsext4 -> ax-driver block -> rd-block -> virtio-blk -> virtqueue。 + +### 4.3 优化实现 + +最终优化涉及文件: + +* `components/rsext4/src/cache/data_block.rs` +* `drivers/interface/rdif-block/src/lib.rs` +* `drivers/blk/rd-block/src/lib.rs` +* `drivers/ax-driver/src/block/binding.rs` +* `drivers/ax-driver/src/virtio/block.rs` +* `drivers/ax-driver/src/qperf_metrics.rs` + +实现内容: + +1. `rdif_block::IQueue` 增加默认 `read_blocks_direct()`,默认返回 `BlkError::NotSupported`,保证旧 driver 兼容。 +2. `rd_block::CmdQueue` 增加 `read_blocks_direct()` 转发。 +3. `ax_driver::block::Block::read_block()` 优先尝试 direct read,只有 `NotSupported` 时回退原路径。 +4. `ax_driver::virtio::block::BlockQueue` 实现 direct read: + * 只在目标 buffer 物理连续时启用。 + * 使用 `axklib::mem::virt_to_phys` 检查 4 KiB 页物理连续性。 + * 调用 `VirtIOBlk::read_blocks()` 直接 DMA 到目标 buffer。 +5. `drivers/ax-driver/src/qperf_metrics.rs` 增加 direct read counters。 +6. `rsext4::cache::data_block::DataBlockCache` 在 miss 时做最多 8 个连续 data block 的 readahead: + * 使用 `Jbd2Dev::read_blocks()` 批量读取。 + * 拆成 `CachedBlock` 插入 cache。 + * 遇到已缓存 block 提前停止。 + * 遵守 cache 容量与 LRU 驱逐。 + +direct-only 曾作为尝试,但 A/B 显示退化: + +| 指标 | baseline | direct-only | +| --- | ---: | ---: | +| throughput | 8,418,553 B/s | 6,889,660 B/s | +| workload elapsed | 6.367021 s | 7.779933 s | +| `virtqueue_add_notify_wait_pop_count` | 14,354 | 14,354 | + +结论:direct-only 没有减少同步 virtqueue 次数,因此不是有效优化;最终有效的是 readahead 降低同步小 I/O 数量。 + +### 4.4 A/B 结果 + +最终 compare: + +* `target/qperf-virtio-blk-opt/compare-readahead/perf-compare/blk-readahead/compare.md` +* `target/qperf-virtio-blk-opt/compare-readahead/perf-compare/blk-readahead/compare.csv` +* `target/qperf-virtio-blk-opt/compare-readahead/perf-compare/blk-readahead/compare.json` + +compare 结论:`明显改善`。 + +| 指标 | baseline | candidate | 变化 | +| --- | ---: | ---: | ---: | +| throughput_bytes_per_second | 8,418,553 | 10,551,346 | +25.3344% | +| workload elapsed | 6.367021 s | 5.080025 s | -20.2135% | +| samples.total_samples | 642 | 528 | -17.7570% | +| virtio_blk_read_requests | 13,629 | 2,111 | -84.5110% | +| virtio_notify_kick_count | 14,417 | 2,899 | -79.8918% | +| virtqueue_add_count | 14,417 | 2,899 | -79.8918% | +| virtqueue_add_notify_wait_pop_count | 14,354 | 2,836 | -80.2424% | +| virtqueue_pop_complete_count | 14,354 | 2,836 | -80.2424% | + +hotspot category 对比: + +| category | baseline | candidate | delta | +| --- | ---: | ---: | ---: | +| virtio_notify_kick | 32.8660% | 14.2045% | -18.6615 pp | +| virtqueue_add_notify_wait_pop | 31.9315% | 13.4470% | -18.4845 pp | +| block_io_path | 75.8567% | 66.2879% | -9.5688 pp | +| memcpy | 28.1931% | 31.0606% | +2.8675 pp | +| lock_mutex_wait | 10.5919% | 10.4167% | -0.1752 pp | + +candidate 报告: + +* `target/qperf-virtio-blk-opt/candidate-readahead/perf/riscv64/latest/report.json` +* `target/qperf-virtio-blk-opt/candidate-readahead/perf/riscv64/latest/report.md` +* `target/qperf-virtio-blk-opt/candidate-readahead/perf/riscv64/latest/qperf/flamegraph.svg` +* `target/qperf-virtio-blk-opt/candidate-readahead/perf/riscv64/latest/qperf/stack.folded` +* `target/qperf-virtio-blk-opt/candidate-readahead/perf/riscv64/latest/qperf/stack-depth-summary.csv` + +注意:candidate `report.json` 的 `result` 是 `incomplete`,原因是 stop marker 后 QEMU 收尾阶段被 SIGKILL。marker window、stdout、counters、folded stack、flamegraph、compare 都已生成;因此本结论只使用 workload marker 内的 dd 和 qperf counters/category 数据,不使用该次 host elapsed 作为严肃指标。 + +## 5. 图片与 PPT 素材 + +可直接用于报告或 PPT 的图片: + +| 图片 | 用途 | +| --- | --- | +| `docs/flamegraphs/qperf-virtio-blk-baseline-fullstack.png` | baseline 深栈火焰图,展示 sys_read -> rsext4 -> ax-driver -> virtio queue | +| `docs/flamegraphs/qperf-virtio-blk-readahead-fullstack.png` | readahead candidate 深栈火焰图,展示 load_readahead/read_blocks_direct 路径 | +| `docs/flamegraphs/qperf-host-rerun-blk-workload.png` | 早期 host rerun blk workload 火焰图 | +| `docs/flamegraphs/qperf-host-rerun-net-workload.png` | 早期 host rerun net workload 火焰图 | +| `docs/flamegraphs/qperf-long-chain-real.virtio-blk-patched.flamegraph.svg` | 深栈火焰图能力展示 | +| `docs/flamegraphs/qperf-long-chain-demo.synthetic.flamegraph.svg` | synthetic long-chain demo 展示 | + +最终优化报告已内嵌 PNG: + +* `docs/qperf-virtio-blk-deepstack-optimization-report.md` + +如需要重新从 SVG 生成 PNG,可使用: + +```bash +convert -background white \ + target/qperf-virtio-blk-opt/baseline/perf/riscv64/latest/qperf/flamegraph.svg \ + docs/flamegraphs/qperf-virtio-blk-baseline-fullstack.png + +convert -background white \ + target/qperf-virtio-blk-opt/candidate-readahead/perf/riscv64/latest/qperf/flamegraph.svg \ + docs/flamegraphs/qperf-virtio-blk-readahead-fullstack.png +``` + +## 6. 主要文档索引 + +建议后续总结报告优先阅读: + +| 文档 | 内容 | +| --- | --- | +| `docs/qperf-tooling-redesign.md` | 工具改造设计 | +| `docs/qperf-marker-and-metrics-usage.md` | marker/window 和 metrics 使用 | +| `docs/qperf-tooling-validation-report.md` | qperf 工具改造验收 | +| `docs/qperf-cargo-starry-integration.md` | `cargo starry perf` 使用指南 | +| `docs/qperf-cargo-starry-integration-report.md` | cargo 集成报告 | +| `docs/qperf-flamegraph-guide.md` | 火焰图阅读与参数指南 | +| `docs/qperf-callchain-flamegraph-design.md` | 深调用栈设计 | +| `docs/qperf-callchain-validation-report.md` | 深调用栈验证报告 | +| `docs/qperf-host-rerun-virtio-bottleneck-report.md` | host QEMU rerun 后的 virtio 瓶颈分析 | +| `docs/qperf-current-blk-bottleneck-analysis.md` | blk 当前瓶颈分析 | +| `docs/qperf-virtio-blk-deepstack-optimization-report.md` | 本轮 virtio-blk 深栈采样与优化最终报告 | + +## 7. 已运行验证 + +工具链和优化相关验证包括: + +```bash +cargo fmt +cargo clippy -p rdif-block -- -D warnings +cargo clippy -p rd-block -- -D warnings +cargo clippy -p rsext4 -- -D warnings +cargo clippy -p ax-driver --no-default-features --features 'plat-dyn,virtio-blk,virtio-net,virtio-socket,qperf-metrics' -- -D warnings +git diff --check +``` + +qperf 实验验证包括: + +```bash +cargo starry perf --case blk-baseline ... +cargo starry perf --case blk-direct-readahead ... +python3 tools/starry-syscall-harness/harness.py perf-compare ... +``` + +详细命令见: + +* `docs/qperf-virtio-blk-deepstack-optimization-report.md` +* `docs/qperf-callchain-validation-report.md` +* `docs/qperf-cargo-starry-integration-report.md` + +## 8. PPT 叙事建议 + +建议 PPT 按 8 页左右展开: + +| 页码 | 标题 | 关键内容 | 推荐素材 | +| --- | --- | --- | --- | +| 1 | 背景:为什么 qperf 要改造 | 原 qperf 从 boot 开始采样、只有 leaf hotspot、无法回答 virtqueue/copy/counter 问题 | `docs/qperf-virtio-drivers-performance-report.md` | +| 2 | 工具链改造总览 | marker/window、工程分类、virtio counters、A/B compare、cargo starry 集成、深栈火焰图 | 本文第 3 节 | +| 3 | 一条命令生成报告 | `cargo starry perf` 和 `cargo starry run --perf` 使用方式、输出文件 | `docs/qperf-cargo-starry-integration.md` | +| 4 | 深栈火焰图能力 | leaf-only 到 frame-pointer callchain,stack depth summary | `docs/flamegraphs/qperf-virtio-blk-baseline-fullstack.png` | +| 5 | virtio-blk baseline 瓶颈 | 13,629 次 4KiB read、14,354 次 `add_notify_wait_pop`、notify/kick 高占比 | baseline 表格和火焰图 | +| 6 | 优化方案 | direct-only 退化,最终采用 rsext4 readahead 减少同步小 I/O | 本文第 4.3 节 | +| 7 | A/B 结果 | throughput +25.33%,read request -84.51%,add_notify_wait_pop -80.24% | compare 表格 | +| 8 | 局限与下一步 | runtime pause/resume、ring-level counters、net/vsock、真正异步 blk queue | 本文第 9/10 节 | + +一句话结论可写为: + +> 本轮把 qperf 从 leaf hotspot 采样器升级为可由 `cargo starry perf` 一键运行、支持 workload window、virtio counters、工程分类、A/B compare 和 RISC-V 深调用栈火焰图的 StarryOS 性能工具链,并用它定位到 virtio-blk 同步小 I/O 瓶颈,通过 rsext4 readahead 将 blk 顺序读吞吐提升约 25%。 + +## 9. 局限性 + +必须在正式报告中如实说明: + +* workload window 当前主要是 postprocess timestamp 过滤,不是真正 QEMU plugin runtime pause/resume。 +* `qperf-metrics` counters 是 driver-visible 近似统计,不是 virtqueue ring-level 精确统计。 +* 深调用栈依赖 `--full-stack`、debuginfo 和 frame pointer;默认 `leaf` 模式仍不会生成深栈。 +* frame-pointer unwinder 主要覆盖 kernel 栈;trap/syscall/task switch 边界仍可能导致 partial unwind。 +* candidate readahead run 的 `report.json` 标为 `incomplete`,原因是 stop marker 后 QEMU shutdown 被 SIGKILL;该次 host elapsed 不应作为严肃对比指标。 +* host perf/PMU 是可选项,未启用时只依赖 qperf guest sampling 和 workload stdout/counters。 +* vsock 在当前环境可能受 `/dev/vhost-vsock` 缺失阻塞,不能做定量结论。 +* net 路径已有 counters 和报告基础,但还没有在本轮实现 net RX/TX 优化补丁。 + +## 10. 下一步建议 + +基于当前工具链,后续建议按以下顺序推进: + +1. virtio-net RX 去 `copy_within()` A/B: + * 使用 `virtio_net_rx_copy_within_count/bytes` 验证 copy 是否下降。 + * 观察 `memcpy/memmove`、`net_rx_tx_path`、吞吐变化。 +2. virtio-net inflight `BTreeMap` 替换: + * 对比 `virtio_net_inflight_insert/remove/get_count` 与 `net_inflight_btree` category。 + * 尝试固定数组或 slab。 +3. virtio-blk pending read / async queue 原型: + * 当前 readahead 降低了同步小 I/O 次数,但没有真正利用 virtqueue queue depth。 + * 下一步应实现 `read_blocks_nb()` / `complete_read_blocks()` 或 pending-read API,用 qperf 验证 `add_notify_wait_pop` 是否继续下降。 +4. ring-level virtqueue counters: + * 将 counters 从 driver-visible 近似下沉到 `virtio-drivers` ring 操作层。 + * 增加更精确的 queue depth avg/histogram、available/used ring 统计。 +5. runtime sampling pause/resume: + * 当前 window 后处理能避免报告污染,但 raw sample 仍包含 boot/post。 + * 后续可在 QEMU plugin 或 harness/QMP 层实现真正运行时启停采样。 +6. vsock 补测: + * 在具备 `/dev/vhost-vsock` 的 Linux host 上补跑 vsock workload。 + * 不具备环境时报告只能写阻塞原因,不能编造数据。 + +## 11. 后续 agent 快速入口 + +查看最终优化报告: + +```bash +sed -n '1,260p' docs/qperf-virtio-blk-deepstack-optimization-report.md +``` + +查看 A/B compare: + +```bash +sed -n '1,220p' target/qperf-virtio-blk-opt/compare-readahead/perf-compare/blk-readahead/compare.md +``` + +查看 stack depth: + +```bash +cat target/qperf-virtio-blk-opt/baseline/perf/riscv64/latest/qperf/stack-depth-summary.csv +cat target/qperf-virtio-blk-opt/candidate-readahead/perf/riscv64/latest/qperf/stack-depth-summary.csv +``` + +检查 folded stack 是否有纵向展开: + +```bash +awk -F';' '{print NF}' target/qperf-virtio-blk-opt/baseline/perf/riscv64/latest/qperf/stack.folded | sort -n | uniq -c +``` + +重跑 blk profile: + +```bash +cargo starry perf \ + --case blk-rerun \ + --output-dir target/qperf-virtio-blk-rerun \ + --full-stack \ + --qperf-metrics \ + --host-time \ + --timeout 240 \ + --workload-timeout 160 \ + --start-marker QPERF_BEGIN \ + --stop-marker QPERF_END \ + --shell-init-cmd 'echo reset > /proc/qperf_metrics; echo QPERF_BEGIN:blk; dd if=/usr/bin/lto-dump of=/dev/null bs=64k; cat /proc/qperf_metrics; echo QPERF_END:blk' \ + --no-truncate +``` + +## 12. 最终交付物清单 + +代码能力: + +* qperf marker/window 支持。 +* qperf 工程热点分类和 workload metric parser。 +* qperf virtio-aware counters 与 `/proc/qperf_metrics`。 +* qperf A/B compare。 +* `cargo starry perf` 和 `cargo starry run --perf`。 +* RISC-V frame-pointer deep callchain flamegraph。 +* virtio-blk direct read fast path。 +* rsext4 data block readahead。 + +文档: + +* `docs/qperf-tooling-redesign.md` +* `docs/qperf-marker-and-metrics-usage.md` +* `docs/qperf-tooling-improvement-report.md` +* `docs/qperf-tooling-validation-report.md` +* `docs/qperf-cargo-starry-integration.md` +* `docs/qperf-cargo-starry-integration-report.md` +* `docs/qperf-flamegraph-guide.md` +* `docs/qperf-callchain-flamegraph-design.md` +* `docs/qperf-callchain-validation-report.md` +* `docs/qperf-host-rerun-virtio-bottleneck-report.md` +* `docs/qperf-current-blk-bottleneck-analysis.md` +* `docs/qperf-virtio-blk-deepstack-optimization-report.md` +* `docs/qperf-work-handoff.md` + +图片: + +* `docs/flamegraphs/qperf-virtio-blk-baseline-fullstack.png` +* `docs/flamegraphs/qperf-virtio-blk-readahead-fullstack.png` +* `docs/flamegraphs/qperf-host-rerun-blk-focus.png` +* `docs/flamegraphs/qperf-host-rerun-blk-workload.png` +* `docs/flamegraphs/qperf-host-rerun-net-workload.png` +* `docs/flamegraphs/qperf-long-chain-real.virtio-blk-patched.flamegraph.svg` +* `docs/flamegraphs/qperf-long-chain-demo.synthetic.flamegraph.svg` + +实验产物: + +* `target/qperf-virtio-blk-opt/baseline/perf/riscv64/latest/` +* `target/qperf-virtio-blk-opt/candidate-readahead/perf/riscv64/latest/` +* `target/qperf-virtio-blk-opt/compare-readahead/perf-compare/blk-readahead/` + diff --git a/docs/starry-syscall-harness.md b/docs/starry-syscall-harness.md new file mode 100644 index 0000000000..f8967edebe --- /dev/null +++ b/docs/starry-syscall-harness.md @@ -0,0 +1,142 @@ +# StarryOS Syscall And Performance Harness + +This harness compares small syscall probes on Linux and StarryOS, and runs qperf-based StarryOS performance profiles with structured hotspot reports. + +## Usage + +Run from the repository root: + +```bash +python3 tools/starry-syscall-harness/harness.py doctor +python3 tools/starry-syscall-harness/harness.py discover --arch riscv64 +python3 tools/starry-syscall-harness/harness.py perf-profile --arch riscv64 --timeout 20 +``` + +The harness re-enters Docker for StarryOS work by default. It uses: + +```text +ghcr.io/rcore-os/tgoskits-container:latest +``` + +Artifacts are written under: + +```text +target/starry-syscall-harness//latest/ +``` + +The main report is `report.json`. + +Performance artifacts are written under: + +```text +target/starry-syscall-harness/perf//latest/ +``` + +Important files: + +```text +report.json +report.md +hotspots.csv +qperf/stack.folded +qperf/flamegraph.svg +qperf/summary.txt +qperf/qperf.summary.txt +qperf/qemu.time.txt +qperf/qemu.perf.csv +``` + +qperf profiling defaults to a release StarryOS build so the hotspot data is +closer to optimized runtime behavior. Pass `--debug` only when the additional +debug information is needed for symbol investigation. + +By default, qperf samples all translated guest code and maps known StarryOS +kernel physical aliases back to ELF virtual addresses before analysis. Pass +`--kernel-filter` to discard samples outside the detected kernel `.text` range. + +Use `perf-diff` to compare two folded stacks or profile directories: + +```bash +python3 tools/starry-syscall-harness/harness.py perf-diff \ + --baseline target/starry-syscall-harness/perf/riscv64/baseline \ + --compare target/starry-syscall-harness/perf/riscv64/latest +``` + +The performance report includes rule-based fix candidates for common VirtIO and lock/copy hotspots. These candidates are intentionally triage-oriented: inspect the referenced files and validate with a new qperf run before treating a change as an optimization. + +## qperf Principle And Metric Scope + +qperf is implemented as a QEMU TCG plugin under `tools/qperf`. It samples guest +PCs and frame-pointer stacks from QEMU translation-block or instruction +callbacks, then `qperf-analyzer` resolves the guest addresses against the +StarryOS kernel ELF. This answers where the guest kernel is executing; it is not +the same as host `perf` on the QEMU process. + +The plugin emits a `qperf.summary.txt` file with sampling health and guest +execution counters: + +```text +samples +dropped_samples +sample_failures +translated_blocks +translated_instructions +executed_blocks +executed_instructions +execute_callbacks +``` + +In `tb` mode, `executed_instructions` is computed as guest instructions in the +translated block multiplied by block executions. In `insn` mode, instruction +callbacks count executed guest instructions directly. These are QEMU guest +instruction counters for the instrumented scope, not hardware retired +instructions. + +The current QEMU plugin API does not expose precise guest hardware cycles or +guest cache misses. For that reason, `--host-perf` is explicitly host-scoped: +it measures the host QEMU process, TCG, device emulation, and qperf overhead. +If `perf` is unavailable in the Docker image or the host denies access, the +report records the error instead of inventing counter values. + +`--host-time` is always independent of GNU `time`: `cargo xtask starry perf` +records wall time with `Instant` and user/system CPU time with +`getrusage(RUSAGE_CHILDREN)` around the QEMU wrapper. + +## Performance CLI Details + +The harness entrypoint forwards the following qperf controls: + +```bash +python3 tools/starry-syscall-harness/harness.py perf-profile \ + --arch riscv64 \ + --timeout 20 \ + --format folded \ + --freq 99 \ + --max-depth 64 \ + --mode tb \ + --top 20 \ + --host-time \ + --host-perf \ + --host-perf-events task-clock,cycles,instructions,cache-references,cache-misses \ + --shell-init-cmd 'echo workload; sleep 1' \ + --shell-prefix 'root@starry:' \ + --qemu-arg=-m \ + --qemu-arg=768M +``` + +Use `--shell-init-cmd` to profile a real guest workload instead of only boot. +Use repeated `--qemu-arg` entries for raw QEMU arguments; values beginning with +`-` should use the `--qemu-arg=-device` form. + +The browser UI exposes the same performance controls and renders summary, +guest-counter, host-time, and host-perf metric groups from `report.json`. + +## Codex MCP + +Register the MCP server locally: + +```bash +codex mcp add starry-syscall-harness -- python3 /path/to/tgoskits/tools/starry-syscall-harness/mcp_server.py --repo /path/to/tgoskits +``` + +The MCP tools expose `doctor`, `discover`, `perf-profile`, and `perf-diff` flows. diff --git a/docs/starryos-local-run-and-qperf-guide.md b/docs/starryos-local-run-and-qperf-guide.md new file mode 100644 index 0000000000..ea1607dd72 --- /dev/null +++ b/docs/starryos-local-run-and-qperf-guide.md @@ -0,0 +1,607 @@ +# 本机启动 StarryOS 与 qperf 的步骤指南 + +本文说明如何在本机工作区一步步启动 StarryOS、运行 qperf 性能采样、查看报告和火焰图。这里的“本机”指你在宿主机上的 tgoskits 仓库目录发起操作;所有 StarryOS 构建、rootfs、QEMU 和 qperf profile 都应放在 Docker 容器中执行。 + +默认镜像: + +```text +ghcr.io/rcore-os/tgoskits-container:latest +``` + +推荐工作目录: + +```bash +cd /home/cg24/tgoskits +``` + +## 1. 基本原则 + +不要在宿主机直接跑 StarryOS/QEMU/qperf。原因有三点: + +1. 工具链、交叉编译器、QEMU 版本和 rootfs 工具都已经在项目容器里配好。 +2. 直接在宿主机跑会污染本地 cargo cache、target 和 rootfs 产物,权限也容易变乱。 +3. harness 和 PR 验证都默认 StarryOS 相关流程在 Docker 内完成。 + +宿主机可以做这些事: + +- 调用 `harness.py`,让它自动 re-enter Docker。 +- 启动本地 Web UI。 +- 打开报告、Markdown、CSV、SVG。 +- 读写源码和文档。 + +容器内做这些事: + +- `cargo xtask starry defconfig` +- `cargo xtask starry rootfs` +- `cargo xtask starry qemu` +- `cargo xtask starry perf` +- StarryOS 相关测试和 clippy。 + +## 2. 一次性检查环境 + +先确认 Docker 可用,并且镜像能拉到: + +```bash +docker pull ghcr.io/rcore-os/tgoskits-container:latest +``` + +再从宿主机跑 harness doctor: + +```bash +python3 tools/starry-syscall-harness/harness.py doctor +``` + +`doctor` 会检查 Docker、镜像、容器内 Python/Cargo/QEMU 等基础工具。这个命令本身可以在宿主机运行;harness 会负责进入 Docker。 + +## 3. 推荐方式:用 harness 跑 qperf + +如果目标是拿 StarryOS 性能报告和 flamegraph,优先用 harness: + +```bash +python3 tools/starry-syscall-harness/harness.py perf-profile \ + --arch riscv64 \ + --timeout 20 \ + --format all \ + --freq 99 \ + --max-depth 64 \ + --mode tb \ + --top 20 \ + --min-percent 5.0 +``` + +这条命令会自动做这些事: + +1. 在 Docker 中执行 StarryOS/qperf 流程。 +2. 刷新 `qemu-riscv64` defconfig。 +3. 构建 qperf plugin 和 qperf analyzer。 +4. 构建 StarryOS release kernel。 +5. 准备 rootfs。 +6. 启动 QEMU 并注入 qperf plugin。 +7. 收集 `qperf.bin` raw samples。 +8. 解析 folded stack。 +9. 生成 flamegraph。 +10. 写出 JSON/Markdown/CSV 报告。 + +输出目录固定在: + +```text +target/starry-syscall-harness/perf/riscv64/latest/ +``` + +重点文件: + +```text +target/starry-syscall-harness/perf/riscv64/latest/report.json +target/starry-syscall-harness/perf/riscv64/latest/report.md +target/starry-syscall-harness/perf/riscv64/latest/hotspots.csv +target/starry-syscall-harness/perf/riscv64/latest/qperf/stack.folded +target/starry-syscall-harness/perf/riscv64/latest/qperf/flamegraph.svg +target/starry-syscall-harness/perf/riscv64/latest/profile.stderr +``` + +如果命令结束时看到类似: + +```text +result: ok +samples: +``` + +说明至少采到了有效样本。 + +## 4. 启动本地 Web UI 查看报告 + +如果想在浏览器里点按钮、看报告和火焰图,可以启动本地 UI: + +```bash +python3 tools/starry-syscall-harness/harness.py ui \ + --host 127.0.0.1 \ + --port 8765 \ + --open +``` + +浏览器地址: + +```text +http://127.0.0.1:8765 +``` + +UI 支持: + +- Doctor 检查; +- syscall scan; +- qperf profile; +- perf diff; +- 查看 `report.json` / `report.md`; +- 查看 `flamegraph.svg`。 + +注意:UI 只是交互入口。真正的 StarryOS/QEMU/qperf 仍然由 harness 放进 Docker 执行。 + +## 5. 手动进入 Docker shell + +如果你想一步步看 StarryOS 怎么起,建议开一个交互式 Docker shell: + +```bash +cd /home/cg24/tgoskits + +docker run --rm -it \ + -v "$PWD":/work \ + -w /work \ + -e HOST_UID="$(id -u)" \ + -e HOST_GID="$(id -g)" \ + ghcr.io/rcore-os/tgoskits-container:latest \ + bash +``` + +进入容器后,工作目录是: + +```bash +/work +``` + +后续本节命令都在容器内执行。 + +退出容器前建议修正产物属主,避免宿主机看到 root-owned 文件: + +```bash +chown -R "$HOST_UID:$HOST_GID" target tmp tools/qperf/target 2>/dev/null || true +exit +``` + +如果你用 harness 自动跑,它会自己处理常见产物目录的属主问题。 + +## 6. 手动准备 StarryOS QEMU 配置 + +在容器内先生成 QEMU defconfig: + +```bash +cargo xtask starry defconfig qemu-riscv64 +``` + +这个命令会生成或刷新 StarryOS 的临时构建配置。建议每次 rebase、切换分支、平台配置变动后都先跑一次,避免复用旧的 `tmp/axbuild` 配置。 + +可查看支持的 StarryOS 平台: + +```bash +cargo xtask starry config ls +``` + +也可以看 quick-start 支持项: + +```bash +cargo xtask starry quick-start list +``` + +## 7. 手动准备 rootfs + +在容器内准备 riscv64 rootfs: + +```bash +cargo xtask starry rootfs --arch riscv64 +``` + +成功后会看到类似: + +```text +rootfs ready at /work/tmp/axbuild/rootfs/rootfs-riscv64-alpine.img +``` + +这个 rootfs 是 QEMU 启动 StarryOS 用户态环境的磁盘镜像。`starry qemu` 和 `starry perf` 通常会自动确保 rootfs 存在,但手动拆步骤时先跑一遍更清楚。 + +## 8. 手动构建 StarryOS + +release 构建: + +```bash +cargo xtask starry build --arch riscv64 +``` + +debug 构建: + +```bash +cargo xtask starry build --arch riscv64 --debug +``` + +性能分析默认使用 release。debug 更适合查符号和栈形态,但不适合做最终性能结论。 + +构建产物通常在: + +```text +target/riscv64gc-unknown-none-elf/release/starryos +target/riscv64gc-unknown-none-elf/release/starryos.bin +``` + +## 9. 手动启动 StarryOS QEMU + +最直接的启动命令: + +```bash +cargo xtask starry qemu --arch riscv64 +``` + +这个命令会: + +1. 读取 StarryOS build config。 +2. 确保 rootfs 可用。 +3. patch QEMU args,把 rootfs 挂到虚拟磁盘。 +4. 构建 kernel。 +5. 启动 QEMU。 + +成功进入 guest 后,通常能看到 StarryOS shell,例如: + +```text +root@starry:/root # +``` + +可以在 guest 里试: + +```sh +pwd +ls / +cat /proc/cpuinfo +``` + +退出方式: + +```sh +poweroff +``` + +如果 guest 没正常关机,可以用 QEMU 的 nographic 退出键: + +```text +Ctrl-A X +``` + +也就是先按 `Ctrl-A`,再按 `x`。 + +## 10. quick-start 启动 StarryOS + +也可以用 quick-start,适合只想快速起机: + +```bash +cargo xtask starry quick-start qemu-riscv64 build +cargo xtask starry quick-start qemu-riscv64 run +``` + +quick-start 会选择对应平台模板,并把常见步骤串起来。手动排查 qperf 时,我更推荐显式跑: + +```bash +cargo xtask starry defconfig qemu-riscv64 +cargo xtask starry rootfs --arch riscv64 +cargo xtask starry qemu --arch riscv64 +``` + +这样每一步失败点更清楚。 + +## 11. 手动运行 qperf + +如果不用 harness,也可以在容器内直接调用 `cargo xtask starry perf`: + +```bash +cargo xtask starry perf \ + --arch riscv64 \ + --timeout 20 \ + --format all \ + --freq 99 \ + --max-depth 64 \ + --mode tb \ + --top 20 \ + --out target/qperf/manual-riscv64 +``` + +这个命令会自动: + +- 构建 qperf plugin:`tools/qperf/target/release/libqperf.so`; +- 构建 analyzer:`tools/qperf/target/release/qperf-analyzer`; +- 如果 `--format all` 或 `--format svg`,启用 analyzer 的 `flamegraph` feature; +- 构建 StarryOS; +- 准备 rootfs; +- 生成 qperf 专用 QEMU config; +- 启动 QEMU,并通过 `-plugin` 注入 qperf; +- 用 analyzer 解析 raw samples。 + +手动 qperf 输出目录: + +```text +target/qperf/manual-riscv64/ +``` + +关键文件: + +```text +target/qperf/manual-riscv64/qperf.bin +target/qperf/manual-riscv64/qperf.summary.txt +target/qperf/manual-riscv64/summary.txt +target/qperf/manual-riscv64/stack.folded +target/qperf/manual-riscv64/flamegraph.svg +target/qperf/manual-riscv64/qemu.toml +``` + +如果只想要 folded stack,不要 SVG: + +```bash +cargo xtask starry perf \ + --arch riscv64 \ + --timeout 20 \ + --format folded \ + --freq 99 \ + --max-depth 64 \ + --mode tb \ + --top 20 \ + --out target/qperf/manual-riscv64-folded +``` + +如果要更细粒度但更慢的 instruction callback: + +```bash +cargo xtask starry perf \ + --arch riscv64 \ + --timeout 10 \ + --format all \ + --freq 101 \ + --max-depth 64 \ + --mode insn \ + --top 20 \ + --out target/qperf/manual-riscv64-insn +``` + +## 12. 打开 flamegraph + +如果是在宿主机上看,可以直接打开: + +```text +target/starry-syscall-harness/perf/riscv64/latest/qperf/flamegraph.svg +``` + +或者手动 qperf 的: + +```text +target/qperf/manual-riscv64/flamegraph.svg +``` + +推荐用浏览器打开。当前 flamegraph 生成参数已经调宽,适合横向滚动查看。 + +如果想通过 UI 看: + +```bash +python3 tools/starry-syscall-harness/harness.py ui \ + --host 127.0.0.1 \ + --port 8765 \ + --open +``` + +然后进入 Performance 页面查看 latest profile。 + +## 13. 比较两次 qperf 结果 + +先保存 baseline: + +```bash +cp -a target/starry-syscall-harness/perf/riscv64/latest \ + target/starry-syscall-harness/perf/riscv64/baseline +``` + +修改代码后重新跑: + +```bash +python3 tools/starry-syscall-harness/harness.py perf-profile \ + --arch riscv64 \ + --timeout 20 \ + --format all \ + --freq 99 \ + --max-depth 64 \ + --mode tb \ + --top 20 +``` + +比较: + +```bash +python3 tools/starry-syscall-harness/harness.py perf-diff \ + --baseline target/starry-syscall-harness/perf/riscv64/baseline \ + --compare target/starry-syscall-harness/perf/riscv64/latest \ + --top 20 +``` + +`perf-diff` 比的是 folded stack 的样本占比变化。它能告诉你热点是否真的下降,但不能代替代码审查。看到下降后还要检查: + +- 样本总数是否足够; +- `dropped_samples` 是否异常; +- workload 是否一致; +- release/debug 配置是否一致; +- 是否只是采样噪声。 + +## 14. 常见问题 + +### 没有 flamegraph.svg + +先看: + +```bash +cat target/starry-syscall-harness/perf/riscv64/latest/qperf/summary.txt +``` + +重点检查: + +```text +flamegraph_generated = true +``` + +如果是 false 或文件不存在,常见原因是 analyzer 没启用 `flamegraph` feature。通过 harness 或 `cargo xtask starry perf --format all` 跑会自动处理。 + +### samples 是 0 + +看: + +```bash +cat target/starry-syscall-harness/perf/riscv64/latest/profile.stderr +cat target/starry-syscall-harness/perf/riscv64/latest/qperf/summary.txt +``` + +常见原因: + +- QEMU 在 plugin 写样本前就退出; +- timeout 太短; +- kernel filter 过滤过严; +- 地址 alias 没映射上; +- StarryOS 没成功进入预期 workload。 + +可以先把 timeout 拉长: + +```bash +python3 tools/starry-syscall-harness/harness.py perf-profile \ + --arch riscv64 \ + --timeout 60 \ + --format all +``` + +### top function 是裸地址 + +例如: + +```text +0x800065ae +_start+0x1000 +``` + +通常是符号解析或地址 canonicalization 问题。检查 `profile.stderr` 中是否有: + +```text +qperf: detected kernel .text virtual range +qperf: detected kernel .text physical alias +``` + +如果没有,说明 kernel ELF 或 axconfig 没被正确找到。 + +### QEMU 配置突然坏了 + +切分支或 rebase 后先刷新 defconfig: + +```bash +docker run --rm -it \ + -v "$PWD":/work \ + -w /work \ + ghcr.io/rcore-os/tgoskits-container:latest \ + bash -lc 'cargo xtask starry defconfig qemu-riscv64' +``` + +如果还不行,可以清理生成配置后重试: + +```bash +rm -rf tmp/axbuild/config/starryos +cargo xtask starry defconfig qemu-riscv64 +``` + +这条清理命令只应在你确认要丢弃本地生成配置时执行。 + +### 宿主机文件变成 root-owned + +如果手动进 Docker 跑过命令,退出前执行: + +```bash +chown -R "$HOST_UID:$HOST_GID" target tmp tools/qperf/target 2>/dev/null || true +``` + +如果已经退出容器,可以在宿主机用 sudo 修: + +```bash +sudo chown -R "$(id -u):$(id -g)" target tmp tools/qperf/target +``` + +## 15. 推荐日常流程 + +只想启动 StarryOS: + +```bash +docker run --rm -it \ + -v "$PWD":/work \ + -w /work \ + -e HOST_UID="$(id -u)" \ + -e HOST_GID="$(id -g)" \ + ghcr.io/rcore-os/tgoskits-container:latest \ + bash + +cargo xtask starry defconfig qemu-riscv64 +cargo xtask starry rootfs --arch riscv64 +cargo xtask starry qemu --arch riscv64 +chown -R "$HOST_UID:$HOST_GID" target tmp tools/qperf/target 2>/dev/null || true +exit +``` + +只想拿 qperf 报告: + +```bash +python3 tools/starry-syscall-harness/harness.py perf-profile \ + --arch riscv64 \ + --timeout 20 \ + --format all \ + --freq 99 \ + --max-depth 64 \ + --mode tb \ + --top 20 +``` + +想交互式看报告: + +```bash +python3 tools/starry-syscall-harness/harness.py ui \ + --host 127.0.0.1 \ + --port 8765 \ + --open +``` + +修改 StarryOS 逻辑后验证: + +```bash +docker run --rm \ + -v "$PWD":/work \ + -w /work \ + ghcr.io/rcore-os/tgoskits-container:latest \ + bash -lc 'cargo fmt --all --check && cargo xtask clippy --package starry-kernel' +``` + +如果改动影响 syscall 行为,再跑: + +```bash +python3 tools/starry-syscall-harness/harness.py discover \ + --arch riscv64 \ + --timeout 120 \ + --fail-on-diff +``` + +如果改动影响性能,再跑 qperf profile 和 perf diff。 + +## 16. 相关文档 + +更偏实现和问题分析的 qperf 采样记录见: + +```text +docs/qperf-sampling-debug-notes.md +``` + +harness 总览见: + +```text +docs/starry-syscall-harness.md +tools/starry-syscall-harness/README.md +``` diff --git a/docs/tg-arceos-tutorial-knowledge-graph-analysis.md b/docs/tg-arceos-tutorial-knowledge-graph-analysis.md new file mode 100644 index 0000000000..1a1fed010b --- /dev/null +++ b/docs/tg-arceos-tutorial-knowledge-graph-analysis.md @@ -0,0 +1,348 @@ +# tg-arceos-tutorial OS 知识图谱分析报告 + +## 1. 分析目标 + +本报告使用当前 harness GUI 的 OS 知识图谱框架,分析外部仓库 `cg24-THU/tg-arceos-tutorial` 的开发任务结构。重点不是重新实现该仓库任务,而是验证知识图谱框架是否能读取教程仓库的源码与文档,并把开发任务映射到 OS 子系统和课程知识点。 + +## 2. 输入仓库 + +| 项目 | 值 | +| --- | --- | +| 仓库 | `git@github.com:cg24-THU/tg-arceos-tutorial.git` | +| 本地路径 | `/home/cg24/tg-arceos-tutorial` | +| commit | `e8ae59bf640a6bce005c4dd4e3a99647bd83baec` | +| 工作区状态 | clean | +| 主要文档 | `README.md`、各 `app-*` / `exercise-*` 的 `README.md`、`report.md` | + +克隆命令: + +```bash +git clone git@github.com:cg24-THU/tg-arceos-tutorial.git /home/cg24/tg-arceos-tutorial +``` + +知识图谱扫描产物: + +```text +target/knowledge-graph/tg-arceos-tutorial.json +``` + +## 3. 对框架做的最小增强 + +原始 OS 知识图谱扫描器主要面向 tgoskits 主仓库,默认扫描 `os/`、`components/`、`drivers/`、`scripts/`、`tools/`、`docs/` 等目录。第一次直接扫描 `tg-arceos-tutorial` 时,`files_seen=0`,原因是教程仓库的核心内容位于 `app-*` 和 `exercise-*` 子 crate。 + +因此本轮做了最小增强: + +* `knowledge_graph.py` 支持扫描: + * 根 `README.md` + * 根 `report.md` + * 根 `Cargo.toml` + * `app-*` + * `exercise-*` +* 节点路径规则支持 glob,例如 `app-guest*/**`。 +* 新增教程相关节点: + * `unikernel_runtime` + * `monolithic_user` + * `hypervisor_guest` + * `tutorial_packaging` +* GUI 的 `Knowledge` 页新增 `扫描仓库路径` 输入框。 +* 后端 API 新增 `repo_root` 查询参数,可从当前 tgoskits GUI 扫描相邻本地仓库。 + +API smoke test: + +```bash +curl --noproxy '*' -s \ + 'http://127.0.0.1:8765/api/knowledge-graph?repo_root=/home/cg24/tg-arceos-tutorial&task=tg-arceos-tutorial%20exercise%20docs&granularity=fine&refresh=1' +``` + +返回: + +```text +HTTP 200 +repo_root=/home/cg24/tg-arceos-tutorial +nodes=20 +edges=27 +files_seen=396 +``` + +## 4. 文档内容摘要 + +根 `README.md` 明确说明该仓库是一个集合 crate,用于把 ArceOS 相关的 `app-*` 和 `exercise-*` 教学 crate 打包进 `bundle/apps.tar.gz`,便于 `cargo clone` 后离线解包。 + +根文档把内容分成三条主线: + +| 主线 | 子目录 | 文档描述 | +| --- | --- | --- | +| unikernel 教学示例 | `app-helloworld`、`app-collections`、`app-readpflash`、`app-childtask`、`app-msgqueue`、`app-fairsched`、`app-readblk`、`app-loadapp` | 从最小启动、标准库集合、MMIO、任务、调度、块设备到文件加载 | +| monolithic kernel 教学示例 | `app-userprivilege`、`app-lazymapping`、`app-runlinuxapp` | 用户态执行、lazy mapping、Linux ELF/syscall | +| hypervisor 教学示例 | `app-guestmode`、`app-guestaspace`、`app-guestvdev`、`app-guestmonolithickernel` | guest mode、guest address space、virtual device、guest monolithic kernel | + +根 `README.md` 还列出 5 个 `exercise-*`: + +| exercise | 文档任务 | +| --- | --- | +| `exercise-printcolor` | 彩色终端输出,理解 `println!` / console 输出层次 | +| `exercise-hashmap` | 在 `axstd` 中支持 `collections::HashMap` | +| `exercise-altalloc` | 实现 bump-style memory allocator | +| `exercise-ramfs-rename` | 在 ramfs 根文件系统上支持 `rename` | +| `exercise-sysmap` | 实现 `mmap(2)`,使文件映射到用户地址空间 | + +根 `report.md` 是已有实验报告,说明这 5 个 exercise 已按“最小必要修改 + 可验证交付”完成,并记录了单题验证和批量回归结果。报告中特别指出: + +* `exercise-sysmap` 是最复杂任务,实际调试中从 `mmap` 扩展到 `brk`、`mprotect`、基础 Linux ABI syscall 和交叉编译器 fallback。 +* `exercise-ramfs-rename` 涉及 `axfs::RootDirectory` 转发和 `axfs_ramfs::DirNode` 的 rename 实现。 +* 批量回归命令覆盖 5 个 exercise,结果为成功 5 个、失败 0 个。 + +本轮没有重新运行这些 exercise 的 Docker/QEMU 测试,只读取并分析仓库内已有文档和源码。 + +## 5. 知识图谱扫描结果 + +扫描命令: + +```bash +python3 - <<'PY' +from pathlib import Path +import json, sys +sys.path.insert(0, '/home/cg24/tgoskits/tools/starry-syscall-harness') +from knowledge_graph import build_knowledge_graph +kg = build_knowledge_graph( + Path('/home/cg24/tg-arceos-tutorial'), + task='分析 tg-arceos-tutorial app exercise 教学开发任务 文档 内容', + granularity='fine', +) +Path('target/knowledge-graph').mkdir(parents=True, exist_ok=True) +Path('target/knowledge-graph/tg-arceos-tutorial.json').write_text( + json.dumps(kg, ensure_ascii=False, indent=2), + encoding='utf-8', +) +PY +``` + +整体结果: + +| 指标 | 值 | +| --- | ---: | +| scanned files | 396 | +| graph nodes | 20 | +| graph edges | 27 | +| focus nodes | `unikernel_runtime`、`tutorial_packaging`、`monolithic_user`、`allocator`、`vfs_io` | + +Top 节点: + +| 节点 | 文件 | 行数 | 关键词命中 | 任务分 | +| --- | ---: | ---: | ---: | ---: | +| `unikernel_runtime` ArceOS unikernel apps | 157 | 15054 | 1149 | 29 | +| `tutorial_packaging` Tutorial bundle / scripts | 4 | 553 | 176 | 24 | +| `monolithic_user` Monolithic kernel / user apps | 63 | 7247 | 903 | 22 | +| `allocator` Allocator / object lifetime | 53 | 4967 | 1300 | 16 | +| `vfs_io` VFS / file I/O | 73 | 11334 | 2077 | 14 | +| `hypervisor_guest` Hypervisor / guest execution | 127 | 17779 | 2361 | 12 | +| `task_process` Task / process lifecycle | 54 | 5669 | 561 | 12 | +| `block_layer` Block layer / request queue | 37 | 4301 | 136 | 12 | +| `build_test` Build / rootfs / qemu tests | 105 | 16299 | 1074 | 7 | +| `interrupt_pci` PCI / interrupt / transport | 161 | 21081 | 910 | 6 | + +## 6. 开发任务到 OS 知识点的映射 + +### 6.1 Unikernel Runtime + +图谱焦点:`unikernel_runtime` + +覆盖目录: + +* `app-helloworld` +* `app-collections` +* `app-readpflash` +* `app-childtask` +* `app-msgqueue` +* `app-fairsched` +* `app-readblk` +* `app-loadapp` +* `exercise-printcolor` +* `exercise-hashmap` +* `exercise-altalloc` + +OS 讲解: + +* 课本知识:unikernel 把应用与内核库静态组合成专用镜像,弱化传统“内核/用户进程”边界,强调按需链接 OS 组件。 +* 仓库实践:这些 `app-*` 从 Hello World 开始,逐步引入 `axstd`、任务、调度、MMIO、块设备和文件加载。 + +对应开发任务: + +* `exercise-printcolor` 是最小 console 输出任务。 +* `exercise-hashmap` 是 `axstd` 标准库兼容任务。 +* `exercise-altalloc` 是内核分配器任务。 + +### 6.2 Tutorial Packaging + +图谱焦点:`tutorial_packaging` + +覆盖目录: + +* `README.md` +* `Cargo.toml` +* `report.md` +* `scripts/` +* `bundle/` +* `src/` + +OS/工程讲解: + +* 课本知识关联较弱,主要是课程工程化:如何把多个可运行 OS 实验组织成可分发、可离线恢复、可批量验证的形式。 +* 仓库实践:根 README 说明 `cargo clone` 后通过 `scripts/extract_crates.sh` 解包,维护者通过 `scripts/compress_crates.sh` 重新生成 `bundle/apps.tar.gz`。 + +对应开发任务: + +* 维护 bundle 完整性。 +* 批量执行 `app-*` / `exercise-*`。 +* 保持根 README、子 README、`report.md` 与实际代码一致。 + +### 6.3 Monolithic User + +图谱焦点:`monolithic_user` + +覆盖目录: + +* `app-userprivilege` +* `app-lazymapping` +* `app-runlinuxapp` +* `exercise-sysmap` + +OS 讲解: + +* 课本知识:用户/内核态隔离、系统调用 ABI、缺页异常、进程地址空间、ELF 加载、mmap。 +* 仓库实践:`app-userprivilege` 展示特权级切换,`app-lazymapping` 展示 demand paging,`app-runlinuxapp` 加载真实 Linux ELF,`exercise-sysmap` 实现 `mmap(2)`。 + +对应开发任务: + +* `exercise-sysmap` 是该仓库最典型的 monolithic/user 任务。 +* 它不是单点 `mmap`,实际需要考虑: + * 文件 fd 到映射内容的读取。 + * 用户地址空间中的页映射。 + * `brk` 堆映射。 + * `mprotect` 和运行时初始化 syscall。 + * musl/gnu 工具链差异。 + +### 6.4 Allocator + +图谱焦点:`allocator` + +覆盖目录: + +* `exercise-altalloc` +* `exercise-hashmap` +* `exercise-altalloc/modules/axalloc` +* `exercise-altalloc/modules/bump_allocator` + +OS 讲解: + +* 课本知识:内核分配器负责管理有限物理内存,常见主题包括 bump allocator、page allocator、byte allocator、碎片和生命周期。 +* 仓库实践:`exercise-altalloc` 要实现 `BaseAllocator`、`ByteAllocator`、`PageAllocator`;`exercise-hashmap` 则从集合类型侧依赖 allocator/collections 支撑。 + +对应开发任务: + +* `exercise-altalloc` 的核心是双端 bump: + * byte allocation 从低地址向高地址增长。 + * page allocation 从高地址向低地址增长。 + * 两端相遇时报 `NoMemory`。 +* `exercise-hashmap` 的核心是让 `axstd::collections::HashMap` 可用,实际采用本地 patch `axstd` 并引入 `hashbrown`。 + +### 6.5 VFS / File I/O + +图谱焦点:`vfs_io` + +覆盖目录: + +* `app-loadapp` +* `exercise-ramfs-rename` +* `exercise-sysmap` + +OS 讲解: + +* 课本知识:VFS 把 syscall 与具体文件系统、设备、缓存解耦;路径解析、inode/dentry、挂载点和 rename 语义是文件系统实验的核心。 +* 仓库实践: + * `app-loadapp` 展示 FAT filesystem、VirtIO block device 和文件加载。 + * `exercise-ramfs-rename` 在 ramfs 根文件系统上实现 `std::fs::rename`。 + * `exercise-sysmap` 的文件映射依赖文件读和磁盘镜像。 + +对应开发任务: + +* `exercise-ramfs-rename` 需要从 `std::fs::rename` 沿 VFS 路径追到: + * `axfs::root::rename` + * `RootDirectory::rename` + * `axfs_ramfs::DirNode` +* 该题文档明确只要求支持 rename,不要求跨目录 move。 + +## 7. 超出 focus 但重要的图谱节点 + +### Hypervisor / Guest Execution + +虽然当前 task 文本更偏 exercise/docs,`hypervisor_guest` 仍有 127 个文件、17779 行、2361 次关键词命中,说明它是教程仓库的一个大体量主题。 + +覆盖目录: + +* `app-guestmode` +* `app-guestaspace` +* `app-guestvdev` +* `app-guestmonolithickernel` + +OS 讲解: + +* 课本知识:guest/host 隔离、二阶段地址转换、VM entry/exit、虚拟设备、架构虚拟化扩展。 +* 仓库实践:这些 app 从最小 guest mode,逐步扩展到 guest address space、virtual device 和 guest monolithic kernel。 + +### Build / Rootfs / QEMU Tests + +`build_test` 识别到 105 个文件,主要来自各 crate 的: + +* `xtask/src/main.rs` +* `scripts/test.sh` +* `configs/*.toml` + +这说明教程仓库的开发任务不是单纯写 Rust 代码,而是强依赖多架构构建、QEMU 运行和脚本化验证。根 `report.md` 也说明真实验证覆盖的是 `riscv64`,其他架构因缺少 QEMU 被跳过。 + +## 8. 框架输出的可读讲解样例 + +以 `exercise-sysmap` 为例,细粒度讲解应这样使用: + +* 代码视角: + * 先看 `exercise-sysmap/README.md` 的 Requirements / Expectation。 + * 再看 `exercise-sysmap/src/syscall.rs`,定位 `SYS_MMAP`、`SYS_BRK`、兼容 syscall。 + * 再看 `exercise-sysmap/xtask/src/main.rs`,确认 payload 编译和工具链 fallback。 +* OS 视角: + * `mmap` 是用户地址空间管理,不只是文件 I/O。 + * 文件映射要把文件内容读入新映射页。 + * `brk` 要真实扩展并映射 heap。 + * 运行 Linux 用户程序时,动态/静态运行时可能依赖额外 syscall,即使题目表面只要求 `mmap`。 + +以 `exercise-ramfs-rename` 为例: + +* 代码视角: + * `std::fs::rename` -> `axfs` root -> mounted fs root -> `axfs_ramfs::DirNode`。 + * 注意路径父目录解析和生命周期。 +* OS 视角: + * VFS rename 是目录项原子更新问题。 + * 本题只支持同一父目录内 rename,不支持跨目录 move。 + +## 9. 结论 + +本次试用说明,扩展后的 OS 知识图谱框架可以分析 `tg-arceos-tutorial` 这类“多教学 crate 聚合仓库”: + +* 能扫描外部本地仓库。 +* 能读取根 README、子 crate README 和已有实验报告。 +* 能把 5 个 exercise 映射到 allocator、VFS、syscall、memory/user、unikernel runtime 等 OS 知识点。 +* 能把 `app-*` 主线分成 unikernel、monolithic user、hypervisor 三条课程路线。 +* 能在 GUI 里通过 `repo_root=/home/cg24/tg-arceos-tutorial` 返回同一份图谱。 + +当前结论是 `PARTIAL PASS`: + +* PASS:框架能完成静态扫描、任务定位和 OS 课本知识关联。 +* PARTIAL:它仍是启发式目录/关键词扫描,不是精确 Rust 调用图或依赖图。 + +## 10. 后续建议 + +1. 为教程仓库增加专门的 `Curriculum` 视图,把 `app-*` / `exercise-*` 按难度和 OS 主题排序。 +2. 从每个 README 自动提取 Requirements / Expectation / Verification,生成任务卡片。 +3. 用 `Cargo.toml` 和 `xtask` 信息补全每个 crate 的构建命令、架构支持和 QEMU 依赖。 +4. 将根 `report.md` 中的验证结果解析成结构化数据,展示每个 exercise 的 PASS/FAIL 状态。 +5. 后续如果要做自动 code explanation,可把选中的图谱节点与对应 README 段落、源码符号一起传给报告生成器。 + diff --git a/drivers/ax-driver/Cargo.toml b/drivers/ax-driver/Cargo.toml index a23d8dbf09..06d5d37715 100644 --- a/drivers/ax-driver/Cargo.toml +++ b/drivers/ax-driver/Cargo.toml @@ -86,6 +86,7 @@ rk3588-pcie = [ rockchip-soc = ["plat-dyn", "dep:rdif-clk", "dep:rockchip-soc"] rockchip-pm = ["rockchip-soc", "dep:rockchip-pm"] list-pci-devices = [] +qperf-metrics = [] [dependencies] anyhow = { workspace = true } diff --git a/drivers/ax-driver/src/block/binding.rs b/drivers/ax-driver/src/block/binding.rs index b5a13ecefb..55ddf18d16 100644 --- a/drivers/ax-driver/src/block/binding.rs +++ b/drivers/ax-driver/src/block/binding.rs @@ -156,14 +156,20 @@ impl Block { } pub fn read_block(&mut self, block_id: u64, buf: &mut [u8]) -> AxResult { - let block_size = self.block_size(); + let use_irq = self.use_irq_completion(); + let mut queue = self.queue.lock(); + let block_size = queue.block_size(); if block_size == 0 || !buf.len().is_multiple_of(block_size) { return Err(AxError::InvalidInput); } - let use_irq = self.use_irq_completion(); - let mut queue = self.queue.lock(); let block_count = buf.len() / block_size; + match queue.read_blocks_direct(block_id as usize, buf) { + Ok(()) => return Ok(()), + Err(BlkError::NotSupported) => {} + Err(err) => return Err(map_blk_err_to_ax_err(err)), + } + let blocks = Self::read_blocks_wait(&mut queue, block_id as usize, block_count, use_irq); let mut copied = 0; for block in blocks { @@ -182,13 +188,13 @@ impl Block { } pub fn write_block(&mut self, block_id: u64, buf: &[u8]) -> AxResult { - let block_size = self.block_size(); + let use_irq = self.use_irq_completion(); + let mut queue = self.queue.lock(); + let block_size = queue.block_size(); if block_size == 0 || !buf.len().is_multiple_of(block_size) { return Err(AxError::InvalidInput); } - let use_irq = self.use_irq_completion(); - let mut queue = self.queue.lock(); let blocks = Self::write_blocks_wait(&mut queue, block_id as usize, buf, use_irq); for block in blocks { block.map_err(map_blk_err_to_ax_err)?; diff --git a/drivers/ax-driver/src/lib.rs b/drivers/ax-driver/src/lib.rs index dcb0f0a7c9..510516fa97 100644 --- a/drivers/ax-driver/src/lib.rs +++ b/drivers/ax-driver/src/lib.rs @@ -73,6 +73,8 @@ pub mod net; pub mod vsock; pub mod pci; +#[cfg(feature = "qperf-metrics")] +pub mod qperf_metrics; #[cfg(feature = "rknpu")] pub mod rknpu; #[cfg(feature = "serial")] diff --git a/drivers/ax-driver/src/qperf_metrics.rs b/drivers/ax-driver/src/qperf_metrics.rs new file mode 100644 index 0000000000..b1a34d9433 --- /dev/null +++ b/drivers/ax-driver/src/qperf_metrics.rs @@ -0,0 +1,218 @@ +use alloc::{format, string::String}; +use core::{ + fmt::Write, + sync::atomic::{AtomicU64, Ordering}, +}; + +const DEPTH_BINS: usize = 9; + +static VIRTQUEUE_ADD: AtomicU64 = AtomicU64::new(0); +static VIRTQUEUE_NOTIFY_KICK: AtomicU64 = AtomicU64::new(0); +static VIRTQUEUE_POP_COMPLETE: AtomicU64 = AtomicU64::new(0); +static VIRTQUEUE_ADD_NOTIFY_WAIT_POP: AtomicU64 = AtomicU64::new(0); +static VIRTQUEUE_DEPTH_MAX: AtomicU64 = AtomicU64::new(0); +static VIRTQUEUE_DEPTH_HIST: [AtomicU64; DEPTH_BINS] = [const { AtomicU64::new(0) }; DEPTH_BINS]; + +static BLK_READ_REQUESTS: AtomicU64 = AtomicU64::new(0); +static BLK_WRITE_REQUESTS: AtomicU64 = AtomicU64::new(0); +static BLK_READ_BYTES: AtomicU64 = AtomicU64::new(0); +static BLK_WRITE_BYTES: AtomicU64 = AtomicU64::new(0); +static BLK_DIRECT_READ_REQUESTS: AtomicU64 = AtomicU64::new(0); +static BLK_DIRECT_READ_BYTES: AtomicU64 = AtomicU64::new(0); + +static NET_RX_PACKETS: AtomicU64 = AtomicU64::new(0); +static NET_TX_PACKETS: AtomicU64 = AtomicU64::new(0); +static NET_RX_BYTES: AtomicU64 = AtomicU64::new(0); +static NET_TX_BYTES: AtomicU64 = AtomicU64::new(0); +static NET_RX_COPY_WITHIN_COUNT: AtomicU64 = AtomicU64::new(0); +static NET_RX_COPY_WITHIN_BYTES: AtomicU64 = AtomicU64::new(0); +static NET_TX_STAGING_COPY_COUNT: AtomicU64 = AtomicU64::new(0); +static NET_TX_STAGING_COPY_BYTES: AtomicU64 = AtomicU64::new(0); +static NET_INFLIGHT_INSERT: AtomicU64 = AtomicU64::new(0); +static NET_INFLIGHT_REMOVE: AtomicU64 = AtomicU64::new(0); +static NET_INFLIGHT_GET: AtomicU64 = AtomicU64::new(0); + +pub fn record_blk_read(bytes: usize) { + BLK_READ_REQUESTS.fetch_add(1, Ordering::Relaxed); + BLK_READ_BYTES.fetch_add(bytes as u64, Ordering::Relaxed); + record_add_notify_wait_pop(1); +} + +pub fn record_blk_direct_read(bytes: usize) { + BLK_DIRECT_READ_REQUESTS.fetch_add(1, Ordering::Relaxed); + BLK_DIRECT_READ_BYTES.fetch_add(bytes as u64, Ordering::Relaxed); + record_blk_read(bytes); +} + +pub fn record_blk_write(bytes: usize) { + BLK_WRITE_REQUESTS.fetch_add(1, Ordering::Relaxed); + BLK_WRITE_BYTES.fetch_add(bytes as u64, Ordering::Relaxed); + record_add_notify_wait_pop(1); +} + +pub fn record_net_tx(bytes: usize, depth: usize) { + NET_TX_PACKETS.fetch_add(1, Ordering::Relaxed); + NET_TX_BYTES.fetch_add(bytes as u64, Ordering::Relaxed); + NET_TX_STAGING_COPY_COUNT.fetch_add(1, Ordering::Relaxed); + NET_TX_STAGING_COPY_BYTES.fetch_add(bytes as u64, Ordering::Relaxed); + NET_INFLIGHT_INSERT.fetch_add(1, Ordering::Relaxed); + record_virtqueue_add(depth); + record_notify_kick(); +} + +pub fn record_net_tx_complete(depth: usize) { + NET_INFLIGHT_GET.fetch_add(1, Ordering::Relaxed); + NET_INFLIGHT_REMOVE.fetch_add(1, Ordering::Relaxed); + record_pop_complete(depth); +} + +pub fn record_net_rx_submit(depth: usize) { + NET_INFLIGHT_INSERT.fetch_add(1, Ordering::Relaxed); + record_virtqueue_add(depth); + record_notify_kick(); +} + +pub fn record_net_rx_complete(bytes: usize, copy_bytes: usize, depth: usize) { + NET_RX_PACKETS.fetch_add(1, Ordering::Relaxed); + NET_RX_BYTES.fetch_add(bytes as u64, Ordering::Relaxed); + NET_RX_COPY_WITHIN_COUNT.fetch_add(1, Ordering::Relaxed); + NET_RX_COPY_WITHIN_BYTES.fetch_add(copy_bytes as u64, Ordering::Relaxed); + NET_INFLIGHT_GET.fetch_add(1, Ordering::Relaxed); + NET_INFLIGHT_REMOVE.fetch_add(1, Ordering::Relaxed); + record_pop_complete(depth); +} + +fn record_add_notify_wait_pop(depth: usize) { + VIRTQUEUE_ADD_NOTIFY_WAIT_POP.fetch_add(1, Ordering::Relaxed); + record_virtqueue_add(depth); + record_notify_kick(); + record_pop_complete(depth.saturating_sub(1)); +} + +fn record_virtqueue_add(depth: usize) { + VIRTQUEUE_ADD.fetch_add(1, Ordering::Relaxed); + record_depth(depth); +} + +fn record_notify_kick() { + VIRTQUEUE_NOTIFY_KICK.fetch_add(1, Ordering::Relaxed); +} + +fn record_pop_complete(depth: usize) { + VIRTQUEUE_POP_COMPLETE.fetch_add(1, Ordering::Relaxed); + record_depth(depth); +} + +fn record_depth(depth: usize) { + update_max(&VIRTQUEUE_DEPTH_MAX, depth as u64); + VIRTQUEUE_DEPTH_HIST[depth_bin(depth)].fetch_add(1, Ordering::Relaxed); +} + +fn depth_bin(depth: usize) -> usize { + match depth { + 0 => 0, + 1 => 1, + 2 => 2, + 3 | 4 => 3, + 5..=8 => 4, + 9..=16 => 5, + 17..=32 => 6, + 33..=64 => 7, + _ => 8, + } +} + +fn update_max(max: &AtomicU64, value: u64) { + let mut current = max.load(Ordering::Relaxed); + while value > current { + match max.compare_exchange_weak(current, value, Ordering::Relaxed, Ordering::Relaxed) { + Ok(_) => break, + Err(next) => current = next, + } + } +} + +pub fn render() -> String { + let mut output = format!( + "QPERF_METRIC virtqueue_add_count={} virtio_notify_kick_count={} \ + virtqueue_pop_complete_count={} virtqueue_add_notify_wait_pop_count={} \ + virtqueue_depth_max={} virtqueue_depth_hist_0={} virtqueue_depth_hist_1={} \ + virtqueue_depth_hist_2={} virtqueue_depth_hist_3_4={} virtqueue_depth_hist_5_8={} \ + virtqueue_depth_hist_9_16={} virtqueue_depth_hist_17_32={} virtqueue_depth_hist_33_64={} \ + virtqueue_depth_hist_gt64={} virtio_blk_read_requests={} virtio_blk_write_requests={} \ + virtio_blk_read_bytes={} virtio_blk_write_bytes={} virtio_blk_direct_read_requests={} \ + virtio_blk_direct_read_bytes={} virtio_net_rx_packets={} virtio_net_tx_packets={} \ + virtio_net_rx_bytes={} virtio_net_tx_bytes={} virtio_net_rx_copy_within_count={} \ + virtio_net_rx_copy_within_bytes={} virtio_net_tx_staging_copy_count={} \ + virtio_net_tx_staging_copy_bytes={} virtio_net_inflight_insert_count={} \ + virtio_net_inflight_remove_count={} virtio_net_inflight_get_count={}\n", + VIRTQUEUE_ADD.load(Ordering::Relaxed), + VIRTQUEUE_NOTIFY_KICK.load(Ordering::Relaxed), + VIRTQUEUE_POP_COMPLETE.load(Ordering::Relaxed), + VIRTQUEUE_ADD_NOTIFY_WAIT_POP.load(Ordering::Relaxed), + VIRTQUEUE_DEPTH_MAX.load(Ordering::Relaxed), + VIRTQUEUE_DEPTH_HIST[0].load(Ordering::Relaxed), + VIRTQUEUE_DEPTH_HIST[1].load(Ordering::Relaxed), + VIRTQUEUE_DEPTH_HIST[2].load(Ordering::Relaxed), + VIRTQUEUE_DEPTH_HIST[3].load(Ordering::Relaxed), + VIRTQUEUE_DEPTH_HIST[4].load(Ordering::Relaxed), + VIRTQUEUE_DEPTH_HIST[5].load(Ordering::Relaxed), + VIRTQUEUE_DEPTH_HIST[6].load(Ordering::Relaxed), + VIRTQUEUE_DEPTH_HIST[7].load(Ordering::Relaxed), + VIRTQUEUE_DEPTH_HIST[8].load(Ordering::Relaxed), + BLK_READ_REQUESTS.load(Ordering::Relaxed), + BLK_WRITE_REQUESTS.load(Ordering::Relaxed), + BLK_READ_BYTES.load(Ordering::Relaxed), + BLK_WRITE_BYTES.load(Ordering::Relaxed), + BLK_DIRECT_READ_REQUESTS.load(Ordering::Relaxed), + BLK_DIRECT_READ_BYTES.load(Ordering::Relaxed), + NET_RX_PACKETS.load(Ordering::Relaxed), + NET_TX_PACKETS.load(Ordering::Relaxed), + NET_RX_BYTES.load(Ordering::Relaxed), + NET_TX_BYTES.load(Ordering::Relaxed), + NET_RX_COPY_WITHIN_COUNT.load(Ordering::Relaxed), + NET_RX_COPY_WITHIN_BYTES.load(Ordering::Relaxed), + NET_TX_STAGING_COPY_COUNT.load(Ordering::Relaxed), + NET_TX_STAGING_COPY_BYTES.load(Ordering::Relaxed), + NET_INFLIGHT_INSERT.load(Ordering::Relaxed), + NET_INFLIGHT_REMOVE.load(Ordering::Relaxed), + NET_INFLIGHT_GET.load(Ordering::Relaxed), + ); + let _ = writeln!( + output, + "QPERF_METRIC qperf_metrics_export=1 qperf_metrics_scope=ax_driver_virtio" + ); + output +} + +pub fn reset() { + for item in [ + &VIRTQUEUE_ADD, + &VIRTQUEUE_NOTIFY_KICK, + &VIRTQUEUE_POP_COMPLETE, + &VIRTQUEUE_ADD_NOTIFY_WAIT_POP, + &VIRTQUEUE_DEPTH_MAX, + &BLK_READ_REQUESTS, + &BLK_WRITE_REQUESTS, + &BLK_READ_BYTES, + &BLK_WRITE_BYTES, + &BLK_DIRECT_READ_REQUESTS, + &BLK_DIRECT_READ_BYTES, + &NET_RX_PACKETS, + &NET_TX_PACKETS, + &NET_RX_BYTES, + &NET_TX_BYTES, + &NET_RX_COPY_WITHIN_COUNT, + &NET_RX_COPY_WITHIN_BYTES, + &NET_TX_STAGING_COPY_COUNT, + &NET_TX_STAGING_COPY_BYTES, + &NET_INFLIGHT_INSERT, + &NET_INFLIGHT_REMOVE, + &NET_INFLIGHT_GET, + ] { + item.store(0, Ordering::Relaxed); + } + for item in &VIRTQUEUE_DEPTH_HIST { + item.store(0, Ordering::Relaxed); + } +} diff --git a/drivers/ax-driver/src/virtio/block.rs b/drivers/ax-driver/src/virtio/block.rs index 8081ce07a7..0a39ba8009 100644 --- a/drivers/ax-driver/src/virtio/block.rs +++ b/drivers/ax-driver/src/virtio/block.rs @@ -14,6 +14,7 @@ use virtio_drivers::{ use crate::{block::PlatformDeviceBlock, virtio::VirtIoHalImpl}; const VIRTIO_BLK_DMA_BUFFER_SIZE: usize = 32 * SECTOR_SIZE; +const VIRTIO_BLK_DIRECT_PAGE_SIZE: usize = 0x1000; #[cfg(any(plat_static, plat_dyn))] crate::model_register!( @@ -151,26 +152,80 @@ impl rd_block::IQueue for BlockQueue { ) -> Result { match request.kind { rd_block::RequestKind::Read(mut buffer) => { + #[cfg(feature = "qperf-metrics")] + let bytes = buffer.len(); self.raw .raw .read_blocks(request.block_id, &mut buffer) .map_err(map_virtio_err_to_blk_err)?; + #[cfg(feature = "qperf-metrics")] + crate::qperf_metrics::record_blk_read(bytes); } rd_block::RequestKind::Write(items) => { + #[cfg(feature = "qperf-metrics")] + let bytes = items.len(); self.raw .raw .write_blocks(request.block_id, items) .map_err(map_virtio_err_to_blk_err)?; + #[cfg(feature = "qperf-metrics")] + crate::qperf_metrics::record_blk_write(bytes); } } Ok(rd_block::RequestId::new(0)) } + fn read_blocks_direct( + &mut self, + block_id: usize, + buf: &mut [u8], + ) -> Result<(), rd_block::BlkError> { + if !is_physically_contiguous(buf) { + return Err(rd_block::BlkError::NotSupported); + } + + #[cfg(feature = "qperf-metrics")] + let bytes = buf.len(); + self.raw + .raw + .read_blocks(block_id, buf) + .map_err(map_virtio_err_to_blk_err)?; + #[cfg(feature = "qperf-metrics")] + crate::qperf_metrics::record_blk_direct_read(bytes); + Ok(()) + } + fn poll_request(&mut self, _request: rd_block::RequestId) -> Result<(), rd_block::BlkError> { Ok(()) } } +fn is_physically_contiguous(buf: &[u8]) -> bool { + if buf.is_empty() { + return false; + } + + let start = buf.as_ptr() as usize; + let Some(end) = start.checked_add(buf.len() - 1) else { + return false; + }; + + let first_page = start & !(VIRTIO_BLK_DIRECT_PAGE_SIZE - 1); + let last_page = end & !(VIRTIO_BLK_DIRECT_PAGE_SIZE - 1); + let mut page = first_page; + let mut expected = axklib::mem::virt_to_phys(page.into()).as_usize(); + + while page < last_page { + page += VIRTIO_BLK_DIRECT_PAGE_SIZE; + expected += VIRTIO_BLK_DIRECT_PAGE_SIZE; + if axklib::mem::virt_to_phys(page.into()).as_usize() != expected { + return false; + } + } + + true +} + fn map_virtio_err_to_blk_err(err: VirtIoError) -> rd_block::BlkError { match err { VirtIoError::QueueFull | VirtIoError::NotReady => rd_block::BlkError::Retry, diff --git a/drivers/ax-driver/src/virtio/net.rs b/drivers/ax-driver/src/virtio/net.rs index 4e07c37579..380cb31b54 100644 --- a/drivers/ax-driver/src/virtio/net.rs +++ b/drivers/ax-driver/src/virtio/net.rs @@ -200,6 +200,8 @@ impl NetInner { .map_err(map_net_error)?; staging[header_len..header_len + buffer.len].copy_from_slice(packet); let token = unsafe { self.raw.transmit_begin(&staging) }.map_err(map_net_error)?; + #[cfg(feature = "qperf-metrics")] + crate::qperf_metrics::record_net_tx(packet.len(), self.tx_inflight.len() + 1); self.tx_inflight.insert( token, TxInflight { @@ -214,6 +216,8 @@ impl NetInner { let token = self.raw.poll_transmit()?; let inflight = self.tx_inflight.remove(&token)?; let _ = unsafe { self.raw.transmit_complete(token, &inflight.staging) }; + #[cfg(feature = "qperf-metrics")] + crate::qperf_metrics::record_net_tx_complete(self.tx_inflight.len()); Some(inflight.bus_addr) } @@ -221,6 +225,8 @@ impl NetInner { let rx_buffer = unsafe { core::slice::from_raw_parts_mut(buffer.virt.as_ptr(), buffer.len) }; let token = unsafe { self.raw.receive_begin(rx_buffer) }.map_err(map_net_error)?; + #[cfg(feature = "qperf-metrics")] + crate::qperf_metrics::record_net_rx_submit(self.rx_inflight.len() + 1); self.rx_inflight.insert( token, RxInflight { @@ -238,6 +244,12 @@ impl NetInner { let buffer = unsafe { core::slice::from_raw_parts_mut(inflight.virt_addr as *mut u8, inflight.len) }; let (header_len, packet_len) = unsafe { self.raw.receive_complete(token, buffer) }.ok()?; + #[cfg(feature = "qperf-metrics")] + crate::qperf_metrics::record_net_rx_complete( + packet_len, + packet_len, + self.rx_inflight.len(), + ); buffer.copy_within(header_len..header_len + packet_len, 0); Some((inflight.bus_addr, packet_len)) } diff --git a/drivers/blk/rd-block/src/lib.rs b/drivers/blk/rd-block/src/lib.rs index a1a3601c21..cd65ee8c02 100644 --- a/drivers/blk/rd-block/src/lib.rs +++ b/drivers/blk/rd-block/src/lib.rs @@ -222,6 +222,10 @@ impl CmdQueue { spin_on::spin_on(self.read_blocks(blk_id, blk_count)) } + pub fn read_blocks_direct(&mut self, blk_id: usize, buf: &mut [u8]) -> Result<(), BlkError> { + self.interface.read_blocks_direct(blk_id, buf) + } + pub async fn write_blocks( &mut self, start_blk_id: usize, diff --git a/drivers/interface/rdif-block/src/lib.rs b/drivers/interface/rdif-block/src/lib.rs index 3dcf3f9681..b1ead48b73 100644 --- a/drivers/interface/rdif-block/src/lib.rs +++ b/drivers/interface/rdif-block/src/lib.rs @@ -245,6 +245,14 @@ pub trait IQueue: Send + 'static { fn submit_request(&mut self, request: Request<'_>) -> Result; + /// Try to read blocks directly into the caller-provided buffer. + /// + /// Implementations may return [`BlkError::NotSupported`] when the buffer is + /// not suitable for direct DMA or the device does not provide a direct path. + fn read_blocks_direct(&mut self, _block_id: usize, _buf: &mut [u8]) -> Result<(), BlkError> { + Err(BlkError::NotSupported) + } + /// Poll the status of a previously submitted request. fn poll_request(&mut self, request: RequestId) -> Result<(), BlkError>; } diff --git a/os/StarryOS/kernel/Cargo.toml b/os/StarryOS/kernel/Cargo.toml index a3ac6d926f..c058ca9e49 100644 --- a/os/StarryOS/kernel/Cargo.toml +++ b/os/StarryOS/kernel/Cargo.toml @@ -21,6 +21,7 @@ input = ["dep:ax-input", "ax-feat/input"] ebpf = [] memtrack = ["ax-feat/dwarf", "ax-alloc/tracking", "dep:gimli"] rknpu = ["dep:ax-driver", "ax-driver/rknpu"] +qperf-metrics = ["dep:ax-driver", "ax-driver/qperf-metrics"] plat-dyn = [ "ax-feat/plat-dyn", "dep:ax-driver", diff --git a/os/StarryOS/kernel/src/pseudofs/proc.rs b/os/StarryOS/kernel/src/pseudofs/proc.rs index 8ddb9a4ffd..8ad6073d81 100644 --- a/os/StarryOS/kernel/src/pseudofs/proc.rs +++ b/os/StarryOS/kernel/src/pseudofs/proc.rs @@ -942,6 +942,25 @@ fn builder(fs: Arc) -> DirMaker { } }), ); + #[cfg(feature = "qperf-metrics")] + root.add( + "qperf_metrics", + SimpleFile::new_regular( + fs.clone(), + RwFile::new(|req| match req { + SimpleFileOperation::Read => Ok(Some(ax_driver::qperf_metrics::render())), + SimpleFileOperation::Write(data) => { + if core::str::from_utf8(data) + .map(|text| text.trim() == "reset") + .unwrap_or(false) + { + ax_driver::qperf_metrics::reset(); + } + Ok(None) + } + }), + ), + ); // Timer-tick callbacks registered once on the boot CPU. // IRQ counting: increment the module-level IRQ_CNT on every tick. ax_task::register_timer_callback(|_| { diff --git a/os/StarryOS/kernel/src/syscall/fs/io.rs b/os/StarryOS/kernel/src/syscall/fs/io.rs index 550e476ccd..5b0fca0686 100644 --- a/os/StarryOS/kernel/src/syscall/fs/io.rs +++ b/os/StarryOS/kernel/src/syscall/fs/io.rs @@ -228,7 +228,15 @@ pub fn sys_ftruncate(fd: c_int, length: __kernel_off_t) -> AxResult { if (length as u64) > u32::MAX as u64 * 4096 { return Err(AxError::from(LinuxError::EFBIG)); } - f.inner().access(FileFlags::WRITE)?.set_len(length as _)?; + let file = f.inner(); + let flags = file.flags(); + if flags.contains(FileFlags::PATH) { + return Err(AxError::BadFileDescriptor); + } + if !flags.contains(FileFlags::WRITE) { + return Err(AxError::BadFileDescriptor); + } + file.access(FileFlags::WRITE)?.set_len(length as _)?; Ok(0) } diff --git a/os/StarryOS/starryos/Cargo.toml b/os/StarryOS/starryos/Cargo.toml index 66aa264810..36559b51d6 100644 --- a/os/StarryOS/starryos/Cargo.toml +++ b/os/StarryOS/starryos/Cargo.toml @@ -57,6 +57,7 @@ aarch64-hvf = ["gic-v3", "cntv-timer"] rknpu = ["ax-driver/rknpu", "starry-kernel/rknpu"] vf2 = ["ax-hal/riscv64-visionfive2"] +qperf-metrics = ["ax-driver/qperf-metrics", "starry-kernel/qperf-metrics"] [[bin]] name = "starryos" diff --git a/os/arceos/modules/axnet-ng/src/device/vsock.rs b/os/arceos/modules/axnet-ng/src/device/vsock.rs index 186c9f99ce..3d27575b01 100644 --- a/os/arceos/modules/axnet-ng/src/device/vsock.rs +++ b/os/arceos/modules/axnet-ng/src/device/vsock.rs @@ -135,13 +135,14 @@ fn poll_vsock_interfaces() -> AxResult { let mut guard = VSOCK_DEVICE.lock(); let dev = guard.as_mut().ok_or(AxError::NotFound)?; let mut event_count = 0; - let mut buf = alloc::vec![0; VSOCK_RX_TMPBUF_SIZE]; + let mut buf = None; // Process pending events first // Use core::mem::take to atomically move all events out and empty the global queue let pending_events = core::mem::take(&mut *PENDING_EVENTS.lock()); for event in pending_events { - handle_vsock_event(event, dev, &mut buf); + let buf = buf.get_or_insert_with(|| alloc::vec![0; VSOCK_RX_TMPBUF_SIZE]); + handle_vsock_event(event, dev, buf); } loop { @@ -149,7 +150,8 @@ fn poll_vsock_interfaces() -> AxResult { Ok(None) => break, // no more events Ok(Some(event)) => { event_count += 1; - handle_vsock_event(event, dev, &mut buf); + let buf = buf.get_or_insert_with(|| alloc::vec![0; VSOCK_RX_TMPBUF_SIZE]); + handle_vsock_event(event, dev, buf); } Err(e) => { info!("Failed to poll vsock event: {e:?}"); diff --git a/scripts/axbuild/src/context/workspace.rs b/scripts/axbuild/src/context/workspace.rs index d1f1dba780..7b34711458 100644 --- a/scripts/axbuild/src/context/workspace.rs +++ b/scripts/axbuild/src/context/workspace.rs @@ -1,5 +1,6 @@ use std::{ collections::HashSet, + env, path::{Path, PathBuf}, }; @@ -38,7 +39,17 @@ pub(crate) fn workspace_manifest_path() -> anyhow::Result { } pub(crate) fn axbuild_tmp_dir(workspace_root: &Path) -> PathBuf { - workspace_root.join("tmp").join("axbuild") + env::var_os("AXBUILD_TMP_DIR") + .filter(|value| !value.is_empty()) + .map(PathBuf::from) + .map(|path| { + if path.is_absolute() { + path + } else { + workspace_root.join(path) + } + }) + .unwrap_or_else(|| workspace_root.join("tmp").join("axbuild")) } pub(crate) fn workspace_manifest_path_in(workspace_root: &Path) -> PathBuf { diff --git a/scripts/axbuild/src/lib.rs b/scripts/axbuild/src/lib.rs index 5fb5c13952..17ed298e03 100644 --- a/scripts/axbuild/src/lib.rs +++ b/scripts/axbuild/src/lib.rs @@ -81,7 +81,7 @@ enum Commands { /// StarryOS build commands Starry { #[command(subcommand)] - command: starry::Command, + command: Box, }, } @@ -100,6 +100,6 @@ async fn run_root_cli(cli: Cli) -> anyhow::Result<()> { Commands::Backtrace { command } => backtrace::execute(command), Commands::Axvisor { command } => Axvisor::new()?.execute(command).await, Commands::Arceos { command } => ArceOS::new()?.execute(command).await, - Commands::Starry { command } => Starry::new()?.execute(command).await, + Commands::Starry { command } => Starry::new()?.execute(*command).await, } } diff --git a/scripts/axbuild/src/starry/mod.rs b/scripts/axbuild/src/starry/mod.rs index d81dc61618..1b04e7babd 100644 --- a/scripts/axbuild/src/starry/mod.rs +++ b/scripts/axbuild/src/starry/mod.rs @@ -1,4 +1,7 @@ -use std::path::{Path, PathBuf}; +use std::{ + fmt, + path::{Path, PathBuf}, +}; use clap::{Args, Subcommand, ValueEnum}; use ostool::{ @@ -25,6 +28,7 @@ pub enum Command { /// Build StarryOS application Build(ArgsBuild), /// Build and run StarryOS application + #[command(alias = "run")] Qemu(ArgsQemu), /// Generate a default StarryOS board config Defconfig(ArgsDefconfig), @@ -74,22 +78,181 @@ pub struct ArgsQemu { /// Override the rootfs disk image path (skips auto-download). #[arg(long, value_name = "IMAGE")] pub rootfs: Option, + + #[command(flatten)] + pub perf: ArgsQemuPerf, +} + +#[derive(Args, Debug, Clone, Default)] +pub struct ArgsQemuPerf { + /// Profile this run with qperf instead of launching a plain QEMU session. + #[arg(long)] + pub perf: bool, + #[arg(long = "perf-case", value_name = "NAME")] + pub case: Option, + #[arg(long = "perf-workload", value_name = "CMD")] + pub workload: Option, + #[arg(long = "perf-shell-prefix", value_name = "PREFIX")] + pub shell_prefix: Option, + #[arg(long = "perf-output-dir", value_name = "DIR")] + pub output_dir: Option, + #[arg(long = "perf-start-marker", value_name = "MARKER")] + pub start_marker: Option, + #[arg(long = "perf-stop-marker", value_name = "MARKER")] + pub stop_marker: Option, + #[arg(long = "perf-timeout", value_name = "SECONDS")] + pub timeout: Option, + #[arg(long = "perf-workload-timeout", value_name = "SECONDS")] + pub workload_timeout: Option, + #[arg(long = "perf-freq", value_name = "HZ")] + pub freq: Option, + #[arg(long = "perf-max-depth", value_name = "DEPTH")] + pub max_depth: Option, + #[arg(long = "perf-mode", value_enum)] + pub mode: Option, + #[arg(long = "perf-format", value_enum)] + pub format: Option, + #[arg(long = "perf-top", value_name = "N")] + pub top: Option, + #[arg(long = "perf-min-percent", value_name = "PERCENT")] + pub min_percent: Option, + #[arg(long = "perf-host-time")] + pub host_time: bool, + #[arg(long = "perf-no-host-time")] + pub no_host_time: bool, + #[arg(long = "perf-host-perf")] + pub host_perf: bool, + #[arg(long = "perf-host-perf-events", value_name = "EVENTS")] + pub host_perf_events: Option, + #[arg(long = "perf-qperf-metrics")] + pub qperf_metrics: bool, + #[arg(long = "perf-qemu-arg", value_name = "ARG", allow_hyphen_values = true)] + pub qemu_args: Vec, + #[arg(long = "perf-flamegraph")] + pub flamegraph: bool, + #[arg(long = "perf-flamegraph-kind", value_enum)] + pub flamegraph_kind: Option, + #[arg(long = "perf-full-stack")] + pub full_stack: bool, + #[arg(long = "perf-callchain", value_enum)] + pub callchain: Option, + #[arg(long = "perf-debuginfo")] + pub debuginfo: bool, + #[arg(long = "perf-force-frame-pointers")] + pub force_frame_pointers: bool, + #[arg(long = "perf-demangle")] + pub demangle: bool, + #[arg(long = "perf-no-truncate")] + pub no_truncate: bool, + #[arg(long = "perf-symbol-style", value_enum)] + pub symbol_style: Option, + #[arg(long = "perf-focus", value_name = "REGEX")] + pub focus: Option, } #[derive(Args, Debug, Clone)] pub struct ArgsPerf { + /// Profile case name used in the default output path. + #[arg(long, default_value = "boot")] + pub case: String, #[arg(long)] pub arch: Option, #[arg(long, default_value_t = 99)] pub freq: u32, - #[arg(long)] + #[arg(long = "out", hide = true)] pub out: Option, + /// Output root. Final reports go under /perf//latest. + #[arg(long)] + pub output_dir: Option, #[arg(long, value_enum, default_value_t = PerfFormat::All)] pub format: PerfFormat, - #[arg(long, default_value_t = 64)] + #[arg(long, default_value_t = 128)] pub max_depth: usize, #[arg(long, value_name = "SECONDS", default_value_t = 20)] pub timeout: u64, + #[arg(long, value_enum, default_value_t = PerfMode::Tb)] + pub mode: PerfMode, + #[arg(long, default_value_t = 80)] + pub top: usize, + #[arg(long, default_value_t = 0.3)] + pub min_percent: f64, + #[arg(long)] + pub debug: bool, + #[arg(long)] + pub kernel_filter: bool, + /// Collect host wall/user/system CPU time metrics for the QEMU process wrapper. + #[arg(long)] + pub host_time: bool, + /// Disable the cargo starry perf default host-time metrics. + #[arg(long)] + pub no_host_time: bool, + /// Run QEMU under host perf stat. These are host/QEMU process metrics, not guest PMU values. + #[arg(long)] + pub host_perf: bool, + /// Comma-separated host perf stat events used with --host-perf. + #[arg( + long, + default_value = "task-clock,cycles,instructions,cache-references,cache-misses,\ + context-switches,cpu-migrations,page-faults" + )] + pub host_perf_events: String, + /// Send this command to the guest shell after the qperf boot prompt appears. + #[arg(long, visible_alias = "workload")] + pub shell_init_cmd: Option, + /// Prompt substring used before sending --shell-init-cmd. + #[arg(long)] + pub shell_prefix: Option, + /// Append one raw QEMU argument. Repeat for options and values. + #[arg(long = "qemu-arg", value_name = "ARG", allow_hyphen_values = true)] + pub qemu_args: Vec, + /// Guest stdout marker that starts the workload sampling window. + #[arg(long)] + pub start_marker: Option, + /// Guest stdout marker that stops the workload sampling window. + #[arg(long)] + pub stop_marker: Option, + /// Stop QEMU if the workload window stays open longer than this many seconds. + #[arg(long, value_name = "SECONDS")] + pub workload_timeout: Option, + /// Enable feature-gated in-guest qperf metric counters. + #[arg(long)] + pub qperf_metrics: bool, + /// Request SVG flamegraph generation even when --format is folded. + #[arg(long)] + pub flamegraph: bool, + /// Flamegraph view format. + #[arg(long, value_enum, default_value_t = PerfFlamegraphKind::Svg)] + pub flamegraph_kind: PerfFlamegraphKind, + /// Preserve the deepest stack qperf can collect for this build. + #[arg(long)] + pub full_stack: bool, + /// qperf callchain collection mode. `leaf` is fastest; `fp` requires frame pointers. + #[arg(long = "perf-callchain", visible_alias = "callchain", value_enum)] + pub callchain: Option, + /// Add DWARF debug info and keep symbols for qperf symbolization. + #[arg(long = "perf-debuginfo")] + pub debuginfo: bool, + /// Force frame pointers for qperf FP unwinding. + #[arg(long = "perf-force-frame-pointers")] + pub force_frame_pointers: bool, + /// Force Rust demangling in qperf-analyzer. + #[arg(long)] + pub demangle: bool, + /// Keep tiny frames in SVG output by setting flamegraph min width to zero. + #[arg(long)] + pub no_truncate: bool, + /// Include kernel symbols in symbolized stacks. This is the default for StarryOS kernels. + #[arg(long)] + pub include_kernel_symbols: bool, + /// Include user symbols when available. Current StarryOS qperf only resolves the kernel ELF. + #[arg(long)] + pub include_user_symbols: bool, + /// Folded-stack symbol style. + #[arg(long, value_enum, default_value_t = PerfSymbolStyle::Full)] + pub symbol_style: PerfSymbolStyle, + /// Generate an additional focused folded stack/flamegraph for matching frames. + #[arg(long, value_name = "REGEX")] + pub focus: Option, } #[derive(Debug, Clone, Copy, PartialEq, Eq, ValueEnum)] @@ -100,6 +263,72 @@ pub enum PerfFormat { All, } +#[derive(Debug, Clone, Copy, PartialEq, Eq, ValueEnum)] +pub enum PerfMode { + Tb, + Insn, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, ValueEnum)] +pub enum PerfCallchain { + Leaf, + Fp, + Logical, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, ValueEnum)] +pub enum PerfFlamegraphKind { + Svg, + Html, + Folded, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, ValueEnum)] +pub enum PerfSymbolStyle { + Full, + Short, + Module, +} + +impl fmt::Display for PerfMode { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str(match self { + Self::Tb => "tb", + Self::Insn => "insn", + }) + } +} + +impl fmt::Display for PerfCallchain { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str(match self { + Self::Leaf => "leaf", + Self::Fp => "fp", + Self::Logical => "logical", + }) + } +} + +impl fmt::Display for PerfFlamegraphKind { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str(match self { + Self::Svg => "svg", + Self::Html => "html", + Self::Folded => "folded", + }) + } +} + +impl fmt::Display for PerfSymbolStyle { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str(match self { + Self::Full => "full", + Self::Short => "short", + Self::Module => "module", + }) + } +} + #[derive(Args)] pub struct ArgsUboot { #[command(flatten)] @@ -160,6 +389,100 @@ impl From<&ArgsBuild> for StarryCliArgs { } } +impl ArgsQemuPerf { + fn has_overrides(&self) -> bool { + self.case.is_some() + || self.workload.is_some() + || self.shell_prefix.is_some() + || self.output_dir.is_some() + || self.start_marker.is_some() + || self.stop_marker.is_some() + || self.timeout.is_some() + || self.workload_timeout.is_some() + || self.freq.is_some() + || self.max_depth.is_some() + || self.mode.is_some() + || self.format.is_some() + || self.top.is_some() + || self.min_percent.is_some() + || self.host_time + || self.no_host_time + || self.host_perf + || self.host_perf_events.is_some() + || self.qperf_metrics + || !self.qemu_args.is_empty() + || self.flamegraph + || self.flamegraph_kind.is_some() + || self.full_stack + || self.callchain.is_some() + || self.debuginfo + || self.force_frame_pointers + || self.demangle + || self.no_truncate + || self.symbol_style.is_some() + || self.focus.is_some() + } +} + +fn perf_args_from_qemu(args: ArgsQemu) -> anyhow::Result { + if args.qemu_config.is_some() || args.rootfs.is_some() { + anyhow::bail!( + "cargo starry run --perf currently uses the default StarryOS qperf QEMU/rootfs flow; \ + --qemu-config and --rootfs are not supported with --perf yet" + ); + } + if args.build.config.is_some() || args.build.target.is_some() || args.build.smp.is_some() { + anyhow::bail!( + "cargo starry run --perf currently supports --arch and --debug build overrides; use \ + cargo starry perf for the default qperf path or plain cargo starry qemu for custom \ + --config/--target/--smp runs" + ); + } + let perf = args.perf; + Ok(ArgsPerf { + case: perf.case.unwrap_or_else(|| "boot".to_string()), + arch: args.build.arch, + freq: perf.freq.unwrap_or(99), + out: None, + output_dir: perf.output_dir, + format: perf.format.unwrap_or(PerfFormat::All), + max_depth: perf.max_depth.unwrap_or(128), + timeout: perf.timeout.unwrap_or(20), + mode: perf.mode.unwrap_or(PerfMode::Tb), + top: perf.top.unwrap_or(80), + min_percent: perf.min_percent.unwrap_or(0.3), + debug: args.build.debug, + kernel_filter: false, + host_time: perf.host_time, + no_host_time: perf.no_host_time, + host_perf: perf.host_perf, + host_perf_events: perf.host_perf_events.unwrap_or_else(|| { + "task-clock,cycles,instructions,cache-references,cache-misses,context-switches,\ + cpu-migrations,page-faults" + .to_string() + }), + shell_init_cmd: perf.workload, + shell_prefix: perf.shell_prefix, + qemu_args: perf.qemu_args, + start_marker: perf.start_marker, + stop_marker: perf.stop_marker, + workload_timeout: perf.workload_timeout, + qperf_metrics: perf.qperf_metrics, + flamegraph: perf.flamegraph, + flamegraph_kind: perf.flamegraph_kind.unwrap_or(PerfFlamegraphKind::Svg), + full_stack: perf.full_stack, + callchain: perf.callchain, + debuginfo: perf.debuginfo, + force_frame_pointers: perf.force_frame_pointers, + demangle: perf.demangle, + no_truncate: perf.no_truncate, + include_kernel_symbols: true, + include_user_symbols: false, + symbol_style: perf.symbol_style.unwrap_or(PerfSymbolStyle::Full), + focus: perf.focus, + }) +} + impl Starry { pub fn new() -> anyhow::Result { let app = AppContext::new()?; @@ -189,6 +512,12 @@ impl Starry { } async fn qemu(&mut self, args: ArgsQemu) -> anyhow::Result<()> { + if args.perf.perf { + return self.perf(perf_args_from_qemu(args)?).await; + } + if args.perf.has_overrides() { + anyhow::bail!("--perf-* options require --perf"); + } let request = self.prepare_request( (&args.build).into(), args.qemu_config, @@ -686,6 +1015,143 @@ mod tests { } } + #[test] + fn command_parses_perf_workload_options() { + #[derive(Parser)] + struct Cli { + #[command(subcommand)] + command: Command, + } + + let cli = Cli::try_parse_from([ + "starry", + "perf", + "--arch", + "riscv64", + "--shell-init-cmd", + "echo qperf", + "--shell-prefix", + "root@starry:", + "--host-time", + "--host-perf", + "--host-perf-events", + "task-clock,instructions", + "--qemu-arg=-device", + "--qemu-arg=vhost-vsock-pci,guest-cid=3", + "--start-marker", + "QPERF_BEGIN", + "--stop-marker", + "QPERF_END", + "--workload-timeout", + "5", + "--qperf-metrics", + ]) + .unwrap(); + + match cli.command { + Command::Perf(args) => { + assert_eq!(args.arch.as_deref(), Some("riscv64")); + assert_eq!(args.shell_init_cmd.as_deref(), Some("echo qperf")); + assert_eq!(args.shell_prefix.as_deref(), Some("root@starry:")); + assert!(args.host_time); + assert!(args.host_perf); + assert_eq!(args.host_perf_events, "task-clock,instructions"); + assert_eq!( + args.qemu_args, + vec!["-device", "vhost-vsock-pci,guest-cid=3"] + ); + assert_eq!(args.start_marker.as_deref(), Some("QPERF_BEGIN")); + assert_eq!(args.stop_marker.as_deref(), Some("QPERF_END")); + assert_eq!(args.workload_timeout, Some(5)); + assert!(args.qperf_metrics); + } + _ => panic!("expected perf command"), + } + } + + #[test] + fn command_parses_perf_flamegraph_options() { + #[derive(Parser)] + struct Cli { + #[command(subcommand)] + command: Command, + } + + let cli = Cli::try_parse_from([ + "starry", + "perf", + "--case", + "blk-read", + "--workload", + "echo qperf", + "--flamegraph-kind", + "html", + "--full-stack", + "--no-truncate", + "--symbol-style", + "module", + "--focus", + "virtio|VirtQueue", + "--min-percent", + "0", + ]) + .unwrap(); + + match cli.command { + Command::Perf(args) => { + assert_eq!(args.case, "blk-read"); + assert_eq!(args.shell_init_cmd.as_deref(), Some("echo qperf")); + assert_eq!(args.flamegraph_kind, PerfFlamegraphKind::Html); + assert!(args.full_stack); + assert!(args.no_truncate); + assert_eq!(args.symbol_style, PerfSymbolStyle::Module); + assert_eq!(args.focus.as_deref(), Some("virtio|VirtQueue")); + assert_eq!(args.min_percent, 0.0); + } + _ => panic!("expected perf command"), + } + } + + #[test] + fn command_parses_run_perf_alias() { + #[derive(Parser)] + struct Cli { + #[command(subcommand)] + command: Command, + } + + let cli = Cli::try_parse_from([ + "starry", + "run", + "--arch", + "riscv64", + "--perf", + "--perf-case", + "net-wget", + "--perf-workload", + "echo qperf", + "--perf-qperf-metrics", + "--perf-symbol-style", + "short", + "--perf-focus", + "memcpy|memmove", + ]) + .unwrap(); + + match cli.command { + Command::Qemu(args) => { + assert_eq!(args.build.arch.as_deref(), Some("riscv64")); + assert!(args.perf.perf); + assert_eq!(args.perf.case.as_deref(), Some("net-wget")); + assert_eq!(args.perf.workload.as_deref(), Some("echo qperf")); + assert!(args.perf.qperf_metrics); + assert_eq!(args.perf.symbol_style, Some(PerfSymbolStyle::Short)); + assert_eq!(args.perf.focus.as_deref(), Some("memcpy|memmove")); + } + _ => panic!("expected qemu command"), + } + } + #[test] fn command_parses_test_board() { #[derive(Parser)] diff --git a/scripts/axbuild/src/starry/perf.rs b/scripts/axbuild/src/starry/perf.rs index 2351d0f643..965369dbc0 100644 --- a/scripts/axbuild/src/starry/perf.rs +++ b/scripts/axbuild/src/starry/perf.rs @@ -1,21 +1,31 @@ use std::{ - env, fs, + env, + ffi::OsString, + fs, fs::File, - io::{BufRead, BufReader, Write}, + io::{BufRead, BufReader, Read, Write}, path::{Path, PathBuf}, process::{Command, ExitStatus, Stdio}, + sync::mpsc, + thread, + time::{Duration, Instant}, }; use anyhow::{Context, bail}; +use object::{Object, ObjectSection}; +use ostool::build::config::Cargo; use serde::{Deserialize, Serialize}; -use super::{ArgsBuild, ArgsPerf, PerfFormat, Starry, build, rootfs}; +use super::{ + ArgsBuild, ArgsPerf, PerfCallchain, PerfFlamegraphKind, PerfFormat, Starry, build, rootfs, +}; use crate::{ context::{SnapshotPersistence, StarryCliArgs, starry_target_for_arch_checked}, support::process::ProcessExt, }; const QPERF_QUEUE_SIZE: usize = 4096; +const DEFAULT_STARRY_SHELL_PREFIX: &str = "root@starry:"; #[derive(Deserialize, Serialize)] struct PerfQemuConfig { @@ -27,6 +37,9 @@ struct PerfQemuConfig { shell_prefix: Option, shell_init_cmd: Option, timeout: Option, + start_marker: Option, + stop_marker: Option, + workload_timeout: Option, } struct QperfTools { @@ -35,12 +48,105 @@ struct QperfTools { } struct PerfOutputs { + work_dir: PathBuf, dir: PathBuf, raw: PathBuf, folded: PathBuf, flamegraph: PathBuf, + folded_boot: PathBuf, + flamegraph_boot: PathBuf, + folded_workload: PathBuf, + flamegraph_workload: PathBuf, + folded_post: PathBuf, + flamegraph_post: PathBuf, + folded_focus: PathBuf, + flamegraph_focus: PathBuf, + stack_depth_summary: PathBuf, + flamegraph_html: PathBuf, summary: PathBuf, qemu_config: PathBuf, + host_time: PathBuf, + host_perf: PathBuf, + resolve_stats: PathBuf, + window: PathBuf, + qmp_socket: PathBuf, + profile_stdout: PathBuf, + profile_stderr: PathBuf, + report_json: PathBuf, + report_md: PathBuf, + hotspots_csv: PathBuf, + hotspot_categories_csv: PathBuf, +} + +#[derive(Default, Serialize)] +struct PerfWindowReport { + enabled: bool, + start_marker: Option, + stop_marker: Option, + start_time: Option, + stop_time: Option, + duration_sec: Option, + workload_timeout: Option, + truncated_by_timeout: bool, + boot_samples_excluded: Option, + stop_requested: bool, + stop_method: Option, + warnings: Vec, + method: String, +} + +struct QemuRun { + status: ExitStatus, + window: PerfWindowReport, +} + +#[derive(Clone, Copy, Default)] +struct ChildResourceUsage { + user_micros: i128, + system_micros: i128, + major_faults: i128, + minor_faults: i128, + voluntary_context_switches: i128, + involuntary_context_switches: i128, +} + +impl ChildResourceUsage { + fn delta_since(self, before: Self) -> Self { + Self { + user_micros: nonnegative_delta(self.user_micros, before.user_micros), + system_micros: nonnegative_delta(self.system_micros, before.system_micros), + major_faults: nonnegative_delta(self.major_faults, before.major_faults), + minor_faults: nonnegative_delta(self.minor_faults, before.minor_faults), + voluntary_context_switches: nonnegative_delta( + self.voluntary_context_switches, + before.voluntary_context_switches, + ), + involuntary_context_switches: nonnegative_delta( + self.involuntary_context_switches, + before.involuntary_context_switches, + ), + } + } + + fn user_seconds(self) -> f64 { + self.user_micros as f64 / 1_000_000.0 + } + + fn system_seconds(self) -> f64 { + self.system_micros as f64 / 1_000_000.0 + } +} + +#[derive(Clone, Copy)] +struct AddressRange { + start: u64, + end: u64, +} + +#[derive(Clone, Copy)] +struct KernelTextRange { + virt: AddressRange, + phys: Option, } pub(super) async fn run(starry: &mut Starry, args: ArgsPerf) -> anyhow::Result<()> { @@ -50,16 +156,29 @@ pub(super) async fn run(starry: &mut Starry, args: ArgsPerf) -> anyhow::Result<( .clone() .unwrap_or_else(|| crate::context::DEFAULT_STARRY_ARCH.to_string()); let target = starry_target_for_arch_checked(&arch)?.to_string(); - let outputs = prepare_outputs(starry.app.workspace_root(), &arch, args.out.as_deref())?; + let outputs = prepare_outputs( + starry.app.workspace_root(), + &arch, + &args.case, + args.out.as_deref(), + args.output_dir.as_deref(), + )?; + let _axbuild_tmp_dir = set_env_if_missing( + "AXBUILD_TMP_DIR", + outputs.work_dir.join("axbuild-tmp").into_os_string(), + )?; + let generate_svg = args.flamegraph + || matches!(args.format, PerfFormat::Svg | PerfFormat::All) + && !matches!(args.flamegraph_kind, PerfFlamegraphKind::Folded); - let tools = build_qperf_tools(starry.app.workspace_root())?; + let tools = build_qperf_tools(starry.app.workspace_root(), generate_svg)?; let build_args = ArgsBuild { config: None, arch: Some(arch.clone()), target: None, smp: None, - debug: true, + debug: args.debug, }; let request = starry.prepare_request( StarryCliArgs::from(&build_args), @@ -68,48 +187,130 @@ pub(super) async fn run(starry: &mut Starry, args: ArgsPerf) -> anyhow::Result<( SnapshotPersistence::Store, )?; - let cargo = build::load_cargo_config(&request)?; - starry.app.set_debug_mode(true)?; + let mut cargo = build::load_cargo_config(&request)?; + apply_perf_cargo_features(&mut cargo, &args); + starry.app.set_debug_mode(args.debug)?; starry .app .build(cargo, request.build_info_path.clone()) .await?; rootfs::ensure_qemu_rootfs_ready(&request, starry.app.workspace_root(), None).await?; - let cargo = build::load_cargo_config(&request)?; + let mut cargo = build::load_cargo_config(&request)?; + apply_perf_cargo_features(&mut cargo, &args); let qemu = rootfs::load_patched_qemu_config(starry, &request, &cargo, None, true).await?; - write_qemu_config(&outputs, &tools, &args, qemu.args)?; + let elf = kernel_elf_path(starry.app.workspace_root(), &target, args.debug); + let axconfig_path = cargo.env.get("AX_CONFIG_PATH").map(PathBuf::from); + let text_range = detect_kernel_text_range(&elf, axconfig_path.as_deref())?; + write_qemu_config(&outputs, &tools, &args, &arch, qemu.args, text_range)?; - let kernel_bin = kernel_bin_path(starry.app.workspace_root(), &target); - let qemu_status = run_qemu_direct(&outputs, &args, &arch, &kernel_bin)?; - if !qemu_status.success() { + let kernel_bin = kernel_bin_path(starry.app.workspace_root(), &target, args.debug); + let qemu_run = run_qemu_direct(&outputs, &args, &arch, &kernel_bin)?; + if !qemu_run.status.success() { if !file_nonempty(&outputs.raw) { - bail!("qperf QEMU run failed before producing samples: {qemu_status}"); + bail!( + "qperf QEMU run failed before producing samples: {}", + qemu_run.status + ); } - eprintln!("qperf: QEMU ended with {qemu_status} after producing samples"); + eprintln!( + "qperf: QEMU ended with {} after producing samples", + qemu_run.status + ); } - let elf = kernel_elf_path(starry.app.workspace_root(), &target); - run_analyzer(&tools.analyzer, &elf, &outputs.raw, &outputs.folded)?; + run_analyzer(AnalyzerRun { + analyzer: &tools.analyzer, + elf: &elf, + raw: &outputs.raw, + folded: &outputs.folded, + flamegraph: &outputs.flamegraph, + resolve_stats: &outputs.resolve_stats, + depth_summary: Some(&outputs.stack_depth_summary), + generate_svg, + top_n: args.top, + start_sec: qemu_run.window.start_time, + stop_sec: qemu_run.window.stop_time, + symbol_style: args.symbol_style.to_string(), + demangle: true, + focus: None, + min_percent: flamegraph_min_percent(&args), + })?; + + generate_phase_flamegraphs( + &tools, + &elf, + &outputs, + &args, + &qemu_run.window, + generate_svg, + )?; + generate_focus_flamegraph(&tools, &elf, &outputs, &args, generate_svg)?; - let flamegraph_generated = if matches!(args.format, PerfFormat::Svg | PerfFormat::All) { + let flamegraph_generated = if generate_svg && !file_nonempty(&outputs.flamegraph) { try_generate_flamegraph(&outputs.folded, &outputs.flamegraph)? } else { - false + generate_svg && file_nonempty(&outputs.flamegraph) }; - write_summary( - &outputs, - &tools, - &elf, - &arch, - &target, - &args, + write_summary(SummaryInputs { + outputs: &outputs, + tools: &tools, + elf: &elf, + arch: &arch, + target: &target, + args: &args, flamegraph_generated, - )?; - print_report(&outputs, flamegraph_generated); + window: &qemu_run.window, + })?; + write_flamegraph_html(&outputs, args.flamegraph_kind, flamegraph_generated)?; + run_report_postprocess(&outputs, &args, &arch, exit_status_code(&qemu_run.status))?; + print_report(&outputs, &args); Ok(()) } +fn apply_perf_cargo_features(cargo: &mut Cargo, args: &ArgsPerf) { + cargo.features.extend([ + "ax-driver/virtio-blk".to_string(), + "ax-driver/virtio-net".to_string(), + "ax-driver/virtio-socket".to_string(), + ]); + if args.qperf_metrics { + cargo.features.push("qperf-metrics".to_string()); + } + cargo.features.sort(); + cargo.features.dedup(); + if perf_needs_debuginfo(args) { + cargo.env.insert("DWARF".to_string(), "y".to_string()); + } + if perf_needs_frame_pointers(args) { + cargo.env.insert("BACKTRACE".to_string(), "y".to_string()); + } + apply_perf_rustflags(cargo, args); +} + +fn apply_perf_rustflags(cargo: &mut Cargo, args: &ArgsPerf) { + let mut flags = Vec::new(); + if perf_needs_debuginfo(args) { + flags.push("-Cdebuginfo=2".to_string()); + flags.push("-Cstrip=none".to_string()); + } + if perf_needs_frame_pointers(args) { + flags.push("-Cforce-frame-pointers=yes".to_string()); + } + if flags.is_empty() { + return; + } + + cargo + .env + .insert("CARGO_ENCODED_RUSTFLAGS".to_string(), flags.join("\x1f")); + cargo.args.push("--config".to_string()); + let rustflags = toml::Value::Array(flags.into_iter().map(toml::Value::String).collect()); + cargo + .args + .push(format!("target.'{}'.rustflags={rustflags}", cargo.target)); +} + fn validate_args(args: &ArgsPerf) -> anyhow::Result<()> { if args.freq == 0 { bail!("--freq must be greater than 0"); @@ -117,33 +318,221 @@ fn validate_args(args: &ArgsPerf) -> anyhow::Result<()> { if args.max_depth == 0 { bail!("--max-depth must be greater than 0"); } + if args.min_percent < 0.0 { + bail!("--min-percent must be non-negative"); + } if matches!(args.format, PerfFormat::Pprof) { bail!("--format pprof is not supported yet; use --format folded, svg, or all"); } + if args + .shell_init_cmd + .as_deref() + .is_some_and(|cmd| cmd.trim().is_empty()) + { + bail!("--shell-init-cmd must not be empty"); + } + if args + .shell_prefix + .as_deref() + .is_some_and(|prefix| prefix.is_empty()) + { + bail!("--shell-prefix must not be empty"); + } + if args.host_perf && args.host_perf_events.trim().is_empty() { + bail!("--host-perf-events must not be empty when --host-perf is set"); + } + if matches!(effective_callchain(args), PerfCallchain::Logical) { + bail!( + "--perf-callchain logical is not implemented yet; use --perf-callchain fp or \ + --full-stack for frame-pointer unwinding" + ); + } + if args.include_user_symbols { + eprintln!( + "qperf: --include-user-symbols requested, but current analyzer resolves only the \ + StarryOS kernel ELF; user symbols will remain unresolved unless they are present in \ + the kernel image" + ); + } + if args + .start_marker + .as_deref() + .is_some_and(|marker| marker.trim().is_empty()) + { + bail!("--start-marker must not be empty"); + } + if args + .stop_marker + .as_deref() + .is_some_and(|marker| marker.trim().is_empty()) + { + bail!("--stop-marker must not be empty"); + } + if args.workload_timeout == Some(0) { + bail!("--workload-timeout must be greater than 0"); + } Ok(()) } -fn prepare_outputs(root: &Path, arch: &str, out: Option<&Path>) -> anyhow::Result { - let dir = out.map(PathBuf::from).unwrap_or_else(|| { - root.join("target") - .join("qperf") - .join(arch) - .join(chrono::Utc::now().format("%Y%m%d-%H%M%S").to_string()) - }); +fn host_time_enabled(args: &ArgsPerf) -> bool { + args.host_time || !args.no_host_time +} + +fn flamegraph_min_percent(args: &ArgsPerf) -> f64 { + if args.no_truncate { + 0.0 + } else { + args.min_percent + } +} + +fn effective_max_depth(args: &ArgsPerf) -> usize { + if args.full_stack { + args.max_depth.max(256) + } else { + args.max_depth + } +} + +fn effective_callchain(args: &ArgsPerf) -> PerfCallchain { + if args.full_stack { + PerfCallchain::Fp + } else { + args.callchain.unwrap_or(PerfCallchain::Leaf) + } +} + +fn perf_needs_debuginfo(args: &ArgsPerf) -> bool { + args.full_stack || args.debuginfo +} + +fn perf_needs_frame_pointers(args: &ArgsPerf) -> bool { + args.full_stack + || args.force_frame_pointers + || matches!(effective_callchain(args), PerfCallchain::Fp) +} + +struct ScopedEnvVar { + key: &'static str, + previous: Option, + active: bool, +} + +impl Drop for ScopedEnvVar { + fn drop(&mut self) { + if !self.active { + return; + } + match &self.previous { + Some(value) => { + // SAFETY: qperf runs this CLI flow serially and restores the process + // environment before returning to the caller. + unsafe { env::set_var(self.key, value) }; + } + None => { + // SAFETY: qperf runs this CLI flow serially and restores the process + // environment before returning to the caller. + unsafe { env::remove_var(self.key) }; + } + } + } +} + +fn set_env_if_missing(key: &'static str, value: OsString) -> anyhow::Result { + let previous = env::var_os(key); + if previous.as_ref().is_some_and(|value| !value.is_empty()) { + return Ok(ScopedEnvVar { + key, + previous, + active: false, + }); + } + let path = PathBuf::from(&value); + fs::create_dir_all(&path) + .with_context(|| format!("failed to create {key} directory {}", path.display()))?; + // SAFETY: qperf runs this CLI flow serially before spawning worker threads that depend on + // axbuild paths. + unsafe { env::set_var(key, &value) }; + Ok(ScopedEnvVar { + key, + previous, + active: true, + }) +} + +fn prepare_outputs( + root: &Path, + arch: &str, + case: &str, + out: Option<&Path>, + output_dir: Option<&Path>, +) -> anyhow::Result { + let (work_dir, dir) = if let Some(out) = out { + let dir = PathBuf::from(out); + let work_dir = dir + .parent() + .map(Path::to_path_buf) + .unwrap_or_else(|| dir.clone()); + (work_dir, dir) + } else { + let output_root = output_dir + .map(PathBuf::from) + .unwrap_or_else(|| root.join("target").join("qperf").join(case)); + let work_dir = output_root.join("perf").join(arch).join("latest"); + let dir = work_dir.join("qperf"); + (work_dir, dir) + }; + if out.is_none() && work_dir.exists() { + fs::remove_dir_all(&work_dir).with_context(|| { + format!( + "failed to remove previous qperf output directory {}", + work_dir.display() + ) + })?; + } fs::create_dir_all(&dir) .with_context(|| format!("failed to create qperf output directory {}", dir.display()))?; + fs::create_dir_all(&work_dir).with_context(|| { + format!( + "failed to create qperf work directory {}", + work_dir.display() + ) + })?; Ok(PerfOutputs { + work_dir: work_dir.clone(), raw: dir.join("qperf.bin"), folded: dir.join("stack.folded"), flamegraph: dir.join("flamegraph.svg"), + folded_boot: dir.join("stack.boot.folded"), + flamegraph_boot: dir.join("flamegraph.boot.svg"), + folded_workload: dir.join("stack.workload.folded"), + flamegraph_workload: dir.join("flamegraph.workload.svg"), + folded_post: dir.join("stack.post.folded"), + flamegraph_post: dir.join("flamegraph.post.svg"), + folded_focus: dir.join("stack.focus.folded"), + flamegraph_focus: dir.join("flamegraph.focus.svg"), + stack_depth_summary: dir.join("stack-depth-summary.csv"), + flamegraph_html: dir.join("flamegraph.html"), summary: dir.join("summary.txt"), qemu_config: dir.join("qemu.toml"), + host_time: dir.join("qemu.time.txt"), + host_perf: dir.join("qemu.perf.csv"), + resolve_stats: dir.join("resolve.stats.json"), + window: dir.join("window.json"), + qmp_socket: dir.join("qmp.sock"), + profile_stdout: work_dir.join("profile.stdout"), + profile_stderr: work_dir.join("profile.stderr"), + report_json: work_dir.join("report.json"), + report_md: work_dir.join("report.md"), + hotspots_csv: work_dir.join("hotspots.csv"), + hotspot_categories_csv: work_dir.join("hotspot_categories.csv"), dir, }) } -fn build_qperf_tools(root: &Path) -> anyhow::Result { +fn build_qperf_tools(root: &Path, analyzer_flamegraph: bool) -> anyhow::Result { let manifest = root.join("tools/qperf/Cargo.toml"); + let target_dir = root.join("tools/qperf/target"); if !manifest.exists() { bail!( "qperf sources not found at {}; expected tools/qperf to be present", @@ -156,18 +545,27 @@ fn build_qperf_tools(root: &Path) -> anyhow::Result { .args(["build", "--manifest-path"]) .arg(&manifest) .arg("--release") + .arg("--target-dir") + .arg(&target_dir) .exec() .context("failed to build qperf plugin")?; - Command::new("cargo") + let mut analyzer_build = Command::new("cargo"); + analyzer_build .current_dir(root) .args(["build", "--manifest-path"]) - .arg(&manifest) - .args(["--release", "-p", "qperf-analyzer"]) + .arg(root.join("tools/qperf/analyzer/Cargo.toml")) + .arg("--release") + .arg("--target-dir") + .arg(&target_dir); + if analyzer_flamegraph { + analyzer_build.args(["--features", "flamegraph"]); + } + analyzer_build .exec() .context("failed to build qperf-analyzer")?; - let release_dir = root.join("tools/qperf/target/release"); + let release_dir = target_dir.join("release"); let tools = QperfTools { plugin: release_dir.join("libqperf.so"), analyzer: release_dir.join("qperf-analyzer"), @@ -181,88 +579,984 @@ fn write_qemu_config( outputs: &PerfOutputs, tools: &QperfTools, args: &ArgsPerf, + arch: &str, qemu_args: Vec, + text_range: Option, ) -> anyhow::Result<()> { let mut perf_qemu_args = vec!["-plugin".to_string()]; - perf_qemu_args.push(format!( - "{},freq={},max_depth={},queue_size={},out={}", + let mut plugin_params = format!( + "{},freq={},max_depth={},queue_size={},mode={},callchain={},out={}", tools.plugin.display(), args.freq, - args.max_depth, + effective_max_depth(args), QPERF_QUEUE_SIZE, + args.mode, + effective_callchain(args), outputs.raw.display() + ); + plugin_params.push_str(&format!( + ",filter_kernel={}", + if args.kernel_filter { 1 } else { 0 } )); + if let Some(range) = text_range { + let start = range.virt.start; + let end = range.virt.end; + plugin_params.push_str(&format!(",filter_start=0x{start:x},filter_end=0x{end:x}")); + if let Some(phys) = range.phys { + let offset = range.virt.start.wrapping_sub(phys.start); + plugin_params.push_str(&format!( + ",filter_alias_start=0x{:x},filter_alias_end=0x{:x},filter_alias_offset=0x{:x}", + phys.start, phys.end, offset + )); + } + } + perf_qemu_args.push(plugin_params); + let mut qemu_args = direct_qemu_args(arch, qemu_args)?; + qemu_args.extend(args.qemu_args.iter().cloned()); + if qemu_stdout_monitor_enabled(args) && !has_qemu_option(&qemu_args, "-qmp") { + qemu_args.extend([ + "-qmp".to_string(), + format!("unix:{},server=on,wait=off", outputs.qmp_socket.display()), + ]); + } perf_qemu_args.extend(qemu_args); + let shell_init_cmd = args + .shell_init_cmd + .as_deref() + .map(str::trim) + .filter(|cmd| !cmd.is_empty()) + .map(str::to_string); + let shell_prefix = shell_init_cmd.as_ref().map(|_| { + args.shell_prefix + .clone() + .unwrap_or_else(|| DEFAULT_STARRY_SHELL_PREFIX.to_string()) + }); + let config = PerfQemuConfig { args: perf_qemu_args, uefi: false, to_bin: true, success_regex: Vec::new(), fail_regex: vec![r"(?i)\bpanic(?:ked)?\b".to_string()], - shell_prefix: None, - shell_init_cmd: None, + shell_prefix, + shell_init_cmd, timeout: (args.timeout > 0).then_some(args.timeout), + start_marker: args.start_marker.clone(), + stop_marker: args.stop_marker.clone(), + workload_timeout: args.workload_timeout, }; fs::write(&outputs.qemu_config, toml::to_string_pretty(&config)?) .with_context(|| format!("failed to write {}", outputs.qemu_config.display()))?; Ok(()) } +fn direct_qemu_args(arch: &str, mut args: Vec) -> anyhow::Result> { + match arch { + "riscv64" | "loongarch64" => { + if !has_qemu_option(&args, "-machine") { + args.splice(0..0, ["-machine".to_string(), "virt".to_string()]); + } + } + _ => bail!("qperf currently supports StarryOS riscv64 and loongarch64 only"), + } + Ok(args) +} + +fn has_qemu_option(args: &[String], option: &str) -> bool { + args.iter().any(|arg| arg == option) +} + fn run_qemu_direct( outputs: &PerfOutputs, args: &ArgsPerf, arch: &str, kernel_bin: &Path, -) -> anyhow::Result { +) -> anyhow::Result { ensure_file(kernel_bin, "StarryOS kernel image")?; let qemu = qemu_executable(arch)?; - let qemu_args = qemu_args_from_config(&outputs.qemu_config)?; + let config = qemu_config_from_path(&outputs.qemu_config)?; + let qemu_args = config.args.clone(); + let monitor_stdout = qemu_stdout_monitor_enabled(args); - let mut command = if args.timeout > 0 { - let mut command = Command::new("timeout"); - command.arg(format!("{}s", args.timeout)); - command.arg(qemu); - command + let mut command_args = if args.timeout > 0 && !monitor_stdout { + vec![ + "timeout".to_string(), + "--signal=INT".to_string(), + "--kill-after=5s".to_string(), + format!("{}s", args.timeout), + qemu.to_string(), + ] } else { - Command::new(qemu) + vec![qemu.to_string()] }; + command_args.extend(qemu_args); + command_args.push("-kernel".to_string()); + command_args.push(kernel_bin.display().to_string()); + + if args.host_perf { + if let Some(perf) = find_executable("perf") { + let mut wrapped = vec![ + perf.display().to_string(), + "stat".to_string(), + "-x".to_string(), + ",".to_string(), + "-o".to_string(), + outputs.host_perf.display().to_string(), + "-e".to_string(), + args.host_perf_events.clone(), + "--".to_string(), + ]; + wrapped.extend(command_args); + command_args = wrapped; + } else { + write_host_perf_unavailable(&outputs.host_perf, "perf not found in PATH")?; + eprintln!("qperf: --host-perf requested but `perf` was not found in PATH"); + } + } - command.args(qemu_args).arg("-kernel").arg(kernel_bin); + let mut command = Command::new(&command_args[0]); + command.args(&command_args[1..]); eprintln!("running qperf QEMU: {command:?}"); - command.status().context("failed to spawn QEMU") + let host_wall_start = Instant::now(); + let host_usage_start = child_resource_usage(); + let qemu_run = if monitor_stdout { + run_qemu_with_stdout_monitor(command, &config, outputs, args.timeout)? + } else { + QemuRun { + status: command.status().context("failed to spawn QEMU")?, + window: window_report_from_config(&config), + } + }; + if host_time_enabled(args) { + write_host_time_metrics( + &outputs.host_time, + host_wall_start.elapsed(), + host_usage_start, + child_resource_usage(), + &qemu_run.status, + )?; + } + write_window_report(&outputs.window, &qemu_run.window)?; + if !outputs.profile_stdout.exists() { + File::create(&outputs.profile_stdout) + .with_context(|| format!("failed to create {}", outputs.profile_stdout.display()))?; + } + if !outputs.profile_stderr.exists() { + File::create(&outputs.profile_stderr) + .with_context(|| format!("failed to create {}", outputs.profile_stderr.display()))?; + } + Ok(qemu_run) } fn qemu_executable(arch: &str) -> anyhow::Result<&'static str> { - match arch { - "riscv64" => Ok("qemu-system-riscv64"), - "loongarch64" => Ok("qemu-system-loongarch64"), + let name = match arch { + "riscv64" => "qemu-system-riscv64", + "loongarch64" => "qemu-system-loongarch64", _ => bail!("qperf currently supports StarryOS riscv64 and loongarch64 only"), + }; + if find_executable(name).is_none() { + bail!( + "qperf requires `{name}` in PATH; install the matching QEMU system emulator or run \ + the Docker-based harness perf-profile entrypoint" + ); } + Ok(name) } -fn qemu_args_from_config(path: &Path) -> anyhow::Result> { +fn qemu_config_from_path(path: &Path) -> anyhow::Result { let text = fs::read_to_string(path) .with_context(|| format!("failed to read qperf QEMU config {}", path.display()))?; - let config: PerfQemuConfig = toml::from_str(&text) - .with_context(|| format!("failed to parse qperf QEMU config {}", path.display()))?; - Ok(config.args) + toml::from_str(&text) + .with_context(|| format!("failed to parse qperf QEMU config {}", path.display())) +} + +fn qemu_stdout_monitor_enabled(args: &ArgsPerf) -> bool { + args.shell_init_cmd + .as_deref() + .is_some_and(|cmd| !cmd.trim().is_empty()) + || args.start_marker.is_some() + || args.stop_marker.is_some() + || args.workload_timeout.is_some() +} + +fn window_report_from_config(config: &PerfQemuConfig) -> PerfWindowReport { + let enabled = config.start_marker.is_some() + || config.stop_marker.is_some() + || config.workload_timeout.is_some(); + let mut report = PerfWindowReport { + enabled, + start_marker: config.start_marker.clone(), + stop_marker: config.stop_marker.clone(), + workload_timeout: config.workload_timeout, + method: if enabled { + "qperf_raw_elapsed_timestamp_filter".to_string() + } else { + "disabled".to_string() + }, + ..PerfWindowReport::default() + }; + if enabled && config.start_marker.is_none() { + report + .warnings + .push("start marker is not configured; boot samples are not excluded".to_string()); + } + if config.workload_timeout.is_some() && config.start_marker.is_none() { + report + .warnings + .push("--workload-timeout requires a start marker to open the window".to_string()); + } + report +} + +fn run_qemu_with_stdout_monitor( + mut command: Command, + config: &PerfQemuConfig, + outputs: &PerfOutputs, + overall_timeout: u64, +) -> anyhow::Result { + let mut window_report = window_report_from_config(config); + let shell_init_cmd = config + .shell_init_cmd + .as_deref() + .map(str::trim) + .filter(|cmd| !cmd.is_empty()); + if shell_init_cmd.is_some() { + command.stdin(Stdio::piped()); + } + command.stdout(Stdio::piped()); + let mut child = command.spawn().context("failed to spawn QEMU")?; + let mut stdin = child.stdin.take(); + let stdout = child.stdout.take().context("failed to open QEMU stdout")?; + let (tx, rx) = mpsc::channel(); + thread::spawn(move || { + let mut stdout = BufReader::new(stdout); + let mut buf = [0_u8; 1024]; + loop { + match stdout.read(&mut buf) { + Ok(0) => break, + Ok(len) => { + if tx.send(buf[..len].to_vec()).is_err() { + break; + } + } + Err(_) => break, + } + } + }); + + let started = Instant::now(); + let mut host_stdout = std::io::stdout().lock(); + let mut profile_stdout = File::create(&outputs.profile_stdout) + .with_context(|| format!("failed to create {}", outputs.profile_stdout.display()))?; + let mut prompt_window = Vec::new(); + let mut marker_window = Vec::new(); + let mut injected = false; + let mut echo_disable_deadline = None; + let shell_prefix = config + .shell_prefix + .as_deref() + .unwrap_or(DEFAULT_STARRY_SHELL_PREFIX); + let prefix = shell_prefix.as_bytes(); + let start_marker = config.start_marker.as_deref().map(str::as_bytes); + let stop_marker = config.stop_marker.as_deref().map(str::as_bytes); + let marker_monitoring = start_marker.is_some() || stop_marker.is_some(); + + loop { + if let Some(status) = child.try_wait().context("failed to poll QEMU")? { + if shell_init_cmd.is_some() && !injected { + window_report.warnings.push(format!( + "shell prompt `{shell_prefix}` was not observed before QEMU exited" + )); + eprintln!( + "qperf: shell prompt `{shell_prefix}` was not observed before QEMU exited" + ); + } + finalize_window_warnings(&mut window_report); + return Ok(QemuRun { + status, + window: window_report, + }); + } + + match rx.recv_timeout(Duration::from_millis(50)) { + Ok(chunk) => { + profile_stdout + .write_all(&chunk) + .context("failed to write qperf profile stdout")?; + host_stdout + .write_all(&chunk) + .context("failed to forward QEMU stdout")?; + host_stdout.flush().ok(); + let elapsed = started.elapsed().as_secs_f64(); + + if let Some(cmd) = shell_init_cmd + && !injected + && echo_disable_deadline.is_none() + { + prompt_window.extend_from_slice(&chunk); + trim_window(&mut prompt_window, prefix.len().saturating_add(1024)); + if contains_subslice(&prompt_window, prefix) { + let stdin = stdin.as_mut().context("failed to open QEMU stdin")?; + if marker_monitoring { + stdin + .write_all(b"stty -echo 2>/dev/null || true\n") + .context("failed to disable shell echo before qperf command")?; + stdin.flush().ok(); + echo_disable_deadline = + Some(Instant::now() + Duration::from_millis(150)); + } else { + write_shell_init_command(stdin, cmd)?; + injected = true; + eprintln!( + "qperf: injected shell init command after prompt `{shell_prefix}`" + ); + } + } + } + + if start_marker.is_some() || stop_marker.is_some() { + marker_window.extend_from_slice(&chunk); + let keep = start_marker + .into_iter() + .chain(stop_marker) + .map(<[u8]>::len) + .max() + .unwrap_or(0) + .saturating_add(1024); + trim_window(&mut marker_window, keep); + } + + if window_report.start_time.is_none() + && start_marker.is_some_and(|marker| contains_subslice(&marker_window, marker)) + { + window_report.start_time = Some(elapsed); + eprintln!( + "qperf: observed start marker `{}` at {elapsed:.6}s", + config.start_marker.as_deref().unwrap_or("") + ); + } + if window_report.stop_time.is_none() + && stop_marker.is_some_and(|marker| contains_subslice(&marker_window, marker)) + { + window_report.stop_time = Some(elapsed); + update_window_duration(&mut window_report); + request_qemu_stop(&mut child, outputs, &mut window_report, "stop marker")?; + break; + } + } + Err(mpsc::RecvTimeoutError::Timeout) => {} + Err(mpsc::RecvTimeoutError::Disconnected) => {} + } + + if let (Some(cmd), Some(deadline)) = (shell_init_cmd, echo_disable_deadline) + && !injected + && Instant::now() >= deadline + { + let stdin = stdin.as_mut().context("failed to open QEMU stdin")?; + write_shell_init_command(stdin, cmd)?; + injected = true; + echo_disable_deadline = None; + eprintln!("qperf: injected shell init command after prompt `{shell_prefix}`"); + } + + let elapsed = started.elapsed().as_secs_f64(); + if let (Some(start_time), Some(timeout)) = + (window_report.start_time, config.workload_timeout) + && window_report.stop_time.is_none() + && elapsed - start_time >= timeout as f64 + { + window_report.stop_time = Some(elapsed); + window_report.truncated_by_timeout = true; + update_window_duration(&mut window_report); + window_report.warnings.push(format!( + "workload window timed out after {timeout}s without stop marker" + )); + request_qemu_stop(&mut child, outputs, &mut window_report, "workload timeout")?; + break; + } + if overall_timeout > 0 && elapsed >= overall_timeout as f64 { + window_report.warnings.push(format!( + "QEMU timed out after {overall_timeout}s before workload completed" + )); + request_qemu_stop(&mut child, outputs, &mut window_report, "overall timeout")?; + break; + } + } + + let status = wait_for_child_exit(&mut child, Duration::from_secs(20))?; + if shell_init_cmd.is_some() && !injected { + window_report.warnings.push(format!( + "shell prompt `{shell_prefix}` was not observed before QEMU exited" + )); + eprintln!("qperf: shell prompt `{shell_prefix}` was not observed before QEMU exited"); + } + finalize_window_warnings(&mut window_report); + Ok(QemuRun { + status, + window: window_report, + }) +} + +fn trim_window(window: &mut Vec, keep: usize) { + if window.len() > keep { + let drain = window.len() - keep; + window.drain(..drain); + } +} + +fn write_shell_init_command(stdin: &mut impl Write, cmd: &str) -> anyhow::Result<()> { + stdin + .write_all(cmd.as_bytes()) + .context("failed to write qperf shell init command")?; + stdin + .write_all(b"\n") + .context("failed to terminate qperf shell init command")?; + stdin.flush().ok(); + Ok(()) +} + +fn update_window_duration(report: &mut PerfWindowReport) { + report.duration_sec = match (report.start_time, report.stop_time) { + (Some(start), Some(stop)) if stop >= start => Some(stop - start), + _ => None, + }; +} + +fn request_qemu_stop( + child: &mut std::process::Child, + outputs: &PerfOutputs, + report: &mut PerfWindowReport, + reason: &str, +) -> anyhow::Result<()> { + if report.stop_requested { + return Ok(()); + } + report.stop_requested = true; + match request_qmp_quit(&outputs.qmp_socket) { + Ok(()) => { + report.stop_method = Some("qmp_quit".to_string()); + eprintln!("qperf: requested QEMU quit via QMP after {reason}"); + } + Err(err) => { + report.warnings.push(format!( + "QMP quit failed after {reason}: {err}; falling back to SIGINT" + )); + interrupt_child(child)?; + report.stop_method = Some("sigint".to_string()); + eprintln!("qperf: sent SIGINT to QEMU after {reason}"); + } + } + Ok(()) +} + +#[cfg(unix)] +fn request_qmp_quit(socket: &Path) -> anyhow::Result<()> { + use std::os::unix::net::UnixStream; + + let mut stream = UnixStream::connect(socket) + .with_context(|| format!("failed to connect QMP socket {}", socket.display()))?; + stream + .set_read_timeout(Some(Duration::from_millis(200))) + .ok(); + stream + .set_write_timeout(Some(Duration::from_millis(200))) + .ok(); + let mut buf = [0_u8; 512]; + let _ = stream.read(&mut buf); + stream.write_all(b"{\"execute\":\"qmp_capabilities\"}\r\n")?; + let _ = stream.read(&mut buf); + stream.write_all(b"{\"execute\":\"quit\"}\r\n")?; + stream.flush()?; + Ok(()) +} + +#[cfg(not(unix))] +fn request_qmp_quit(_socket: &Path) -> anyhow::Result<()> { + bail!("QMP unix sockets are not supported on this host") +} + +#[cfg(unix)] +fn interrupt_child(child: &mut std::process::Child) -> anyhow::Result<()> { + let pid = child.id() as libc::pid_t; + if unsafe { libc::kill(pid, libc::SIGINT) } == 0 { + Ok(()) + } else { + Err(std::io::Error::last_os_error()).context("failed to send SIGINT to QEMU") + } +} + +#[cfg(not(unix))] +fn interrupt_child(child: &mut std::process::Child) -> anyhow::Result<()> { + child.kill().context("failed to kill QEMU") +} + +fn wait_for_child_exit( + child: &mut std::process::Child, + timeout: Duration, +) -> anyhow::Result { + let deadline = Instant::now() + timeout; + loop { + if let Some(status) = child.try_wait().context("failed to poll QEMU after stop")? { + return Ok(status); + } + if Instant::now() >= deadline { + child.kill().context("failed to kill unresponsive QEMU")?; + return child.wait().context("failed to wait for killed QEMU"); + } + thread::sleep(Duration::from_millis(50)); + } +} + +fn finalize_window_warnings(report: &mut PerfWindowReport) { + if !report.enabled { + return; + } + if report.start_marker.is_some() && report.start_time.is_none() { + report + .warnings + .push("start marker was not observed; folded stacks include boot samples".to_string()); + } + if report.start_time.is_some() && report.stop_marker.is_some() && report.stop_time.is_none() { + report + .warnings + .push("stop marker was not observed; workload window extends to QEMU exit".to_string()); + } + update_window_duration(report); } -fn run_analyzer(analyzer: &Path, elf: &Path, raw: &Path, folded: &Path) -> anyhow::Result<()> { - ensure_file(elf, "StarryOS kernel ELF")?; - ensure_file(raw, "qperf raw samples")?; - Command::new(analyzer) +fn write_window_report(path: &Path, report: &PerfWindowReport) -> anyhow::Result<()> { + let text = serde_json::to_string_pretty(report).context("failed to serialize qperf window")?; + fs::write(path, text).with_context(|| format!("failed to write {}", path.display())) +} + +fn contains_subslice(haystack: &[u8], needle: &[u8]) -> bool { + needle.is_empty() + || haystack + .windows(needle.len()) + .any(|window| window == needle) +} + +fn write_host_time_metrics( + path: &Path, + elapsed: Duration, + usage_start: Option, + usage_end: Option, + status: &ExitStatus, +) -> anyhow::Result<()> { + let mut file = + File::create(path).with_context(|| format!("failed to create {}", path.display()))?; + let elapsed_seconds = elapsed.as_secs_f64(); + writeln!(file, "Elapsed time: {elapsed_seconds:.6}")?; + if let (Some(start), Some(end)) = (usage_start, usage_end) { + let usage = end.delta_since(start); + let user_seconds = usage.user_seconds(); + let system_seconds = usage.system_seconds(); + writeln!(file, "User time: {user_seconds:.6}")?; + writeln!(file, "System time: {system_seconds:.6}")?; + if elapsed_seconds > 0.0 { + let cpu_percent = (user_seconds + system_seconds) / elapsed_seconds * 100.0; + writeln!(file, "Percent of CPU this job got: {cpu_percent:.2}%")?; + } + writeln!(file, "Major page faults: {}", usage.major_faults)?; + writeln!(file, "Minor page faults: {}", usage.minor_faults)?; + writeln!( + file, + "Voluntary context switches: {}", + usage.voluntary_context_switches + )?; + writeln!( + file, + "Involuntary context switches: {}", + usage.involuntary_context_switches + )?; + } else { + writeln!(file, "User time: unavailable")?; + writeln!(file, "System time: unavailable")?; + } + writeln!(file, "Exit status: {}", exit_status_code(status))?; + Ok(()) +} + +fn write_host_perf_unavailable(path: &Path, reason: &str) -> anyhow::Result<()> { + let mut file = + File::create(path).with_context(|| format!("failed to create {}", path.display()))?; + writeln!(file, "# host perf unavailable: {reason}")?; + writeln!( + file, + "# host perf stat measures the host QEMU process; it is not a guest PMU counter" + )?; + Ok(()) +} + +fn exit_status_code(status: &ExitStatus) -> i32 { + status + .code() + .unwrap_or_else(|| if status.success() { 0 } else { 1 }) +} + +fn nonnegative_delta(after: i128, before: i128) -> i128 { + after.saturating_sub(before).max(0) +} + +#[cfg(unix)] +fn child_resource_usage() -> Option { + let mut usage = std::mem::MaybeUninit::::uninit(); + // SAFETY: getrusage initializes the provided rusage pointer when it returns 0. + if unsafe { libc::getrusage(libc::RUSAGE_CHILDREN, usage.as_mut_ptr()) } != 0 { + return None; + } + // SAFETY: getrusage returned success, so usage is initialized. + let usage = unsafe { usage.assume_init() }; + Some(ChildResourceUsage { + user_micros: timeval_micros(usage.ru_utime), + system_micros: timeval_micros(usage.ru_stime), + major_faults: usage.ru_majflt.into(), + minor_faults: usage.ru_minflt.into(), + voluntary_context_switches: usage.ru_nvcsw.into(), + involuntary_context_switches: usage.ru_nivcsw.into(), + }) +} + +#[cfg(unix)] +fn timeval_micros(value: libc::timeval) -> i128 { + i128::from(value.tv_sec) * 1_000_000 + i128::from(value.tv_usec) +} + +#[cfg(not(unix))] +fn child_resource_usage() -> Option { + None +} + +struct AnalyzerRun<'a> { + analyzer: &'a Path, + elf: &'a Path, + raw: &'a Path, + folded: &'a Path, + flamegraph: &'a Path, + resolve_stats: &'a Path, + depth_summary: Option<&'a Path>, + generate_svg: bool, + top_n: usize, + start_sec: Option, + stop_sec: Option, + symbol_style: String, + demangle: bool, + focus: Option<&'a str>, + min_percent: f64, +} + +fn run_analyzer(args: AnalyzerRun<'_>) -> anyhow::Result<()> { + ensure_file(args.elf, "StarryOS kernel ELF")?; + ensure_file(args.raw, "qperf raw samples")?; + let mut command = Command::new(args.analyzer); + command + .arg("resolve") .arg("-e") - .arg(elf) - .arg(raw) - .arg(folded) - .exec() - .context("failed to run qperf-analyzer")?; - ensure_file(folded, "folded stack output")?; + .arg(args.elf) + .arg(args.raw) + .arg(args.folded); + if args.top_n > 0 { + command.arg("--top").arg(args.top_n.to_string()); + } + if let Some(start_sec) = args.start_sec { + command.arg("--start-sec").arg(format!("{start_sec:.9}")); + } + if let Some(stop_sec) = args.stop_sec { + command.arg("--stop-sec").arg(format!("{stop_sec:.9}")); + } + command + .arg("--symbol-style") + .arg(&args.symbol_style) + .arg("--min-percent") + .arg(args.min_percent.to_string()); + if !args.demangle { + command.arg("--no-demangle"); + } + if let Some(focus) = args.focus { + command.arg("--focus").arg(focus); + } + command.arg("--stats").arg(args.resolve_stats); + if let Some(depth_summary) = args.depth_summary { + command.arg("--depth-summary").arg(depth_summary); + } + if args.generate_svg { + command.arg("--flamegraph").arg(args.flamegraph); + } + command.exec().context("failed to run qperf-analyzer")?; + if !args.folded.exists() { + bail!("folded stack output not found at {}", args.folded.display()); + } + Ok(()) +} + +fn generate_phase_flamegraphs( + tools: &QperfTools, + elf: &Path, + outputs: &PerfOutputs, + args: &ArgsPerf, + window: &PerfWindowReport, + generate_svg: bool, +) -> anyhow::Result<()> { + if window.start_time.is_some() && window.stop_time.is_some() { + fs::copy(&outputs.folded, &outputs.folded_workload).with_context(|| { + format!( + "failed to copy workload folded stack to {}", + outputs.folded_workload.display() + ) + })?; + if file_nonempty(&outputs.flamegraph) { + fs::copy(&outputs.flamegraph, &outputs.flamegraph_workload).with_context(|| { + format!( + "failed to copy workload flamegraph to {}", + outputs.flamegraph_workload.display() + ) + })?; + } + } + if let Some(start_sec) = window.start_time { + run_analyzer(AnalyzerRun { + analyzer: &tools.analyzer, + elf, + raw: &outputs.raw, + folded: &outputs.folded_boot, + flamegraph: &outputs.flamegraph_boot, + resolve_stats: &outputs + .resolve_stats + .with_file_name("resolve.boot.stats.json"), + depth_summary: Some( + &outputs + .stack_depth_summary + .with_file_name("stack-depth-summary.boot.csv"), + ), + generate_svg, + top_n: 0, + start_sec: None, + stop_sec: Some(start_sec), + symbol_style: args.symbol_style.to_string(), + demangle: true, + focus: None, + min_percent: flamegraph_min_percent(args), + })?; + } + if let Some(stop_sec) = window.stop_time { + run_analyzer(AnalyzerRun { + analyzer: &tools.analyzer, + elf, + raw: &outputs.raw, + folded: &outputs.folded_post, + flamegraph: &outputs.flamegraph_post, + resolve_stats: &outputs + .resolve_stats + .with_file_name("resolve.post.stats.json"), + depth_summary: Some( + &outputs + .stack_depth_summary + .with_file_name("stack-depth-summary.post.csv"), + ), + generate_svg, + top_n: 0, + start_sec: Some(stop_sec), + stop_sec: None, + symbol_style: args.symbol_style.to_string(), + demangle: true, + focus: None, + min_percent: flamegraph_min_percent(args), + })?; + } Ok(()) } +fn generate_focus_flamegraph( + tools: &QperfTools, + elf: &Path, + outputs: &PerfOutputs, + args: &ArgsPerf, + generate_svg: bool, +) -> anyhow::Result<()> { + let Some(focus) = args.focus.as_deref() else { + return Ok(()); + }; + run_analyzer(AnalyzerRun { + analyzer: &tools.analyzer, + elf, + raw: &outputs.raw, + folded: &outputs.folded_focus, + flamegraph: &outputs.flamegraph_focus, + resolve_stats: &outputs + .resolve_stats + .with_file_name("resolve.focus.stats.json"), + depth_summary: Some( + &outputs + .stack_depth_summary + .with_file_name("stack-depth-summary.focus.csv"), + ), + generate_svg, + top_n: 0, + start_sec: None, + stop_sec: None, + symbol_style: args.symbol_style.to_string(), + demangle: true, + focus: Some(focus), + min_percent: flamegraph_min_percent(args), + }) +} + +fn write_flamegraph_html( + outputs: &PerfOutputs, + kind: PerfFlamegraphKind, + flamegraph_generated: bool, +) -> anyhow::Result<()> { + if !matches!(kind, PerfFlamegraphKind::Html) || !flamegraph_generated { + return Ok(()); + } + let svg = outputs + .flamegraph + .file_name() + .and_then(|name| name.to_str()) + .unwrap_or("flamegraph.svg"); + let html = format!( + "StarryOS qperf Flame \ + Graph