hmtrace-parser
v0.9.4
Published
Kernel trace format helpers (checkpoint_revoked, perf trace text blocks)
Downloads
2,222
Readme
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)、FFRT gid 聚合(tracing_mark_write / I13),以及供 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,
parseHitraceFile,
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 |
| tracing_mark_write | 298 | 含 buf(ftrace content 整段字符串);解码时展开 mark_type、trace_tag、is_ffrt 等;I13 为 FFRT 生命周期事件,进一步解析 ffrt_event、gid、label |
FFRT gid 聚合
采集时需打开 ffrt tag(tracing_mark_write 中 I13)。FFRT worker 线程名通常以 OS_FFRT 为前缀。
| 导出 | 说明 |
|------|------|
| parseTracingMarkWriteContent(buf) | 解析 tracing_mark_write buf 字符串为结构化字段 |
| aggregateFfrtByGid(data, formats, options?) | 解码后按 tgid + gid 聚合生命周期事件与 exec 片段内伴生事件 |
| aggregateFfrtByGidFromRecords(records, options?) | 对已解码记录聚合(不再解码) |
| FfrtGidAggregate | 含 lifecycleRecords、execSlices、companionRecords、anomalies |
companionRecords 仅包含各 exec 片段 [exec_begin, exec_end] 时间窗内、运行于 OS_FFRT* 线程上的非生命周期记录;可通过 includeEventNames / excludeEventNames 按 function.name 过滤。
import {
parseHitraceText,
getTraceEventFormats,
aggregateFfrtByGid,
} from "hmtrace-parser";
const data = parseHitraceText(ffrtTraceText);
const aggregates = aggregateFfrtByGid(data, getTraceEventFormats(), {
tgid: 1000,
gid: 17,
includeEventNames: ["sched_switch", "cpu_frequency"],
});
for (const agg of aggregates) {
console.log(agg.gid, agg.execSlices, agg.companionRecords.length);
}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 |
| parseHitraceFile(filePath, options?) | 流式解析 hitrace 文件为 HitraceData(options: encoding?、highWaterMark?) |
| ParseHitraceFileOptions | parseHitraceFile 选项类型 |
| 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 流式读取,避免整文件载入单个 string。
过滤
面向解析结果中的 HitraceRecord,按 tgid(进程组 / 进程 pid)或 function.name 筛选:
| 导出 | 说明 |
|------|------|
| filterHitraceRecordsByTgid(records, tgid) | 过滤 HitraceRecord[],保留 record.tgid === tgid |
| filterHitraceByTgid(data, tgid) | 同上,入参/出参为 HitraceData |
| filterHitraceRecordsByFunctionName(records, filter) | 按事件名过滤 record 列表(见下 HitraceFunctionNameFilter) |
| filterHitraceByFunctionName(data, filter) | 同上,包装为 HitraceData |
| filterHitraceRecordsExcludingFunctionName(records, name) | 按事件名黑名单排除(name 为 string 或 string[]) |
| filterHitraceExcludingFunctionName(data, name) | 同上,包装为 HitraceData |
| HitraceFunctionNameFilter | 过滤条件:string(单事件白名单)、string[](多事件白名单;空数组表示不匹配任何行)、{ include?, exclude? }(白名单与黑名单可组合,include / exclude 均为 string 或 string[]) |
导出
将 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 |
低层工具(如 decodeHitraceFunctions、buildHitraceThreadIndex、registryByEventName)仍存在于 src/lib/hitrace/,供本库内部与测试使用,未从主入口导出。FFRT 聚合见上文 FFRT gid 聚合 小节。
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
