hiperf_txt_parser 1.0.13 → 1.0.15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  export { parsePerfData, filterByTgid } from "./parser.js";
2
2
  export { formatPerfDataToText, formatPerfDataToJson } from "./serializer.js";
3
3
  export { toBackTraceStack, toBackTraceStacks } from "./backtrace.js";
4
- export { parseTraceFormat, parseCommonFieldsFromRaw, parseAllFieldsFromRaw, rawHexLinesToBuffer, bufferToRawHexLines, buildTraceParserRegistry, decodeRawByRegistry, decodePerfRawData, } from "./traceFormat.js";
5
- export type { ParsedTraceFormat, TraceFormatField, TraceParserRegistry, DecodedRawSample, DecodePerfRawDataOptions, DecodeRawByRegistryOptions, TracePrintMode, Endian, } from "./traceFormat.js";
4
+ export { parseTraceFormat, parseCommonFieldsFromRaw, parseAllFieldsFromRaw, rawHexLinesToBuffer, bufferToRawHexLines, buildTraceParserRegistry, decodeRawByRegistry, decodePerfRawData, formatPrintfValue, tokenizePrintfFormat, } from "./traceFormat.js";
5
+ export type { ParsedTraceFormat, TraceFormatField, TraceParserRegistry, DecodedRawSample, DecodePerfRawDataOptions, DecodeRawByRegistryOptions, TracePrintMode, PrintfSpec, Endian, } from "./traceFormat.js";
6
6
  export type { PerfData, RecordSample } from "./types.js";
7
7
  export type { RecordSampleJsonExportItem } from "./serializer.js";
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
1
  export { parsePerfData, filterByTgid } from "./parser.js";
2
2
  export { formatPerfDataToText, formatPerfDataToJson } from "./serializer.js";
3
3
  export { toBackTraceStack, toBackTraceStacks } from "./backtrace.js";
4
- export { parseTraceFormat, parseCommonFieldsFromRaw, parseAllFieldsFromRaw, rawHexLinesToBuffer, bufferToRawHexLines, buildTraceParserRegistry, decodeRawByRegistry, decodePerfRawData, } from "./traceFormat.js";
4
+ export { parseTraceFormat, parseCommonFieldsFromRaw, parseAllFieldsFromRaw, rawHexLinesToBuffer, bufferToRawHexLines, buildTraceParserRegistry, decodeRawByRegistry, decodePerfRawData, formatPrintfValue, tokenizePrintfFormat, } from "./traceFormat.js";
@@ -3,13 +3,15 @@ import type { PerfData } from "./types.js";
3
3
  * 将 PerfData 导出为与 sample/perf_data.txt 相同格式的文本(含缩进与每行前缀)
4
4
  */
5
5
  export declare function formatPerfDataToText(data: PerfData): string;
6
- /** 导出用 JSON 的单项:issuce 固定为 "unknow",call_chain 为 frames 逐行拼接 */
7
- export interface RecordSampleJsonExportItem {
6
+ /**
7
+ * 导出用 JSON 单项:固定含 `issuce`、`call_chain`;若存在 `traceFieldDict`,其键值对与二者**同级**平铺。
8
+ */
9
+ export type RecordSampleJsonExportItem = {
8
10
  issuce: "unknow";
9
11
  call_chain: string;
10
- }
12
+ } & Record<string, string>;
11
13
  /**
12
- * 将 PerfData 转为导出用 JSON 结构:顶层为数组,每项为 { issuce: "unknow", call_chain: "" },
13
- * call_chain 由对应 record sample 的 callchainFrames.frames 逐行拼接得到,无则为空字符串。
14
+ * 将 PerfData 转为导出用 JSON 结构:顶层为数组。
15
+ * call_chain callchainFrames.frames 拼接;有 traceFieldDict 时各字段平铺在对象顶层(与 call_chain 同级)。
14
16
  */
15
17
  export declare function formatPerfDataToJson(data: PerfData): RecordSampleJsonExportItem[];
@@ -19,7 +19,18 @@ function serializeOneSample(sample) {
19
19
  lines.push(` ${addr}`);
20
20
  }
21
21
  }
