Skip to content

Commit d008963

Browse files
committed
Refactor OptionalValue
1 parent 9800fa1 commit d008963

File tree

1 file changed

+49
-40
lines changed

1 file changed

+49
-40
lines changed

extensions/ql-vscode/src/view/compare-performance/ComparePerformance.tsx

Lines changed: 49 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,14 @@ const enum AbsentReason {
2020
Sentinel = "Sentinel",
2121
}
2222

23-
interface OptionalValue {
24-
absentReason: AbsentReason | undefined;
25-
tuples: number;
23+
type Optional<T> = AbsentReason | T;
24+
25+
function isPresent<T>(x: Optional<T>): x is T {
26+
return typeof x !== "string";
2627
}
2728

28-
interface PredicateInfo extends OptionalValue {
29+
interface PredicateInfo {
30+
tuples: number;
2931
evaluationCount: number;
3032
iterationCount: number;
3133
timeCost: number;
@@ -47,41 +49,32 @@ class ComparisonDataset {
4749
this.sentinelEmptyIndices = new Set(data.sentinelEmptyIndices);
4850
}
4951

50-
getTupleCountInfo(name: string): PredicateInfo {
52+
getTupleCountInfo(name: string): Optional<PredicateInfo> {
5153
const { data, nameToIndex, cacheHitIndices, sentinelEmptyIndices } = this;
5254
const index = nameToIndex.get(name);
5355
if (index == null) {
54-
return {
55-
evaluationCount: 0,
56-
iterationCount: 0,
57-
tuples: 0,
58-
timeCost: 0,
59-
absentReason: AbsentReason.NotSeen,
60-
pipelines: {},
61-
};
56+
return AbsentReason.NotSeen;
6257
}
6358
const tupleCost = data.tupleCosts[index];
64-
let absentReason: AbsentReason | undefined;
6559
if (tupleCost === 0) {
6660
if (sentinelEmptyIndices.has(index)) {
67-
absentReason = AbsentReason.Sentinel;
61+
return AbsentReason.Sentinel;
6862
} else if (cacheHitIndices.has(index)) {
69-
absentReason = AbsentReason.CacheHit;
63+
return AbsentReason.CacheHit;
7064
}
7165
}
7266
return {
7367
evaluationCount: data.evaluationCounts[index],
7468
iterationCount: data.iterationCounts[index],
7569
timeCost: data.timeCosts[index],
7670
tuples: tupleCost,
77-
absentReason,
7871
pipelines: data.pipelineSummaryList[index],
7972
};
8073
}
8174
}
8275

83-
function renderAbsoluteValue(x: PredicateInfo, metric: Metric) {
84-
switch (x.absentReason) {
76+
function renderAbsoluteValue(x: Optional<PredicateInfo>, metric: Metric) {
77+
switch (x) {
8578
case AbsentReason.NotSeen:
8679
return <AbsentNumberCell>n/a</AbsentNumberCell>;
8780
case AbsentReason.CacheHit:
@@ -251,17 +244,18 @@ const HeaderTR = styled.tr`
251244
`;
252245

253246
interface HighLevelStatsProps {
254-
before: PredicateInfo;
255-
after: PredicateInfo;
247+
before: Optional<PredicateInfo>;
248+
after: Optional<PredicateInfo>;
256249
comparison: boolean;
257250
}
258251

259252
function HighLevelStats(props: HighLevelStatsProps) {
260253
const { before, after, comparison } = props;
261-
const hasBefore = before.absentReason !== AbsentReason.NotSeen;
262-
const hasAfter = after.absentReason !== AbsentReason.NotSeen;
254+
const hasBefore = isPresent(before);
255+
const hasAfter = isPresent(after);
263256
const showEvaluationCount =
264-
before.evaluationCount > 1 || after.evaluationCount > 1;
257+
(hasBefore && before.evaluationCount > 1) ||
258+
(hasAfter && after.evaluationCount > 1);
265259
return (
266260
<>
267261
<HeaderTR>
@@ -275,15 +269,19 @@ function HighLevelStats(props: HighLevelStatsProps) {
275269
</HeaderTR>
276270
{showEvaluationCount && (
277271
<PipelineStep
278-
before={before.evaluationCount || undefined}
279-
after={after.evaluationCount || undefined}
272+
before={hasBefore ? before.evaluationCount : undefined}
273+
after={hasAfter ? after.evaluationCount : undefined}
280274
comparison={comparison}
281275
step="Number of evaluations"
282276
/>
283277
)}
284278
<PipelineStep
285-
before={before.iterationCount / before.evaluationCount || undefined}
286-
after={after.iterationCount / after.evaluationCount || undefined}
279+
before={
280+
hasBefore ? before.iterationCount / before.evaluationCount : undefined
281+
}
282+
after={
283+
hasAfter ? after.iterationCount / after.evaluationCount : undefined
284+
}
287285
comparison={comparison}
288286
step={
289287
showEvaluationCount
@@ -297,8 +295,8 @@ function HighLevelStats(props: HighLevelStatsProps) {
297295

298296
interface TRow {
299297
name: string;
300-
before: PredicateInfo;
301-
after: PredicateInfo;
298+
before: Optional<PredicateInfo>;
299+
after: Optional<PredicateInfo>;
302300
diff: number;
303301
}
304302

@@ -332,14 +330,23 @@ const metrics: Record<string, Metric> = {
332330
iterations: {
333331
title: "Iterations (per evaluation)",
334332
get: (info) =>
335-
info.absentReason ? 0 : info.iterationCount / info.evaluationCount,
333+
info.evaluationCount === 0
334+
? 0
335+
: info.iterationCount / info.evaluationCount,
336336
},
337337
iterationsTotal: {
338338
title: "Iterations (total)",
339339
get: (info) => info.iterationCount,
340340
},
341341
};
342342

343+
function metricGetOptional(
344+
metric: Metric,
345+
value: Optional<PredicateInfo>,
346+
): Optional<number> {
347+
return isPresent(value) ? metric.get(value) : value;
348+
}
349+
343350
function Chevron({ expanded }: { expanded: boolean }) {
344351
return <Codicon name={expanded ? "chevron-down" : "chevron-right"} />;
345352
}
@@ -419,21 +426,23 @@ function ComparePerformanceWithData(props: {
419426
.map((name) => {
420427
const before = from.getTupleCountInfo(name);
421428
const after = to.getTupleCountInfo(name);
422-
const beforeValue = metric.get(before);
423-
const afterValue = metric.get(after);
429+
const beforeValue = metricGetOptional(metric, before);
430+
const afterValue = metricGetOptional(metric, after);
424431
if (beforeValue === afterValue) {
425432
return undefined!;
426433
}
427434
if (
428-
before.absentReason === AbsentReason.CacheHit ||
429-
after.absentReason === AbsentReason.CacheHit
435+
before === AbsentReason.CacheHit ||
436+
after === AbsentReason.CacheHit
430437
) {
431438
hasCacheHitMismatch.current = true;
432439
if (hideCacheHits) {
433440
return undefined!;
434441
}
435442
}
436-
const diff = afterValue - beforeValue;
443+
const diff =
444+
(isPresent(afterValue) ? afterValue : 0) -
445+
(isPresent(beforeValue) ? beforeValue : 0);
437446
return { name, before, after, diff } satisfies TRow;
438447
})
439448
.filter((x) => !!x)
@@ -445,8 +454,8 @@ function ComparePerformanceWithData(props: {
445454
let totalAfter = 0;
446455
let totalDiff = 0;
447456
for (const row of rows) {
448-
totalBefore += metric.get(row.before);
449-
totalAfter += metric.get(row.after);
457+
totalBefore += isPresent(row.before) ? metric.get(row.before) : 0;
458+
totalAfter += isPresent(row.after) ? metric.get(row.after) : 0;
450459
totalDiff += row.diff;
451460
}
452461
return { totalBefore, totalAfter, totalDiff };
@@ -543,8 +552,8 @@ function ComparePerformanceWithData(props: {
543552
comparison={comparison}
544553
/>
545554
{collatePipelines(
546-
row.before.pipelines,
547-
row.after.pipelines,
555+
isPresent(row.before) ? row.before.pipelines : {},
556+
isPresent(row.after) ? row.after.pipelines : {},
548557
).map(({ name, first, second }, pipelineIndex) => (
549558
<Fragment key={pipelineIndex}>
550559
<HeaderTR>

0 commit comments

Comments
 (0)