Skip to content

Commit 3f87cf2

Browse files
toschmidtclaude
andcommitted
reweight the combined metric for lukewarm and inapplicable metrics
The Combined score is a weighted geomean of load (10%), data size (10%), cold (20%) and hot (60%) ratios. That unfairly penalizes systems for metrics that don't apply to them, and lets lukewarm "cold" numbers (really warm queries) distort the cold component. Unify the per-metric exclusion rules in a single metricExcludes() helper (stateless from load, in-memory from cold/combined/load, lukewarm from cold, missing data size from size) and reuse it everywhere: - Cold Run metric: lukewarm systems are excluded from the ranking by default. - Combined per-query baseline: the cold-run minimum excludes lukewarm / in-memory systems, so their warm "cold" numbers can't depress the baseline and inflate every true-cold system's cold ratio. min load time / min data size likewise exclude systems that don't qualify. - Combined score: a metric that doesn't apply to a system is dropped and the remaining weights are renormalized, instead of feeding a bogus ratio. Lukewarm systems keep a cold component of 0 with its weight folded into hot (load 10% / size 10% / hot 80%); a stateless engine that still reports a load time (e.g. Polars (Parquet)) drops the load component; etc. The cold term is guarded so an all-lukewarm selection (empty cold baseline) can't poison the score with NaN. The Combined view still shows only the single overall score; the per-component breakdown is added in a follow-up commit. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1 parent ccbcbb1 commit 3f87cf2

1 file changed

Lines changed: 75 additions & 19 deletions

File tree

index.html

Lines changed: 75 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -882,6 +882,33 @@ <h2>Detailed Comparison</h2>
882882
return 60 + Math.abs(x % 240);
883883
}
884884

885+
/// Whether a system is excluded from a given metric. Single source of truth
886+
/// shared by the top-level metric filter (render) and the per-run baseline
887+
/// used inside the Combined metric (renderSummary) so the two never drift.
888+
function metricExcludes(elem, metric) {
889+
const tags = elem.tags || [];
890+
switch (metric) {
891+
case 'size':
892+
/// Can't rank a system that didn't report a data size.
893+
return !(elem.data_size > 1e9);
894+
case 'load':
895+
/// Needs a real load step: skip trivially-fast loads and
896+
/// stateless / in-memory engines that don't persist data.
897+
return !(elem.load_time >= 5) || tags.includes('stateless') || tags.includes('in-memory');
898+
case 'cold':
899+
/// True cold-cache reads only: in-memory engines have nothing to
900+
/// read from storage, and lukewarm runs never flush engine caches.
901+
return tags.includes('in-memory') || tags.includes('lukewarm-cold-run');
902+
case 'combined':
903+
/// Combined still scores lukewarm systems (with the cold component
904+
/// dropped, see below), but in-memory engines are excluded.
905+
return tags.includes('in-memory');
906+
case 'hot':
907+
default:
908+
return false;
909+
}
910+
}
911+
885912
function renderSummary(filtered_data) {
886913
let table = document.getElementById('summary');
887914
clearElement(table);
@@ -897,10 +924,18 @@ <h2>Detailed Comparison</h2>
897924

898925
const baseline_data = [...filtered_data[0].result.keys()].map(query_num =>
899926
[...Array(3).keys()].map(run_num =>
900-
Math.min(...filtered_data.filter(elem => !elem.fake).map(elem => elem.result[query_num]?.[run_num]).filter(x => x != null))));
901-
902-
const min_load_time = Math.min(...filtered_data.map(elem => elem.load_time).filter(x => x && x > 5));
903-
const min_data_size = Math.min(...filtered_data.map(elem => elem.data_size).filter(x => x && x > 1e9));
927+
Math.min(...filtered_data.filter(elem => !elem.fake)
928+
// Apply the same per-metric exclusions to the baseline that the
929+
// standalone metric uses: run 0 is the cold run, runs 1/2 are
930+
// hot. This keeps lukewarm/in-memory systems out of the cold
931+
// baseline so they can't depress the per-query minimum and
932+
// inflate every true-cold system's cold ratio in Combined. In
933+
// the standalone Cold Run metric they're already filtered out.
934+
.filter(elem => !metricExcludes(elem, run_num === 0 ? 'cold' : 'hot'))
935+
.map(elem => elem.result[query_num]?.[run_num]).filter(x => x != null))));
936+
937+
const min_load_time = Math.min(...filtered_data.filter(elem => !metricExcludes(elem, 'load')).map(elem => elem.load_time));
938+
const min_data_size = Math.min(...filtered_data.filter(elem => !metricExcludes(elem, 'size')).map(elem => elem.data_size));
904939

