Skip to content

Commit dea82ab

Browse files
Rewrite computeSelfTime to improve performance on Trace Statistics page
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 Signed-off-by: Damian Maslanka <[email protected]>
1 parent a80c328 commit dea82ab

File tree

1 file changed

+41
-16
lines changed

1 file changed

+41
-16
lines changed

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

Lines changed: 41 additions & 16 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';
@@ -45,21 +44,47 @@ function getChildOfSpans(parentID: string, allSpans: Span[]): Span[] {
4544

4645
function computeSelfTime(span: Span, allSpans: Span[]): number {
4746
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);
47+
48+
let spanSelfTime = span.duration;
49+
let previousSpanEndTime = span.startTime;
50+
51+
const children = getChildOfSpans(span.spanID, allSpans).sort((a,b) => a.startTime - b.startTime );
52+
53+
const parentSpanEndTime = span.startTime + span.duration;
54+
55+
for (let index = 0; index < children.length; index++) {
56+
const child = children[index];
57+
58+
const spanEndTime = child.startTime + child.duration;
59+
const spanStartsAfterParentEnded = child.startTime > parentSpanEndTime;
60+
const spanEndsBeforePreviousSpan = spanEndTime < previousSpanEndTime;
61+
if (spanStartsAfterParentEnded || spanEndsBeforePreviousSpan) {
62+
continue;
63+
}
64+
65+
let nonOverlappingStartTime = child.startTime;
66+
let nonOverlappingDuration = child.duration;
67+
68+
const spanStartsBeforePreviousSpanEnds = child.startTime < previousSpanEndTime;
69+
if (spanStartsBeforePreviousSpanEnds) {
70+
const diff = previousSpanEndTime - child.startTime
71+
nonOverlappingDuration = child.duration - diff;
72+
nonOverlappingStartTime = previousSpanEndTime;
73+
}
74+
// last span which can be included in self time calculation, because it ends after parent span ends
75+
else if (spanEndTime > parentSpanEndTime) {
76+
const diff = spanEndTime - parentSpanEndTime
77+
78+
nonOverlappingDuration = child.duration - diff;
79+
spanSelfTime -= nonOverlappingDuration
80+
break;
81+
}
82+
83+
spanSelfTime -= nonOverlappingDuration
84+
previousSpanEndTime = nonOverlappingStartTime + nonOverlappingDuration;
85+
}
86+
87+
return spanSelfTime
6388
}
6489

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

0 commit comments

Comments
 (0)