1
1
const EMBEDDED_DATA = { { FLAMEGRAPH_DATA } } ;
2
2
3
+ // Global string table for resolving string indices
4
+ let stringTable = [ ] ;
5
+
6
+ // Function to resolve string indices to actual strings
7
+ function resolveString ( index ) {
8
+ if ( typeof index === 'number' && index >= 0 && index < stringTable . length ) {
9
+ return stringTable [ index ] ;
10
+ }
11
+ // Fallback for non-indexed strings or invalid indices
12
+ return String ( index ) ;
13
+ }
14
+
15
+ // Function to recursively resolve all string indices in flamegraph data
16
+ function resolveStringIndices ( node ) {
17
+ if ( ! node ) return node ;
18
+
19
+ // Create a copy to avoid mutating the original
20
+ const resolved = { ...node } ;
21
+
22
+ // Resolve string fields
23
+ if ( typeof resolved . name === 'number' ) {
24
+ resolved . name = resolveString ( resolved . name ) ;
25
+ }
26
+ if ( typeof resolved . filename === 'number' ) {
27
+ resolved . filename = resolveString ( resolved . filename ) ;
28
+ }
29
+ if ( typeof resolved . funcname === 'number' ) {
30
+ resolved . funcname = resolveString ( resolved . funcname ) ;
31
+ }
32
+
33
+ // Resolve source lines if present
34
+ if ( Array . isArray ( resolved . source ) ) {
35
+ resolved . source = resolved . source . map ( index =>
36
+ typeof index === 'number' ? resolveString ( index ) : index
37
+ ) ;
38
+ }
39
+
40
+ // Recursively resolve children
41
+ if ( Array . isArray ( resolved . children ) ) {
42
+ resolved . children = resolved . children . map ( child => resolveStringIndices ( child ) ) ;
43
+ }
44
+
45
+ return resolved ;
46
+ }
47
+
3
48
// Python color palette - cold to hot
4
49
const pythonColors = [
5
50
"#fff4bf" , // Coldest - light yellow (<1%)
@@ -100,6 +145,10 @@ function createPythonTooltip(data) {
100
145
</div>` ;
101
146
}
102
147
148
+ // Resolve strings for display
149
+ const funcname = resolveString ( d . data . funcname ) || resolveString ( d . data . name ) ;
150
+ const filename = resolveString ( d . data . filename ) || "" ;
151
+
103
152
const tooltipHTML = `
104
153
<div>
105
154
<div style="color: #3776ab; font-weight: 600; font-size: 16px;
@@ -257,9 +306,9 @@ function updateSearchHighlight(searchTerm, searchInput) {
257
306
let matchCount = 0 ;
258
307
d3 . selectAll ( "#chart rect" ) . each ( function ( d ) {
259
308
if ( d && d . data ) {
260
- const name = d . data . name || "" ;
261
- const funcname = d . data . funcname || "" ;
262
- const filename = d . data . filename || "" ;
309
+ const name = resolveString ( d . data . name ) || "" ;
310
+ const funcname = resolveString ( d . data . funcname ) || "" ;
311
+ const filename = resolveString ( d . data . filename ) || "" ;
263
312
const term = searchTerm . toLowerCase ( ) ;
264
313
const matches =
265
314
name . toLowerCase ( ) . includes ( term ) ||
@@ -317,12 +366,20 @@ function handleResize(chart, data) {
317
366
318
367
function initFlamegraph ( ) {
319
368
ensureLibraryLoaded ( ) ;
320
- const tooltip = createPythonTooltip ( EMBEDDED_DATA ) ;
321
- const chart = createFlamegraph ( tooltip , EMBEDDED_DATA . value ) ;
322
- renderFlamegraph ( chart , EMBEDDED_DATA ) ;
369
+
370
+ // Extract string table if present and resolve string indices
371
+ let processedData = EMBEDDED_DATA ;
372
+ if ( EMBEDDED_DATA . strings ) {
373
+ stringTable = EMBEDDED_DATA . strings ;
374
+ processedData = resolveStringIndices ( EMBEDDED_DATA ) ;
375
+ }
376
+
377
+ const tooltip = createPythonTooltip ( processedData ) ;
378
+ const chart = createFlamegraph ( tooltip , processedData . value ) ;
379
+ renderFlamegraph ( chart , processedData ) ;
323
380
attachPanelControls ( ) ;
324
381
initSearchHandlers ( ) ;
325
- handleResize ( chart , EMBEDDED_DATA ) ;
382
+ handleResize ( chart , processedData ) ;
326
383
}
327
384
328
385
if ( document . readyState === "loading" ) {
@@ -338,7 +395,10 @@ function populateStats(data) {
338
395
const functionMap = new Map ( ) ;
339
396
340
397
function collectFunctions ( node ) {
341
- if ( node . filename && node . funcname ) {
398
+ const filename = resolveString ( node . filename ) ;
399
+ const funcname = resolveString ( node . funcname ) ;
400
+
401
+ if ( filename && funcname ) {
342
402
// Calculate direct samples (this node's value minus children's values)
343
403
let childrenValue = 0 ;
344
404
if ( node . children ) {
@@ -347,23 +407,23 @@ function populateStats(data) {
347
407
const directSamples = Math . max ( 0 , node . value - childrenValue ) ;
348
408
349
409
// Use file:line:funcname as key to ensure uniqueness
350
- const funcKey = `${ node . filename } :${ node . lineno || '?' } :${ node . funcname } ` ;
410
+ const funcKey = `${ filename } :${ node . lineno || '?' } :${ funcname } ` ;
351
411
352
412
if ( functionMap . has ( funcKey ) ) {
353
413
const existing = functionMap . get ( funcKey ) ;
354
414
existing . directSamples += directSamples ;
355
415
existing . directPercent = ( existing . directSamples / totalSamples ) * 100 ;
356
416
// Keep the most representative file/line (the one with more samples)
357
417
if ( directSamples > existing . maxSingleSamples ) {
358
- existing . filename = node . filename ;
418
+ existing . filename = filename ;
359
419
existing . lineno = node . lineno || '?' ;
360
420
existing . maxSingleSamples = directSamples ;
361
421
}
362
422
} else {
363
423
functionMap . set ( funcKey , {
364
- filename : node . filename ,
424
+ filename : filename ,
365
425
lineno : node . lineno || '?' ,
366
- funcname : node . funcname ,
426
+ funcname : funcname ,
367
427
directSamples,
368
428
directPercent : ( directSamples / totalSamples ) * 100 ,
369
429
maxSingleSamples : directSamples
0 commit comments