905940
let summaries;
906941
if (selectors.metric == 'load') {
@@ -913,11 +948,39 @@ <h2>Detailed Comparison</h2>
913948
summaries = filtered_data.map(elem => relativeQueryTime(num_queries, baseline_data, elem, selectors.metric));
914949
document.getElementById('time-or-size').innerText = 'time';
915950
} else if (selectors.metric == 'combined') {
916-
summaries = filtered_data.map(elem => Math.exp(
917-
combined_load_time_share * Math.log(elem.load_time >= 5 ? (elem.load_time / min_load_time) : 1) +
918-
combined_data_size_share * Math.log(elem.data_size >= 1e9 ? (elem.data_size / min_data_size) : 2) +
919-
combined_cold_share * Math.log(relativeQueryTime(num_queries, baseline_data, elem, 'cold')) +
920-
combined_hot_share * Math.log(relativeQueryTime(num_queries, baseline_data, elem, 'hot'))));
951+
summaries = filtered_data.map(elem => {
952+
// Exclude metrics that are not applicable to this system from the combined score,
953+
// and reweight the rest so the final score is still on a similar scale. For example,
954+
// lukewarm systems that don't have a true cold run get their cold weight folded
955+
// into hot, so they can still be compared against true cold systems on the hot
956+
// performance they do have without being penalized for the cold performance they
957+
// can't have.
958+
const exclude_cold = metricExcludes(elem, 'cold');
959+
const exclude_load = metricExcludes(elem, 'load');
960+
const exclude_size = metricExcludes(elem, 'size');
961+
962+
const hot_share = exclude_cold ? combined_cold_share + combined_hot_share : combined_hot_share;
963+
let log_sum = hot_share * Math.log(relativeQueryTime(num_queries, baseline_data, elem, 'hot'));
964+
965+
if (!exclude_cold) {
966+
log_sum += combined_cold_share * Math.log(relativeQueryTime(num_queries, baseline_data, elem, 'cold'));
967+
}
968+
969+
if (!exclude_load) {
970+
log_sum += combined_load_time_share * Math.log(elem.load_time / min_load_time);
971+
}
972+
973+
if (!exclude_size) {
974+
log_sum += combined_data_size_share * Math.log(elem.data_size / min_data_size);
975+
}
976+
977+
if (exclude_load || exclude_size) {
978+
const correction = 1 - (exclude_load ? combined_load_time_share : 0) - (exclude_size ? combined_data_size_share : 0);
979+
log_sum = log_sum / correction;
980+
}
981+
982+
return Math.exp(log_sum);
983+
});
921984
document.getElementById('time-or-size').innerText = 'time and data size';
922985
}
923986

@@ -1086,16 +1149,9 @@ <h2>Detailed Comparison</h2>
10861149
((selectors.hardware.cpu && (elem.hardware === "cpu" || !elem.hardware)) || (selectors.hardware.gpu && elem.hardware === "gpu"))
10871150
);
10881151

1089-
/// Filter out unreasonable entries
1090-
if (selectors.metric == 'size') {
1091-
filtered_data = filtered_data.filter(elem => elem.data_size);
1092-
}
1093-
if (selectors.metric == 'load') {
1094-
filtered_data = filtered_data.filter(elem => elem.load_time >= 5 && !elem.tags.includes('stateless'));
1095-
}
1096-
if (selectors.metric == 'cold' || selectors.metric == 'combined' || selectors.metric == 'load') {
1097-
filtered_data = filtered_data.filter(elem => !elem.tags.includes('in-memory'));
1098-
}
1152+
/// Filter out entries that can't be ranked under the selected metric
1153+
/// (see metricExcludes for the per-metric rules).
1154+
filtered_data = filtered_data.filter(elem => !metricExcludes(elem, selectors.metric));
10991155

11001156
let nothing_selected_elem = document.getElementById('nothing-selected');
11011157
if (filtered_data.length == 0) {

0 commit comments

Comments
 (0)