Skip to content

Commit 89b7e79

Browse files
Rewrite computeSelfTime to improve performance on Trace Statistics page (#2767)
Stop using drange For 10k spans, 1s => 1ms, computeSelfTime is no longer visible in a profiler To test: 1. Generate data: go run cmd/tracegen/main.go -service abcd -traces 1 -spans 10000 1. Go to Trace Statistics 1. Change Group By to Operation Name 1. Change Group By to Service Name ## Which problem is this PR solving? Related to #645 ## How was this change tested? - Existing tests ## Before ![image](https://github.com/user-attachments/assets/95b7a6a8-15f1-44db-b303-6ea0fdd942c4) ## After ![image](https://github.com/user-attachments/assets/0cadf309-fee5-4ad2-8a6d-066fa852d39e) --------- Signed-off-by: Damian Maslanka <[email protected]>
1 parent 483d574 commit 89b7e79

File tree

1 file changed

+47
-18
lines changed

1 file changed

+47
-18
lines changed

packages/jaeger-ui/src/components/TracePage/TraceStatistics/tableValues.tsx

Lines changed: 47 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@
1414

1515
import memoizeOne from 'memoize-one';
1616
import _uniq from 'lodash/uniq';
17-
import DRange from 'drange';
1817
import { Trace, Span } from '../../../types/trace';
1918
import { ITableSpan } from './types';
2019
import colorGenerator from '../../../utils/color-generator';
@@ -43,23 +42,53 @@ function getChildOfSpans(parentID: string, allSpans: Span[]): Span[] {
4342
return memoizedParentChildOfMap(allSpans)[parentID] || [];
4443
}
4544

46-
function computeSelfTime(span: Span, allSpans: Span[]): number {
47-
if (!span.hasChildren) return span.duration;
48-
// We want to represent spans as half-open intervals like [startTime, startTime + duration).
49-
// This way the subtraction preserves the right boundaries. However, DRange treats all
50-
// intervals as inclusive. For example,
51-
// range(1, 10).subtract(4, 8) => range([1, 3], [9-10])
52-
// length=(3-1)+(10-9)=2+1=3
53-
// In other words, we took an interval of length=10-1=9 and subtracted length=8-4=4.
54-
// We should've ended up with length 9-4=5, but we got 3.
55-
// To work around that, we multiply start/end times by 10 and subtract one from the end.
56-
// So instead of [1-10] we get [10-99]. This makes the intervals work like half-open.
57-
const spanRange = new DRange(10 * span.startTime, 10 * (span.startTime + span.duration) - 1);
58-
const children = getChildOfSpans(span.spanID, allSpans);
59-
children.forEach(child => {
60-
spanRange.subtract(10 * child.startTime, 10 * (child.startTime + child.duration) - 1);
61-
});
62-
return Math.round(spanRange.length / 10);
45+
function computeSelfTime(parentSpan: Span, allSpans: Span[]): number {
46+
if (!parentSpan.hasChildren) return parentSpan.duration;
47+
48+
let parentSpanSelfTime = parentSpan.duration;
49+
let previousChildEndTime = parentSpan.startTime;
50+
51+
const children = getChildOfSpans(parentSpan.spanID, allSpans).sort((a, b) => a.startTime - b.startTime);
52+
53+
const parentSpanEndTime = parentSpan.startTime + parentSpan.duration;
54+
55+
for (let index = 0; index < children.length; index++) {
56+
const child = children[index];
57+
58+
const childEndTime = child.startTime + child.duration;
59+
const childStartsAfterParentEnded = child.startTime > parentSpanEndTime;
60+
const childEndsBeforePreviousChild = childEndTime < previousChildEndTime;
61+
62+
// parent |..................|
63+
// child |.......| - previousChild
64+
// child |.....| - childEndsBeforePreviousChild is true, skipped
65+
// child |......| - childStartsAfterParentEnded is true, skipped
66+
if (childStartsAfterParentEnded || childEndsBeforePreviousChild) {
67+
continue;
68+
}
69+
70+
// parent |.....................|
71+
// child |.......| - previousChild
72+
// child |.....| - nonOverlappingStartTime is previousChildEndTime
73+
// child |.....| - nonOverlappingStartTime is child.startTime
74+
const nonOverlappingStartTime = Math.max(previousChildEndTime, child.startTime);
75+
const childEndTimeOrParentEndTime = Math.min(parentSpanEndTime, childEndTime);
76+
77+
const nonOverlappingDuration = childEndTimeOrParentEndTime - nonOverlappingStartTime;
78+
parentSpanSelfTime -= nonOverlappingDuration;
79+
80+
// last span which can be included in self time calculation, because it ends after parent span ends
81+
// parent |......................|
82+
// child |.....| - last span included in self time calculation
83+
// child |.........| - skipped
84+
if (childEndTimeOrParentEndTime === parentSpanEndTime) {
85+
break;
86+
}
87+
88+
previousChildEndTime = childEndTime;
89+
}
90+
91+
return parentSpanSelfTime;
6392
}
6493

6594
function computeColumnValues(trace: Trace, span: Span, allSpans: Span[], resultValue: StatsPerTag) {

0 commit comments

Comments
 (0)