v145 · Web APIs · Performance

Enabling Web Applications to understand bimodal performance timings

Chrome 145 adds APIs that let web applications detect when their performance data follows a bimodal distribution — identifying fast cached responses versus slow network fetches — rather than averaging across both populations.

background

Many performance metrics follow a bimodal distribution: a cluster of fast responses (cache hits, warm connections) and a cluster of slow responses (cold fetches, DNS lookup, TCP setup). Averaging both together produces a mean that doesn't represent either experience.

Chrome 145 provides additional timing resolution — including extended Resource Timing fields — that allows applications to programmatically detect bimodal patterns and present separate percentiles for each population, rather than a misleading aggregate.

concepts

  1. Bimodal Demo

    Collects resource timing entries for a set of repeated fetches, plots the distribution, and applies a simple K-means split to separate the fast and slow populations.

  2. Timing Analysis

    How to read Resource Timing entries to distinguish cache hits from network fetches, which fields reveal which phase, and how to compute per-population percentiles.

  3. Distribution Detector

    Run pre-canned or real fetch workloads, draw a live histogram, and let a 2-mean clustering verdict tell you whether the data is bimodal — and therefore whether overall median/p95 are misleading.

  4. Cache vs Network

    Fetches the same resource repeatedly and classifies each response as memory cache, disk cache, or network using transferSize and connectStart. The dot chart reveals two populations — and why averaging them produces a meaningless metric.

the change

// Resource Timing entry provides phase breakdown
// Use these to separate cache hits from network fetches:

const entries = performance.getEntriesByType('resource');
const fast = [], slow = [];

for (const e of entries) {
  // transferSize === 0 → served from cache (memory or disk)
  if (e.transferSize === 0 && e.encodedBodySize > 0) {
    fast.push(e.duration);
  } else {
    slow.push(e.duration);
  }
}

// Chrome 145 adds more granular timing to distinguish:
// - Memory cache (near 0ms, connectStart === 0)
// - Disk cache (few ms, connectStart === 0)
// - Network (>20ms, full phase breakdown available)

const p50fast = percentile(fast, 0.5);
const p50slow = percentile(slow, 0.5);
console.log('Fast p50:', p50fast, 'Slow p50:', p50slow);

references