22
- if (sample.raw) {
22
+ if (sample.traceFieldDict && Object.keys(sample.traceFieldDict).length > 0 && sample.raw) {
23
+ lines.push(` raw size=${sample.raw.size}`);
24
+ for (const [k, v] of Object.entries(sample.traceFieldDict)) {
25
+ lines.push(` ${k}: ${v}`);
26
+ }
27
+ const n = Object.keys(sample.traceFieldDict).length;
28
+ for (let i = n; i < sample.raw.lines.length; i++) {
29
+ const { hex, short } = sample.raw.lines[i];
30
+ lines.push(short ? ` ${hex} (${short})` : ` ${hex}`);
31
+ }
32
+ }
33
+ else if (sample.raw) {
23
34
  lines.push(` raw size=${sample.raw.size}`);
24
35
  for (const { hex, short } of sample.raw.lines) {
25
36
  lines.push(short ? ` ${hex} (${short})` : ` ${hex}`);
@@ -47,12 +58,20 @@ export function formatPerfDataToText(data) {
47
58
  return data.recordSamples.map(serializeOneSample).join("\n\n");
48
59
  }
49
60
  /**
50
- * 将 PerfData 转为导出用 JSON 结构:顶层为数组,每项为 { issuce: "unknow", call_chain: "" },
51
- * call_chain 由对应 record sample 的 callchainFrames.frames 逐行拼接得到,无则为空字符串。
61
+ * 将 PerfData 转为导出用 JSON 结构:顶层为数组。
62
+ * call_chain callchainFrames.frames 拼接;有 traceFieldDict 时各字段平铺在对象顶层(与 call_chain 同级)。
52
63
  */
53
64
  export function formatPerfDataToJson(data) {
54
- return data.recordSamples.map((s) => ({
55
- issuce: "unknow",
56
- call_chain: s.callchainFrames ? s.callchainFrames.frames.join("\n") : "",
57
- }));
65
+ return data.recordSamples.map((s) => {
66
+ const item = {
67
+ issuce: "unknow",
68
+ call_chain: s.callchainFrames ? s.callchainFrames.frames.join("\n") : "",
69
+ };
70
+ if (s.traceFieldDict) {
71
+ for (const [k, v] of Object.entries(s.traceFieldDict)) {
72
+ item[k] = v;
73
+ }
74
+ }
75
+ return item;
76
+ });
58
77
  }
@@ -75,6 +75,30 @@ export declare function bufferToRawHexLines(raw: Uint8Array, bytesPerLine?: numb
75
75
  * 从多个 trace_format 文本构建解析器集合(按 event ID 索引)
76
76
  */
77
77
  export declare function buildTraceParserRegistry(formatTexts: string[]): TraceParserRegistry;
78
+ /** 与 C printf 接近的转换说明符(不含 * 动态宽度等) */
79
+ export interface PrintfSpec {
80
+ flags: string;
81
+ width?: number;
82
+ precision?: number;
83
+ length: string;
84
+ conv: string;
85
+ }
86
+ /**
87
+ * 按 C printf 子集格式化:标志 -+ #0 空格,宽度,精度,长度 hl ll hh,转换 d i u x X o s p。
88
+ */
89
+ export declare function formatPrintfValue(value: number | bigint | string, spec: PrintfSpec): string;
90
+ /**
91
+ * 将 print fmt 拆成文本、`%%`、与带参数的转换说明符。
92
+ */
93
+ export declare function tokenizePrintfFormat(printFmt: string): Array<{
94
+ kind: "text";
95
+ text: string;
96
+ } | {
97
+ kind: "literal_pct";
98
+ } | {
99
+ kind: "spec";
100
+ spec: PrintfSpec;
101
+ }>;
78
102
  /**
79
103
  * 对一条 raw 数据先解 common_*,再按 common_type 选择解析器,最后按 print fmt 渲染。
80
104
  * 找不到解析器时返回 skipped=true,并打印 common_type。
@@ -88,6 +112,7 @@ export declare function decodeRawByRegistry(raw: Uint8Array, registry: TracePars
88
112
  *
89
113
  * 规则:
90
114
  * - 若找到 common_type 对应解析器:将 print fmt 渲染结果写入 `sample.raw.lines`(一行)。
115
+ * - fieldDict:写入 `traceFieldDict`,`raw.lines` 为每行一条 `key: value`;`raw.size` 为行数(含可选 common 行)。
91
116
  * - 若找不到解析器:放弃解析,并将 `common_type` 写入 `sample.raw.lines`(一行)。
92
117
  */
93
118
  export declare function decodePerfRawData(perfData: PerfData, registry: TraceParserRegistry, options?: DecodePerfRawDataOptions): PerfData;
@@ -274,22 +274,232 @@ export function buildTraceParserRegistry(formatTexts) {
274
274
  }
275
275
  return { byEventId, commonFormat };
276
276
  }
277
- const PRINT_FMT_SPEC_RE = /%[0-9]*[lh]*([duxXsS])/g;
278
- function formatArgBySpecifier(value, spec) {
279
- if (spec.toLowerCase() === "s") {
280
- return typeof value === "string" ? value : String(value);
277
+ const PRINT_FLAG_CHARS = new Set(["-", "+", "#", "0", " "]);
278
+ const VALID_PRINTF_CONV = new Set(["d", "i", "u", "x", "X", "o", "s", "S", "p", "P"]);
279
+ function hasPrintfFlag(flags, f) {
280
+ return flags.includes(f);
281
+ }
282
+ function toBigIntForPrintf(value) {
283
+ if (typeof value === "bigint")
284
+ return value;
285
+ if (typeof value === "string")
286
+ return 0n;
287
+ if (!Number.isFinite(value))
288
+ return 0n;
289
+ return BigInt(Math.trunc(value));
290
+ }
291
+ /** 按 64 位无符号解释(与内核 trace 常见 long 一致) */
292
+ function asUInt64(n) {
293
+ return n & ((1n << 64n) - 1n);
294
+ }
295
+ function applyWidth(s, width, leftAlign, zeroPad) {
296
+ if (width === undefined || s.length >= width)
297
+ return s;
298
+ const padLen = width - s.length;
299
+ const ch = zeroPad && !leftAlign ? "0" : " ";
300
+ if (leftAlign)
301
+ return s + ch.repeat(padLen);
302
+ return ch.repeat(padLen) + s;
303
+ }
304
+ /** 带符号十进制:支持 precision、0 宽度、+- 空格 */
305
+ function formatPrintfD(n, spec) {
306
+ const neg = n < 0n;
307
+ const abs = neg ? -n : n;
308
+ let digits = abs.toString(10);
309
+ const prec = spec.precision !== undefined ? spec.precision : 1;
310
+ digits = digits.padStart(Math.max(prec, digits.length), "0");
311
+ let sign = "";
312
+ if (neg)
313
+ sign = "-";
314
+ else if (hasPrintfFlag(spec.flags, "+"))
315
+ sign = "+";
316
+ else if (hasPrintfFlag(spec.flags, " "))
317
+ sign = " ";
318
+ const body = sign + digits;
319
+ if (spec.width === undefined || body.length >= spec.width)
320
+ return body;
321
+ const padLen = spec.width - body.length;
322
+ if (hasPrintfFlag(spec.flags, "0") && !hasPrintfFlag(spec.flags, "-") && spec.precision === undefined) {
323
+ if (sign)
324
+ return sign + "0".repeat(padLen) + digits;
325
+ return "0".repeat(padLen) + body;
326
+ }
327
+ if (hasPrintfFlag(spec.flags, "-"))
328
+ return body + " ".repeat(padLen);
329
+ return " ".repeat(padLen) + body;
330
+ }
331
+ function formatPrintfUnsignedRadix(unsigned, spec, radix, upper) {
332
+ let body = radix === 16
333
+ ? upper
334
+ ? unsigned.toString(16).toUpperCase()
335
+ : unsigned.toString(16)
336
+ : unsigned.toString(radix);
337
+ const precDefault = 1;
338
+ const prec = spec.precision !== undefined ? spec.precision : precDefault;
339
+ body = body.padStart(Math.max(prec, body.length), "0");
340
+ if (hasPrintfFlag(spec.flags, "#")) {
341
+ if (radix === 16)
342
+ body = (upper ? "0X" : "0x") + body;
343
+ else if (radix === 8 && body !== "0" && !body.startsWith("0"))
344
+ body = "0" + body;
345
+ }
346
+ const zeroPad = hasPrintfFlag(spec.flags, "0") &&
347
+ !hasPrintfFlag(spec.flags, "-") &&
348
+ spec.precision === undefined;
349
+ return applyWidth(body, spec.width, hasPrintfFlag(spec.flags, "-"), zeroPad);
350
+ }
351
+ /**
352
+ * 按 C printf 子集格式化:标志 -+ #0 空格,宽度,精度,长度 hl ll hh,转换 d i u x X o s p。
353
+ */
354
+ export function formatPrintfValue(value, spec) {
355
+ const conv = spec.conv;
356
+ const cl = conv.toLowerCase();
357
+ if (conv === "s" || conv === "S") {
358
+ let s = typeof value === "string" ? value : String(value);
359
+ if (spec.precision !== undefined) {
360
+ s = s.slice(0, spec.precision);
361
+ }
362
+ return applyWidth(s, spec.width, hasPrintfFlag(spec.flags, "-"), false);
281
363
  }
282
- const isBig = typeof value === "bigint";
283
- const lower = spec.toLowerCase();
284
- if (lower === "x") {
285
- return isBig ? value.toString(16) : Math.trunc(value).toString(16);
364
+ const n = toBigIntForPrintf(value);
365
+ if (conv === "p" || conv === "P") {
366
+ const u = asUInt64(n);
367
+ const upper = conv === "P";
368
+ let body = upper ? u.toString(16).toUpperCase() : u.toString(16);
369
+ const prec = spec.precision !== undefined ? spec.precision : 1;
370
+ body = body.padStart(Math.max(prec, body.length), "0");
371
+ const zeroPad = hasPrintfFlag(spec.flags, "0") &&
372
+ !hasPrintfFlag(spec.flags, "-") &&
373
+ spec.precision === undefined;
374
+ return applyWidth(body, spec.width, hasPrintfFlag(spec.flags, "-"), zeroPad);
286
375
  }
287
- if (lower === "u") {
288
- if (isBig)
289
- return (value < 0n ? 0n : value).toString(10);
290
- return Math.max(0, Math.trunc(value)).toString(10);
376
+ if (cl === "d" || cl === "i") {
377
+ return formatPrintfD(n, spec);
378
+ }
379
+ if (cl === "u" || cl === "x" || cl === "X" || cl === "o") {
380
+ const u = asUInt64(n);
381
+ if (cl === "u") {
382
+ let body = u.toString(10);
383
+ const prec = spec.precision !== undefined ? spec.precision : 1;
384
+ body = body.padStart(Math.max(prec, body.length), "0");
385
+ const zeroPad = hasPrintfFlag(spec.flags, "0") &&
386
+ !hasPrintfFlag(spec.flags, "-") &&
387
+ spec.precision === undefined;
388
+ return applyWidth(body, spec.width, hasPrintfFlag(spec.flags, "-"), zeroPad);
389
+ }
390
+ if (cl === "o") {
391
+ return formatPrintfUnsignedRadix(u, spec, 8, false);
392
+ }
393
+ return formatPrintfUnsignedRadix(u, spec, 16, conv === "X");
394
+ }
395
+ return String(value);
396
+ }
397
+ /**
398
+ * 将 print fmt 拆成文本、`%%`、与带参数的转换说明符。
399
+ */
400
+ export function tokenizePrintfFormat(printFmt) {
401
+ const out = [];
402
+ let i = 0;
403
+ let textBuf = "";
404
+ const flushText = () => {
405
+ if (textBuf.length > 0) {
406
+ out.push({ kind: "text", text: textBuf });
407
+ textBuf = "";
408
+ }
409
+ };
410
+ while (i < printFmt.length) {
411
+ if (printFmt[i] !== "%") {
412
+ textBuf += printFmt[i];
413
+ i++;
414
+ continue;
415
+ }
416
+ flushText();
417
+ const pctPos = i;
418
+ if (i + 1 >= printFmt.length) {
419
+ textBuf += "%";
420
+ i++;
421
+ continue;
422
+ }
423
+ if (printFmt[i + 1] === "%") {
424
+ out.push({ kind: "literal_pct" });
425
+ i += 2;
426
+ continue;
427
+ }
428
+ i++;
429
+ let flags = "";
430
+ while (i < printFmt.length && PRINT_FLAG_CHARS.has(printFmt[i])) {
431
+ flags += printFmt[i];
432
+ i++;
433
+ }
434
+ let width;
435
+ if (i < printFmt.length && printFmt[i] >= "0" && printFmt[i] <= "9") {
436
+ let w = 0;
437
+ while (i < printFmt.length && printFmt[i] >= "0" && printFmt[i] <= "9") {
438
+ w = w * 10 + (printFmt[i].charCodeAt(0) - 48);
439
+ i++;
440
+ }
441
+ width = w;
442
+ }
443
+ let precision;
444
+ if (i < printFmt.length && printFmt[i] === ".") {
445
+ i++;
446
+ if (i < printFmt.length && printFmt[i] >= "0" && printFmt[i] <= "9") {
447
+ let p = 0;
448
+ while (i < printFmt.length && printFmt[i] >= "0" && printFmt[i] <= "9") {
449
+ p = p * 10 + (printFmt[i].charCodeAt(0) - 48);
450
+ i++;
451
+ }
452
+ precision = p;
453
+ }
454
+ else {
455
+ precision = 0;
456
+ }
457
+ }
458
+ let length = "";
459
+ if (i < printFmt.length) {
460
+ if (printFmt[i] === "h") {
461
+ length = "h";
462
+ i++;
463
+ if (i < printFmt.length && printFmt[i] === "h") {
464
+ length = "hh";
465
+ i++;
466
+ }
467
+ }
468
+ else if (printFmt[i] === "l") {
469
+ length = "l";
470
+ i++;
471
+ if (i < printFmt.length && printFmt[i] === "l") {
472
+ length = "ll";
473
+ i++;
474
+ }
475
+ }
476
+ else if (printFmt[i] === "L" ||
477
+ printFmt[i] === "j" ||
478
+ printFmt[i] === "z" ||
479
+ printFmt[i] === "t") {
480
+ length = printFmt[i];
481
+ i++;
482
+ }
483
+ }
484
+ if (i >= printFmt.length) {
485
+ textBuf += printFmt.slice(pctPos, i);
486
+ break;
487
+ }
488
+ const conv = printFmt[i];
489
+ i++;
490
+ if (!VALID_PRINTF_CONV.has(conv)) {
491
+ textBuf += printFmt.slice(pctPos, i);
492
+ continue;
493
+ }
494
+ out.push({ kind: "spec", spec: { flags, width, precision, length, conv } });
291
495
  }
292
- return isBig ? value.toString(10) : Math.trunc(value).toString(10);
496
+ flushText();
497
+ return out;
498
+ }
499
+ function extractPrintfSpecs(printFmt) {
500
+ return tokenizePrintfFormat(printFmt)
501
+ .filter((t) => t.kind === "spec")
502
+ .map((t) => t.spec);
293
503
  }
294
504
  function normalizePrintExpr(exprRaw) {
295
505
  let expr = exprRaw.trim();
@@ -336,28 +546,19 @@ function buildPrintArgValues(printArgs, fieldMap) {
336
546
  const values = (printArgs ?? []).map((e) => evalPrintArgExpr(e, fieldMap));
337
547
  return { normalizedArgs, values };
338
548
  }
339
- /** 与 renderPrintFmt 中 replace 顺序一致:依次取出每个格式符的类型字母 */
340
- function extractPrintfSpecChars(printFmt) {
341
- const specs = [];
342
- printFmt.replace(PRINT_FMT_SPEC_RE, (_all, spec) => {
343
- specs.push(spec);
344
- return _all;
345
- });
346
- return specs;
347
- }
348
549
  function formatOnePrintArg(idx, spec, fieldMap, normalizedArgs, values) {
349
550
  const v = values[idx] ?? 0;
350
551
  const argExpr = normalizedArgs[idx] ?? "";
351
- if (spec.toLowerCase() === "s") {
552
+ if (spec.conv === "s" || spec.conv === "S") {
352
553
  const m = argExpr.match(/^REC->__data_loc_(\w+)(?:&0xffff)?(?:>>16)?$/);
353
554
  if (m) {
354
555
  const s = fieldMap[m[1]];
355
556
  if (typeof s === "string") {
356
- return s;
557
+ return formatPrintfValue(s, spec);
357
558
  }
358
559
  }
359
560
  }
360
- return formatArgBySpecifier(v, spec);
561
+ return formatPrintfValue(v, spec);
361
562
  }
362
563
  function fieldKeyFromNormalizedArg(normalizedArg, index) {
363
564
  let k = normalizedArg;
@@ -367,7 +568,7 @@ function fieldKeyFromNormalizedArg(normalizedArg, index) {
367
568
  }
368
569
  function renderPrintFmtAsFieldDict(printFmt, printArgs, fieldMap) {
369
570
  const { normalizedArgs, values } = buildPrintArgValues(printArgs, fieldMap);
370
- const specs = extractPrintfSpecChars(printFmt);
571
+ const specs = extractPrintfSpecs(printFmt);
371
572
  const out = {};
372
573
  const seen = new Map();
373
574
  for (let i = 0; i < specs.length; i++) {
@@ -381,11 +582,21 @@ function renderPrintFmtAsFieldDict(printFmt, printArgs, fieldMap) {
381
582
  }
382
583
  function renderPrintFmt(printFmt, printArgs, fieldMap) {
383
584
  const { normalizedArgs, values } = buildPrintArgValues(printArgs, fieldMap);
384
- let valueIdx = 0;
385
- return printFmt.replace(PRINT_FMT_SPEC_RE, (_all, spec) => {
386
- const idx = valueIdx++;
387
- return formatOnePrintArg(idx, spec, fieldMap, normalizedArgs, values);
388
- });
585
+ const tokens = tokenizePrintfFormat(printFmt);
586
+ let argIdx = 0;
587
+ let out = "";
588
+ for (const tok of tokens) {
589
+ if (tok.kind === "text") {
590
+ out += tok.text;
591
+ }
592
+ else if (tok.kind === "literal_pct") {
593
+ out += "%";
594
+ }
595
+ else {
596
+ out += formatOnePrintArg(argIdx++, tok.spec, fieldMap, normalizedArgs, values);
597
+ }
598
+ }
599
+ return out;
389
600
  }
390
601
  /**
391
602
  * 对一条 raw 数据先解 common_*,再按 common_type 选择解析器,最后按 print fmt 渲染。
@@ -441,6 +652,7 @@ export function decodeRawByRegistry(raw, registry, options = {}) {
441
652
  *
442
653
  * 规则:
443
654
  * - 若找到 common_type 对应解析器:将 print fmt 渲染结果写入 `sample.raw.lines`(一行)。
655
+ * - fieldDict:写入 `traceFieldDict`,`raw.lines` 为每行一条 `key: value`;`raw.size` 为行数(含可选 common 行)。
444
656
  * - 若找不到解析器:放弃解析,并将 `common_type` 写入 `sample.raw.lines`(一行)。
445
657
  */
446
658
  export function decodePerfRawData(perfData, registry, options = {}) {
@@ -461,8 +673,30 @@ export function decodePerfRawData(perfData, registry, options = {}) {
461
673
  .map(([k, v]) => `${k}:${typeof v === "bigint" ? v.toString(10) : v}`)
462
674
  .join(" ")
463
675
  : "";
676
+ const dict = decoded.renderedFieldDict;
677
+ const useFieldDict = options.tracePrintMode === "fieldDict" &&
678
+ dict !== undefined &&
679
+ Object.keys(dict).length > 0;
680
+ if (useFieldDict) {
681
+ const kvLines = Object.entries(dict).map(([k, v]) => ({
682
+ hex: `${k}: ${v}`,
683
+ }));
684
+ const lines = options.keepCommonFields && commonLine.length > 0
685
+ ? [...kvLines, { hex: commonLine }]
686
+ : kvLines;
687
+ return {
688
+ ...sample,
689
+ traceFieldDict: dict,
690
+ raw: {
691
+ ...sample.raw,
692
+ size: lines.length,
693
+ lines,
694
+ },
695
+ };
696
+ }
464
697
  return {
465
698
  ...sample,
699
+ traceFieldDict: undefined,
466
700
  raw: {
467
701
  ...sample.raw,
468
702
  lines: options.keepCommonFields && commonLine.length > 0
package/dist/types.d.ts CHANGED
@@ -39,6 +39,8 @@ export interface RecordSample {
39
39
  period: number;
40
40
  callchain?: CallchainEntry;
41
41
  raw?: RawEntry;
42
+ /** tracePrintMode 为 fieldDict 且解码成功时:print 各参数键值(用于导出 txt/json) */
43
+ traceFieldDict?: Record<string, string>;
42
44
  server?: ServerEntry;
43
45
  callchainFrames?: CallchainFramesEntry;
44
46
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hiperf_txt_parser",
3
- "version": "1.0.13",
3
+ "version": "1.0.15",
4
4
  "description": "Parse perf data.txt and output structured TypeScript data",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",