hiperf_txt_parser 1.0.8 → 1.0.9

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.
@@ -41,7 +41,7 @@ export declare function parseCommonFieldsFromRaw(raw: Uint8Array, format: Parsed
41
41
  /**
42
42
  * 解析 format 中全部字段(含数组),数组字段名会去掉 [],如 args[6] => args: [...]
43
43
  */
44
- export declare function parseAllFieldsFromRaw(raw: Uint8Array, format: ParsedTraceFormat): Record<string, number | bigint | Array<number | bigint>>;
44
+ export declare function parseAllFieldsFromRaw(raw: Uint8Array, format: ParsedTraceFormat): Record<string, number | bigint | string | Array<number | bigint>>;
45
45
  /**
46
46
  * 将 perf 文本里 raw 段的 hex 行拼成连续字节(小端:每行一个数值,宽度由 hex 位数决定,4→2 字节,8→4 字节,16→8 字节)
47
47
  */
@@ -163,9 +163,38 @@ export function parseCommonFieldsFromRaw(raw, format) {
163
163
  export function parseAllFieldsFromRaw(raw, format) {
164
164
  const view = new DataView(raw.buffer, raw.byteOffset, raw.byteLength);
165
165
  const out = {};
166
+ const decoder = new TextDecoder("utf-8", { fatal: false });
166
167
  for (const field of format.fields) {
167
168
  const arr = parseArrayName(field.name);
168
169
  const key = arr ? arr.baseName : field.name;
170
+ const t = normalizeType(field.typeName);
171
+ // __data_loc char[] reason: 实际存一个 u32,低 16 位为 offset,高 16 位为 length
172
+ if (t.includes("__data_loc") && t.includes("char")) {
173
+ const locField = {
174
+ ...field,
175
+ typeName: "unsigned int",
176
+ signed: false,
177
+ size: 4,
178
+ };
179
+ const loc = readFieldScalar(view, locField);
180
+ if (typeof loc === "number") {
181
+ const locKey = `__data_loc_${field.name}`;
182
+ out[locKey] = loc;
183
+ const offset = loc & 0xffff;
184
+ const len = (loc >>> 16) & 0xffff;
185
+ if (offset >= 0 && len > 0 && offset + len <= raw.length) {
186
+ const bytes = raw.slice(offset, offset + len);
187
+ // 去掉末尾 \0
188
+ const nul = bytes.indexOf(0);
189
+ const slice = nul >= 0 ? bytes.slice(0, nul) : bytes;
190
+ out[field.name] = decoder.decode(slice);
191
+ }
192
+ else {
193
+ out[field.name] = "";
194
+ }
195
+ }
196
+ continue;
197
+ }
169
198
  const v = readFieldValue(view, field);
170
199
  if (v !== undefined) {
171
200
  out[key] = v;
@@ -211,6 +240,9 @@ export function buildTraceParserRegistry(formatTexts) {
211
240
  return { byEventId, commonFormat };
212
241
  }
213
242
  function formatArgBySpecifier(value, spec) {
243
+ if (spec.toLowerCase() === "s") {
244
+ return typeof value === "string" ? value : String(value);
245
+ }
214
246
  const isBig = typeof value === "bigint";
215
247
  const lower = spec.toLowerCase();
216
248
  if (lower === "x") {
@@ -225,36 +257,51 @@ function formatArgBySpecifier(value, spec) {
225
257
  }
226
258
  function renderPrintFmt(printFmt, printArgs, fieldMap) {
227
259
  const values = [];
228
- for (const expr of printArgs ?? []) {
229
- const em = expr.match(/^REC->(\w+)(?:\[(\d+)])?$/);
230
- if (!em) {
231
- values.push(0);
232
- continue;
260
+ function evalExpr(exprRaw) {
261
+ // 允许表达式带括号与空格
262
+ let expr = exprRaw.trim();
263
+ // 去掉外层括号(可能不止一层,也可能只有一侧被 match 捕获到)
264
+ while (expr.startsWith("("))
265
+ expr = expr.slice(1).trim();
266
+ while (expr.endsWith(")"))
267
+ expr = expr.slice(0, -1).trim();
268
+ expr = expr.replace(/\s+/g, "");
269
+ // (REC->__data_loc_reason&0xffff) / (REC->__data_loc_reason>>16)
270
+ let m = expr.match(/^REC->(\w+)&0xffff$/);
271
+ if (m) {
272
+ const v = fieldMap[m[1]];
273
+ const n = typeof v === "number" ? v : 0;
274
+ return n & 0xffff;
275
+ }
276
+ m = expr.match(/^REC->(\w+)>>16$/);
277
+ if (m) {
278
+ const v = fieldMap[m[1]];
279
+ const n = typeof v === "number" ? v : 0;
280
+ return (n >>> 16) & 0xffff;
233
281
  }
234
- const name = em[1];
235
- const idxRaw = em[2];
282
+ // REC->field REC->field[idx]
283
+ m = expr.match(/^REC->(\w+)(?:\[(\d+)])?$/);
284
+ if (!m)
285
+ return 0;
286
+ const name = m[1];
287
+ const idxRaw = m[2];
236
288
  const v = fieldMap[name];
237
289
  if (idxRaw !== undefined) {
238
290
  const idx = parseInt(idxRaw, 10);
239
291
  if (Array.isArray(v) && idx >= 0 && idx < v.length) {
240
- values.push(v[idx]);
292
+ return v[idx];
241
293
  }
242
- else {
243
- values.push(0);
244
- }
245
- }
246
- else if (Array.isArray(v)) {
247
- values.push(v[0] ?? 0);
248
- }
249
- else if (v !== undefined) {
250
- values.push(v);
251
- }
252
- else {
253
- values.push(0);
294
+ return 0;
254
295
  }
296
+ if (Array.isArray(v))
297
+ return v[0] ?? 0;
298
+ return v ?? 0;
299
+ }
300
+ for (const expr of printArgs ?? []) {
301
+ values.push(evalExpr(expr));
255
302
  }
256
303
  let valueIdx = 0;
257
- return printFmt.replace(/%[0-9]*[lh]*([duxX])/g, (_all, spec) => {
304
+ return printFmt.replace(/%[0-9]*[lh]*([duxXsS])/g, (_all, spec) => {
258
305
  const v = values[valueIdx++] ?? 0;
259
306
  return formatArgBySpecifier(v, spec);
260
307
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hiperf_txt_parser",
3
- "version": "1.0.8",
3
+ "version": "1.0.9",
4
4
  "description": "Parse perf data.txt and output structured TypeScript data",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",