@@ -35,6 +35,8 @@ function isPresent<T>(x: Optional<T>): x is T {
35
35
}
36
36
37
37
interface PredicateInfo {
38
+ name : string ;
39
+ raHash : string ;
38
40
tuples : number ;
39
41
evaluationCount : number ;
40
42
iterationCount : number ;
@@ -43,23 +45,37 @@ interface PredicateInfo {
43
45
}
44
46
45
47
class ComparisonDataset {
48
+ /**
49
+ * Predicates indexed by a key consisting of the name and its pipeline hash.
50
+ * Unlike the RA hash, the pipeline hash only depends on the predicate's own pipeline.
51
+ */
52
+ public keyToIndex = new Map < string , number > ( ) ;
53
+ public raToIndex = new Map < string , number > ( ) ;
46
54
public nameToIndex = new Map < string , number > ( ) ;
47
55
public cacheHitIndices : Set < number > ;
48
56
public sentinelEmptyIndices : Set < number > ;
49
57
50
- constructor ( public data : PerformanceComparisonDataFromLog ) {
51
- const { names } = data ;
52
- const { nameToIndex } = this ;
58
+ constructor ( private data : PerformanceComparisonDataFromLog ) {
59
+ const { names, raHashes , pipelineSummaryList } = data ;
60
+ const { keyToIndex , raToIndex , nameToIndex } = this ;
53
61
for ( let i = 0 ; i < names . length ; i ++ ) {
54
- nameToIndex . set ( names [ i ] , i ) ;
62
+ const name = names [ i ] ;
63
+ const pipelineHash = getPipelineSummaryHash ( pipelineSummaryList [ i ] ) ;
64
+ keyToIndex . set ( `${ name } @${ pipelineHash } ` , i ) ;
65
+ nameToIndex . set ( name , i ) ;
66
+ raToIndex . set ( raHashes [ i ] , i ) ;
55
67
}
56
68
this . cacheHitIndices = new Set ( data . cacheHitIndices ) ;
57
69
this . sentinelEmptyIndices = new Set ( data . sentinelEmptyIndices ) ;
58
70
}
59
71
60
- getTupleCountInfo ( name : string ) : Optional < PredicateInfo > {
61
- const { data, nameToIndex, cacheHitIndices, sentinelEmptyIndices } = this ;
62
- const index = nameToIndex . get ( name ) ;
72
+ keys ( ) {
73
+ return Array . from ( this . keyToIndex . keys ( ) ) ;
74
+ }
75
+
76
+ getTupleCountInfo ( key : string ) : Optional < PredicateInfo > {
77
+ const { data, keyToIndex, cacheHitIndices, sentinelEmptyIndices } = this ;
78
+ const index = keyToIndex . get ( key ) ;
63
79
if ( index == null ) {
64
80
return AbsentReason . NotSeen ;
65
81
}
@@ -72,6 +88,8 @@ class ComparisonDataset {
72
88
}
73
89
}
74
90
return {
91
+ name : data . names [ index ] ,
92
+ raHash : data . raHashes [ index ] ,
75
93
evaluationCount : data . evaluationCounts [ index ] ,
76
94
iterationCount : data . iterationCounts [ index ] ,
77
95
timeCost : data . timeCosts [ index ] ,
@@ -336,6 +354,7 @@ function HighLevelStats(props: HighLevelStatsProps) {
336
354
}
337
355
338
356
interface Row {
357
+ key : string ;
339
358
name : string ;
340
359
before : Optional < PredicateInfo > ;
341
360
after : Optional < PredicateInfo > ;
@@ -480,19 +499,16 @@ function ComparePerformanceWithData(props: {
480
499
481
500
const [ isPerEvaluation , setPerEvaluation ] = useState ( false ) ;
482
501
483
- const nameSet = useMemo (
484
- ( ) => union ( from . data . names , to . data . names ) ,
485
- [ from , to ] ,
486
- ) ;
502
+ const keySet = useMemo ( ( ) => union ( from . keys ( ) , to . keys ( ) ) , [ from , to ] ) ;
487
503
488
504
const hasCacheHitMismatch = useRef ( false ) ;
489
505
490
506
const rows : Row [ ] = useMemo ( ( ) => {
491
507
hasCacheHitMismatch . current = false ;
492
- return Array . from ( nameSet )
493
- . map ( ( name ) => {
494
- const before = from . getTupleCountInfo ( name ) ;
495
- const after = to . getTupleCountInfo ( name ) ;
508
+ return Array . from ( keySet )
509
+ . map ( ( key ) => {
510
+ const before = from . getTupleCountInfo ( key ) ;
511
+ const after = to . getTupleCountInfo ( key ) ;
496
512
const beforeValue = metricGetOptional ( metric , before , isPerEvaluation ) ;
497
513
const afterValue = metricGetOptional ( metric , after , isPerEvaluation ) ;
498
514
if ( beforeValue === afterValue ) {
@@ -510,11 +526,16 @@ function ComparePerformanceWithData(props: {
510
526
const diff =
511
527
( isPresent ( afterValue ) ? afterValue : 0 ) -
512
528
( isPresent ( beforeValue ) ? beforeValue : 0 ) ;
513
- return { name, before, after, diff } satisfies Row ;
529
+ const name = isPresent ( before )
530
+ ? before . name
531
+ : isPresent ( after )
532
+ ? after . name
533
+ : key ;
534
+ return { key, name, before, after, diff } satisfies Row ;
514
535
} )
515
536
. filter ( ( x ) => ! ! x )
516
537
. sort ( getSortOrder ( sortOrder ) ) ;
517
- } , [ nameSet , from , to , metric , hideCacheHits , sortOrder , isPerEvaluation ] ) ;
538
+ } , [ keySet , from , to , metric , hideCacheHits , sortOrder , isPerEvaluation ] ) ;
518
539
519
540
const { totalBefore, totalAfter, totalDiff } = useMemo ( ( ) => {
520
541
let totalBefore = 0 ;
@@ -860,3 +881,14 @@ function collatePipelines(
860
881
function samePipeline ( a : string [ ] , b : string [ ] ) {
861
882
return a . length === b . length && a . every ( ( x , i ) => x === b [ i ] ) ;
862
883
}
884
+
885
+ function getPipelineSummaryHash ( pipelines : Record < string , PipelineSummary > ) {
886
+ // Note: we can't import "crypto" here because it is not available in the browser,
887
+ // so we just concatenate the hashes of the individual pipelines.
888
+ const keys = Object . keys ( pipelines ) . sort ( ) ;
889
+ let result = "" ;
890
+ for ( const key of keys ) {
891
+ result += `${ pipelines [ key ] . hash } ;` ;
892
+ }
893
+ return result ;
894
+ }
0 commit comments