mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 17:59:23 -04:00
[Profiling] Simplify query post-processing and flamegraph response (#141729)
* Replace non-null assertion with nullish coalescing * Remove createFrameGroup * Remove callers * Use adjacency list representation for tree * Move frame type map outside function * Inline frame group name * Replace FrameGroupID with ID * Create columnar view model in client
This commit is contained in:
parent
90b9afdcee
commit
924c7f912a
14 changed files with 548 additions and 489 deletions
|
@ -8,12 +8,8 @@
|
|||
import { schema } from '@kbn/config-schema';
|
||||
import { RouteRegisterParameters } from '.';
|
||||
import { getRoutePaths } from '../../common';
|
||||
import { createCallerCalleeGraph } from '../../common/callercallee';
|
||||
import {
|
||||
createColumnarCallerCallee,
|
||||
createFlameGraph,
|
||||
ElasticFlameGraph,
|
||||
} from '../../common/flamegraph';
|
||||
import { createCalleeTree } from '../../common/callee';
|
||||
import { createFlameGraph } from '../../common/flamegraph';
|
||||
import { createProfilingEsClient } from '../utils/create_profiling_es_client';
|
||||
import { withProfilingSpan } from '../utils/with_profiling_span';
|
||||
import { getClient } from './compat';
|
||||
|
@ -46,55 +42,57 @@ export function registerFlameChartSearchRoute({ router, logger }: RouteRegisterP
|
|||
});
|
||||
const totalSeconds = timeTo - timeFrom;
|
||||
|
||||
const { stackTraces, executables, stackFrames, eventsIndex, totalCount, stackTraceEvents } =
|
||||
await getExecutablesAndStackTraces({
|
||||
logger,
|
||||
client: createProfilingEsClient({ request, esClient }),
|
||||
filter,
|
||||
sampleSize: targetSampleSize,
|
||||
});
|
||||
const {
|
||||
stackTraces,
|
||||
executables,
|
||||
stackFrames,
|
||||
eventsIndex,
|
||||
totalCount,
|
||||
totalFrames,
|
||||
stackTraceEvents,
|
||||
} = await getExecutablesAndStackTraces({
|
||||
logger,
|
||||
client: createProfilingEsClient({ request, esClient }),
|
||||
filter,
|
||||
sampleSize: targetSampleSize,
|
||||
});
|
||||
|
||||
const flamegraph = await withProfilingSpan('create_flamegraph', async () => {
|
||||
const t0 = Date.now();
|
||||
const graph = createCallerCalleeGraph(
|
||||
const tree = createCalleeTree(
|
||||
stackTraceEvents,
|
||||
stackTraces,
|
||||
stackFrames,
|
||||
executables
|
||||
executables,
|
||||
totalFrames
|
||||
);
|
||||
logger.info(`creating caller-callee graph took ${Date.now() - t0} ms`);
|
||||
logger.info(`creating callee tree took ${Date.now() - t0} ms`);
|
||||
|
||||
// sampleRate is 1/5^N, with N being the downsampled index the events were fetched from.
|
||||
// N=0: full events table (sampleRate is 1)
|
||||
// N=1: downsampled by 5 (sampleRate is 0.2)
|
||||
// ...
|
||||
|
||||
// totalCount is the sum(Count) of all events in the filter range in the
|
||||
// downsampled index we were looking at.
|
||||
// To estimate how many events we have in the full events index: totalCount / sampleRate.
|
||||
// Do the same for single entries in the events array.
|
||||
|
||||
const t1 = Date.now();
|
||||
const columnar = createColumnarCallerCallee(graph);
|
||||
logger.info(`creating columnar caller-callee graph took ${Date.now() - t1} ms`);
|
||||
|
||||
const t2 = Date.now();
|
||||
const fg = createFlameGraph(columnar);
|
||||
logger.info(`creating flamegraph took ${Date.now() - t2} ms`);
|
||||
const fg = createFlameGraph(
|
||||
tree,
|
||||
totalSeconds,
|
||||
Math.floor(totalCount / eventsIndex.sampleRate),
|
||||
totalCount
|
||||
);
|
||||
logger.info(`creating flamegraph took ${Date.now() - t1} ms`);
|
||||
|
||||
return fg;
|
||||
});
|
||||
|
||||
// sampleRate is 1/5^N, with N being the downsampled index the events were fetched from.
|
||||
// N=0: full events table (sampleRate is 1)
|
||||
// N=1: downsampled by 5 (sampleRate is 0.2)
|
||||
// ...
|
||||
|
||||
// totalCount is the sum(Count) of all events in the filter range in the
|
||||
// downsampled index we were looking at.
|
||||
// To estimate how many events we have in the full events index: totalCount / sampleRate.
|
||||
// Do the same for single entries in the events array.
|
||||
|
||||
const body: ElasticFlameGraph = {
|
||||
...flamegraph,
|
||||
TotalSeconds: totalSeconds,
|
||||
TotalTraces: Math.floor(totalCount / eventsIndex.sampleRate),
|
||||
SampledTraces: totalCount,
|
||||
};
|
||||
|
||||
logger.info('returning payload response to client');
|
||||
|
||||
return response.ok({ body });
|
||||
return response.ok({ body: flamegraph });
|
||||
} catch (e) {
|
||||
logger.error(e);
|
||||
return response.customError({
|
||||
|
|
|
@ -68,7 +68,7 @@ export async function getExecutablesAndStackTraces({
|
|||
stackTraceEvents.set(id, Math.floor(count / (eventsIndex.sampleRate * p)));
|
||||
}
|
||||
|
||||
const { stackTraces, stackFrameDocIDs, executableDocIDs } = await mgetStackTraces({
|
||||
const { stackTraces, totalFrames, stackFrameDocIDs, executableDocIDs } = await mgetStackTraces({
|
||||
logger,
|
||||
client,
|
||||
events: stackTraceEvents,
|
||||
|
@ -86,6 +86,7 @@ export async function getExecutablesAndStackTraces({
|
|||
stackFrames,
|
||||
stackTraceEvents,
|
||||
totalCount,
|
||||
totalFrames,
|
||||
eventsIndex,
|
||||
};
|
||||
});
|
||||
|
|
|
@ -18,6 +18,8 @@ import {
|
|||
ProfilingStackTrace,
|
||||
} from '../../common/elasticsearch';
|
||||
import {
|
||||
emptyExecutable,
|
||||
emptyStackFrame,
|
||||
Executable,
|
||||
FileID,
|
||||
StackFrame,
|
||||
|
@ -310,7 +312,7 @@ export async function mgetStackTraces({
|
|||
);
|
||||
}
|
||||
|
||||
return { stackTraces, stackFrameDocIDs, executableDocIDs };
|
||||
return { stackTraces, totalFrames, stackFrameDocIDs, executableDocIDs };
|
||||
}
|
||||
|
||||
export async function mgetStackFrames({
|
||||
|
@ -352,13 +354,7 @@ export async function mgetStackFrames({
|
|||
});
|
||||
framesFound++;
|
||||
} else {
|
||||
stackFrames.set(frame._id, {
|
||||
FileName: '',
|
||||
FunctionName: '',
|
||||
FunctionOffset: 0,
|
||||
LineNumber: 0,
|
||||
SourceType: 0,
|
||||
});
|
||||
stackFrames.set(frame._id, emptyStackFrame);
|
||||
}
|
||||
}
|
||||
logger.info(`processing data took ${Date.now() - t0} ms`);
|
||||
|
@ -403,9 +399,7 @@ export async function mgetExecutables({
|
|||
});
|
||||
exeFound++;
|
||||
} else {
|
||||
executables.set(exe._id, {
|
||||
FileName: '',
|
||||
});
|
||||
executables.set(exe._id, emptyExecutable);
|
||||
}
|
||||
}
|
||||
logger.info(`processing data took ${Date.now() - t0} ms`);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue