hiperf_txt_parser 1.0.7 → 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.
- package/dist/traceFormat.d.ts +1 -1
- package/dist/traceFormat.js +68 -21
- package/package.json +1 -1
package/dist/traceFormat.d.ts
CHANGED
|
@@ -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
|
*/
|
package/dist/traceFormat.js
CHANGED
|
@@ -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
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
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
|
-
|
|
235
|
-
|
|
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
|
-
|
|
292
|
+
return v[idx];
|
|
241
293
|
}
|
|
242
|
-
|
|
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]*([
|
|
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
|
});
|