npm.io
0.9.2 • Published 10h ago

hmtrace-parser

Licence
MIT
Version
0.9.2
Deps
1
Size
153 kB
Vulns
0
Weekly
573

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)获取 TraceParserRegistryRecordSampleHitraceThreadIndexSnapshot 等公共类型与 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 块、字段变换、getTraceEventFormatsop_flag 可读化
profile(续) cp_revoked.tsbacktrack.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 读取,该函数未从主入口导出)。快照仅含 timestampNsfunctionNamefieldDict(由 ftrace content 反解析,不合成 perf raw 字节);合并侧车时由消费方(如 snapshot_checker)写 traceFieldDict 并将 sample raw.size 置 0。options 默认剔除 function name 不在 formats 中的行;includeUnknownEvents: true 可保留未登记事件(空 fieldDict)。快照键为 ${tgid}:${pid}(hitrace 语义),与 hiperf RecordSamplepid(进程)/ tid(线程)对齐。

Logger
导出 说明
setHmtraceLogger 注入 trace / debug / info / error 日志实现;未调用时相关模块日志为 no-op
Profile 策略层(RLS)

内置 RLS trace 事件格式(TraceEventFormattext + 可选 transformFieldDict)。defaultrls 为同一套定义的别名;未知 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 namerevoke_idop_flag;hitrace content 为空格分隔 key=value
checkpoint_revoked 32945 checkpoint_monitor_idtyperevoke_reason;FS(type=0)时展开 revoke_reason kv
VFS 操作码可读化(readable

映射表见 samples/op_flag.mdWRITEMMAP、…、SPLICE_WRITE,bit 0–13)。解码时在保留原字段前提下追加:

事件 原字段 可读字段 条件
vfs_snapshot_dump_monitor op_flag op_flag_readable 掩码可解析
checkpoint_revokedtype=0 reason reason_readable revoke_reason 已展开且 kv 中含 reason:<op_flag>%x 十六进制

规则摘要:

  • 多 bit 以 | 连接(如 WRITE|ACCESS
  • 含未知 bit 时打 error 日志,写入 readable 字段
  • readable: false 时不追加可读字段(适用于 buildTraceRegistrybuildTraceRegistryFromProfiledecodeHitraceFunctionsbuildHitraceIndexSnapshot

说明:checkpoint_revoked 展开后的 reason 按内核 %x 解析为十六进制掩码(如 200x20ACCESS)。vfs_snapshot_dump_monitorop_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 数据行:taskpid(线程 tid)、tgid(进程 pid)、cpuflagstimestamp(秒)、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 lineEndingtrailingLineEndingencoding

写入后可通过 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

低层工具(如 parseHitraceFiledecodeHitraceFunctionsbuildHitraceThreadIndexregistryByEventName)仍存在于 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

Keywords