hmtrace-parser
hmtrace-parser
内核 trace 相关辅助:为 hiperf_txt_parser 提供 RLS 版本内核事件的 perf trace 文本格式块(format: / print fmt:),以及对 checkpoint_revoked 事件中 revoke_reason 的解析与展开;另含 hitrace ftrace 文本 的解析、按 tgid 过滤、导出回 txt、fieldDict 解码、VFS 操作码可读化(op_flag_readable / reason_readable),以及供 hiperf 侧车合并使用的 hitrace 线程索引快照 构建。
依赖分层:本库直接依赖 hm-pt-core(≥ 2.0.0)获取 TraceParserRegistry、RecordSample、HitraceThreadIndexSnapshot 等公共类型与 trace format 解码原语;不再依赖 hiperf。解析 perf 文本、批量 raw 解码与 hitrace 侧车合并仍由 hiperf(≥ 2.1.0)提供,由调用方(如 snapshot_checker)自行组合。本库仅导出 trace 机制层、profile 策略层、hitrace 预处理与领域工具,不 re-export hm-pt-core 或 hiperf 已有符号。
源码按职责分层:
| 层 | 路径 | 职责 |
|---|---|---|
| trace(机制) | src/lib/trace/ |
接收 TraceEventFormat[],构建 TraceParserRegistry |
| profile(策略) | src/lib/profile/ |
RLS format 块、字段变换、getTraceEventFormats、op_flag 可读化 |
| profile(续) | cp_revoked.ts、backtrack.ts |
revoke_reason 解析、backtrack 配对策略 |
| hitrace | src/lib/hitrace/ |
ftrace 文本行解析、按 tgid 过滤、导出 txt、按 event name 解码 function 为 fieldDict、构建线程索引快照 |
- Node.js ≥ 18
- ESM(
"type": "module")
安装
npm install hmtrace-parser与 hiperf 组合解码 perf 文本时,另装 hiperf_txt_parser@^2.1.0(及 hiperf 自带的 hm-pt-core 传递依赖)。
用法概览
主入口 hmtrace-parser
当前包仅发布主入口(exports["."]),聚合 trace、profile、hitrace、logger 各层导出:
import {
parsePerfData,
decodePerfRawData,
type HitraceSidecarOptions,
} from "hiperf_txt_parser";
import {
setHmtraceLogger,
type TraceEventFormat,
type TraceRegistryOptions,
buildTraceRegistry,
getTraceEventFormats,
getTraceEventFormatProfiles,
buildTraceRegistryFromProfile,
expandCheckpointRevokedFieldDict,
passthroughFieldDict,
applyOpFlagReadableFields,
parseOpFlagMask,
opFlagMaskToReadable,
VFS_OP_FLAG_BITS,
backtrackFS,
backtrackStrategyRls,
resolveBacktrackStrategy,
buildHitraceIndexSnapshot,
parseHitraceText,
formatHitraceRecordLine,
saveHitraceDataToTxt,
filterHitraceByTgid,
filterHitraceRecordsByTgid,
type HitraceData,
type HitraceRecord,
} from "hmtrace-parser";perf raw 解码(调用方组合)
本库提供 format 块与 registry 构建;解析 perf 文本与批量 raw 解码由 hiperf 完成。省略 profile 名时等价于 default / rls:
import { parsePerfData, decodePerfRawData } from "hiperf_txt_parser";
import {
getTraceEventFormats,
buildTraceRegistryFromProfile,
} from "hmtrace-parser";
const formats = getTraceEventFormats();
const registry = buildTraceRegistryFromProfile(undefined, {
readable: true, // 默认 true:追加 op_flag_readable / reason_readable
});
const perfData = parsePerfData(text);
const decoded = await decodePerfRawData(perfData, registry, {
tracePrintMode: "fieldDict",
});hitrace 与 perf 合并(hiperf ≥ 2.1.0)
hiperf 1.4.2 起,decodePerfRawData 支持 options.hitrace 侧车:传入预处理后的 HitraceThreadIndexSnapshot 与合并策略(fallback / overlay / off)。快照由本库 buildHitraceIndexSnapshot 构建:
import {
parsePerfData,
decodePerfRawData,
type HitraceSidecarOptions,
} from "hiperf_txt_parser";
import {
getTraceEventFormats,
buildTraceRegistryFromProfile,
buildHitraceIndexSnapshot,
} from "hmtrace-parser";
const formats = getTraceEventFormats();
const hitraceIndex = await buildHitraceIndexSnapshot(
{ filePath: "samples/bug.hitrace" },
formats,
{
tracePrintMode: "fieldDict",
readable: true, // 默认 true
},
);
const hitrace: HitraceSidecarOptions = {
index: hitraceIndex,
strategy: "fallback",
};
const perfData = parsePerfData(perfText);
const decoded = await decodePerfRawData(perfData, registry, {
tracePrintMode: "fieldDict",
hitrace,
});buildHitraceIndexSnapshot 入参支持 { filePath, encoding?, highWaterMark? } 或已解析的 { data: HitraceData }(filePath 在内部通过流式 parseHitraceFile 读取,该函数未从主入口导出)。快照仅含 timestampNs、functionName、fieldDict(由 ftrace content 反解析,不合成 perf raw 字节);合并侧车时由消费方(如 snapshot_checker)写 traceFieldDict 并将 sample raw.size 置 0。options 默认剔除 function name 不在 formats 中的行;includeUnknownEvents: true 可保留未登记事件(空 fieldDict)。快照键为 ${tgid}:${pid}(hitrace 语义),与 hiperf RecordSample 的 pid(进程)/ tid(线程)对齐。
Logger
| 导出 | 说明 |
|---|---|
setHmtraceLogger |
注入 trace / debug / info / error 日志实现;未调用时相关模块日志为 no-op |
Profile 策略层(RLS)
内置 RLS trace 事件格式(TraceEventFormat:text + 可选 transformFieldDict)。default 与 rls 为同一套定义的别名;未知 profile 名回退至该定义。
| 导出 | 说明 |
|---|---|
getTraceEventFormats(profile?) |
取 RLS 格式列表(浅拷贝) |
getTraceEventFormatProfiles() |
返回 ["default", "rls"] |
buildTraceRegistryFromProfile(profile?, options?) |
构建 TraceParserRegistry |
expandCheckpointRevokedFieldDict / passthroughFieldDict |
字段字典变换 |
applyOpFlagReadableFields / parseOpFlagMask / parseOpFlagMaskHex / opFlagMaskToReadable |
VFS 操作码映射与可读化 |
VFS_OP_FLAG_BITS |
硬编码 bit → 名称表(与 samples/op_flag.md 一致) |
当前事件(RLS):
| 事件 | ID | 说明 |
|---|---|---|
vfs_snapshot_dump_monitor |
33220 | 含 name、revoke_id、op_flag;hitrace content 为空格分隔 key=value |
checkpoint_revoked |
32945 | 含 checkpoint_monitor_id、type、revoke_reason;FS(type=0)时展开 revoke_reason kv |
VFS 操作码可读化(readable)
映射表见 samples/op_flag.md(WRITE、MMAP、…、SPLICE_WRITE,bit 0–13)。解码时在保留原字段前提下追加:
| 事件 | 原字段 | 可读字段 | 条件 |
|---|---|---|---|
vfs_snapshot_dump_monitor |
op_flag |
op_flag_readable |
掩码可解析 |
checkpoint_revoked(type=0) |
reason |
reason_readable |
revoke_reason 已展开且 kv 中含 reason:<op_flag>(%x 十六进制) |
规则摘要:
- 多 bit 以
|连接(如WRITE|ACCESS) - 含未知 bit 时打
error日志,不写入 readable 字段 readable: false时不追加可读字段(适用于buildTraceRegistry、buildTraceRegistryFromProfile、decodeHitraceFunctions、buildHitraceIndexSnapshot)
说明:checkpoint_revoked 展开后的 reason 按内核 %x 解析为十六进制掩码(如 20 → 0x20 → ACCESS)。vfs_snapshot_dump_monitor 的 op_flag:hitrace content 反解析后多为十进制字符串(如 32);perf raw 经 %lx 渲染时可能为十六进制字符串(如 20 表示 0x20),二者经 parseOpFlagMask 可读化结果一致。
示例(type=0):
revoke_reason = "devid:9, fs:ab, index:1, reason:20"
→ 展开后 reason="20", reason_readable="ACCESS" (0x20 = ACCESS)
Trace 机制层
| 导出 | 说明 |
|---|---|
buildTraceRegistry(formats, options?) |
由 TraceEventFormat[] 构建 TraceParserRegistry;默认包装可读化 transform |
hitrace 与 perf raw 共用同一 registry:transform 先执行 profile 逻辑(如展开 revoke_reason),再追加 *_readable 字段。
Hitrace 层
解析
| 导出 | 说明 |
|---|---|
parseHitraceText(text) |
解析整段 ftrace 文本为 HitraceData |
HitraceData |
聚合类型,{ records: HitraceRecord[] } |
HitraceRecord |
单条 ftrace 数据行:task、pid(线程 tid)、tgid(进程 pid)、cpu、flags、timestamp(秒)、function |
ftrace 数据行形态:TASK-PID (TGID) [CPU] FLAGS TIMESTAMP: function: content。解析时跳过空行、# 注释与 tracer: 行;不保留文件头元数据。
parseHitraceText 逐行调用 parseHitraceLine,产出 HitraceRecord 列表(此阶段 function.fieldDict 尚未填充)。大文件可在内部通过未导出的 parseHitraceFile 流式读取。
过滤
面向解析结果中的 HitraceRecord,按 tgid(进程组 / 进程 pid)或 function.name 筛选:
| 导出 | 说明 |
|---|---|
filterHitraceRecordsByTgid(records, tgid) |
过滤 HitraceRecord[],保留 record.tgid === tgid |
filterHitraceByTgid(data, tgid) |
同上,入参/出参为 HitraceData |
filterHitraceRecordsByFunctionName(records, name) |
按事件名过滤 record 列表 |
filterHitraceByFunctionName(data, name) |
同上,包装为 HitraceData |
导出
将 HitraceRecord / HitraceData 写回 ftrace 数据行 txt 文件(不含 tracer: 与注释头)。使用 saveHitraceDataToTxt 逐行流式写入,避免将全部内容拼接为单个 string(受 V8 max string 长度限制):
| 导出 | 说明 |
|---|---|
formatHitraceRecordLine(record) |
单条记录 → 一行 ftrace 文本(不含行尾换行) |
saveHitraceDataToTxt(filePath, data, options?) |
逐行写入文件;默认 \n 分隔且末行后追加换行 |
SaveHitraceDataToTxtOptions |
lineEnding、trailingLineEnding、encoding |
写入后可通过 parseHitraceFile / parseHitraceText 再次解析,字段语义与导出前一致(往返测试已覆盖)。function.content 为空时,导出行在事件名后不追加 :。
典型流程:解析 → 按 tgid 过滤 → 写入文件:
import {
parseHitraceText,
filterHitraceRecordsByTgid,
saveHitraceDataToTxt,
} from "hmtrace-parser";
const data = parseHitraceText(hitraceText);
const records = filterHitraceRecordsByTgid(data.records, 952);
await saveHitraceDataToTxt("out.hitrace", { records });解码与侧车快照
| 导出 | 说明 |
|---|---|
buildHitraceIndexSnapshot(input, formats, options?) |
解析 + 解码 + 线程分桶,产出 HitraceThreadIndexSnapshot |
低层工具(如 parseHitraceFile、decodeHitraceFunctions、buildHitraceThreadIndex、registryByEventName)仍存在于 src/lib/hitrace/,供本库内部与测试使用,未从主入口导出。
Backtrack
在已解码、且 traceFieldDict 已填充的 RecordSample 上做 backtrack 配对。默认按 revoke_id 配对:vfs_snapshot_dump_monitor(backtrack op)与 FS checkpoint_revoked(invalid op)。
历史 devid + fs + index 配对须显式传入 backtrackStrategy: backtrackStrategyDefault(未从主入口导出,测试/internal 使用)。
| 导出 | 说明 |
|---|---|
backtrackFS(perfData | samples, options?) |
返回 BacktrackResult:[recordSamples, map] |
backtrackStrategyRls |
默认 revoke_id 配对策略 |
resolveBacktrackStrategy(profile?) |
解析策略(当前恒为 RLS) |
开发
npm install
npm run build # 输出到 dist/
npm test # 单元测试
npm run test:all # 单元测试 + perf 测试许可证
MIT