Skip to content

Commit

Permalink
Merge pull request #13 from optimyze/jbcrail/add-flamegraph-labels
Browse files Browse the repository at this point in the history
Use block name as labels for flamegraph nodes
  • Loading branch information
rockdaboot authored Feb 10, 2022
2 parents 867b75f + e46e7a5 commit 6b80bbe
Showing 1 changed file with 105 additions and 6 deletions.
111 changes: 105 additions & 6 deletions src/plugins/profiling/server/routes/flamegraph.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,65 @@
* Side Public License, v 1.
*/

function getExeFileName(exe: any, type: number) {
if (exe.FileName === undefined) {
return '';
}
if (exe.FileName !== '') {
return exe.FileName;
}
switch (type) {
case 0:
return '<unsymbolized frame>';
case 1:
return 'Python';
case 2:
return 'PHP';
case 3:
return 'Native';
case 4:
return 'Kernel';
case 5:
return 'JVM/Hotspot';
case 6:
return 'Ruby';
case 7:
return 'Perl';
case 8:
return 'JavaScript';
default:
return '';
}
}

function checkIfStringHasParentheses(s: string) {
return /\(|\)/.test(s);
}

function getFunctionName(frame: any) {
return frame.FunctionName !== '' && !checkIfStringHasParentheses(frame.FunctionName)
? `${frame.FunctionName}()`
: frame.FunctionName;
}

// Generates the label for a flamegraph node
//
// This is slightly modified from the original code in elastic/prodfiler_ui
function getLabel(frame: any, executable: any, type: number) {
if (frame.FunctionName !== '') {
return `${getExeFileName(executable, type)}: ${getFunctionName(frame)} in #${frame.LineNumber}`;
}
return getExeFileName(executable, type);
}

export class FlameGraph {
constructor(events, totalEvents, stackTraces, stackFrames, executables) {
events: any;
totalEvents: any;
stacktraces: any;
stackframes: any;
executables: any;

constructor(events: any, totalEvents: any, stackTraces: any, stackFrames: any, executables: any) {
this.events = events;
this.totalEvents = totalEvents;
this.stacktraces = stackTraces;
Expand All @@ -16,19 +73,61 @@ export class FlameGraph {
}

toElastic() {
// Create a lookup table for stack frames with an appropriate default if
// the corresponding metadata is missing
const frameMap = new Map();
for (let i = 0; i < this.stackframes.length; i++) {
const frame = this.stackframes[i];
if (frame.found) {
frameMap.set(frame._id, frame._source);
} else {
frameMap.set(frame._id, {
FunctionName: '',
LineNumber: 0,
});
}
}

// Create a lookup table for executables with an appropriate default if
// the corresponding metadata is missing
const exeMap = new Map();
for (let i = 0; i < this.executables.length; i++) {
const exe = this.executables[i];
if (exe.found) {
exeMap.set(exe._id, exe._source);
} else {
exeMap.set(exe._id, {
FileName: '',
});
}
}

let leaves = [];

for (const trace of this.stacktraces) {
if (trace.found) {
const pairs = ['root'].concat(trace._source.FrameID).map((item, i) => [i, item]);
const fact = {
id: trace._source.FrameID[trace._source.FrameID.length - 1],
const path = ['root'];
for (let i = 0; i < trace._source.FrameID.length; i++) {
const label = getLabel(
frameMap.get(trace._source.FrameID[i]),
exeMap.get(trace._source.FileID[i]),
trace._source.Type[i]);
if (label.length === 0) {
path.push(trace._source.FrameID[i]);
} else {
path.push(label);
}
}
const leaf = {
id: path[path.length - 1],
value: 1,
depth: trace._source.FrameID.length,
pathFromRoot: Object.fromEntries(pairs),
pathFromRoot: Object.fromEntries(path.map((item, i) => [i, item])),
};
leaves.push(fact);
leaves.push(leaf);
}
}

return { leaves };
}

Expand Down

0 comments on commit 6b80bbe

Please sign in to comment.