mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-11-15 13:58:20 +00:00
fix(studio): count logical media fetches, not ranged reads
A media element pulls one file as a series of ranged reads. Counting raw HTTP requests reported a file fetched once in eight chunks as "8x amplification", and the number got WORSE when a fix deferred a source so the browser later fetched it in pieces: 19 requests became 37 for byte identical content, and the ratio climbed from 2.38x to 4.63x while the actual cost was unchanged. Ranged reads of one URL now collapse into a single logical fetch. Raw and ranged counts stay in the output as diagnostics. Same tree, same fixture: 4.63x becomes 1.13x, which is what the transferred bytes said all along.
This commit is contained in:
@@ -553,7 +553,9 @@ async function recordRequests(client) {
|
||||
};
|
||||
await client.send("Network.enable");
|
||||
client.on("Network.requestWillBeSent", ({ requestId, request, type }) => {
|
||||
pending.set(requestId, { url: request.url, type });
|
||||
const headers = request.headers ?? {};
|
||||
const ranged = Boolean(headers.Range ?? headers.range);
|
||||
pending.set(requestId, { url: request.url, type, ranged });
|
||||
activity.at = Date.now();
|
||||
});
|
||||
client.on("Network.loadingFinished", ({ requestId, encodedDataLength }) =>
|
||||
@@ -575,11 +577,39 @@ async function waitForNetworkQuiet(activity) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A media element fetches one file as a series of ranged reads — that is normal
|
||||
* playback behaviour, not duplication. Counting raw HTTP requests therefore
|
||||
* reports a file pulled once in eight chunks as "8x amplification", and gets
|
||||
* WORSE when a fix defers a source so it is later fetched in pieces.
|
||||
*
|
||||
* What this gate is for is wasted fetching: the same source pulled from scratch
|
||||
* by independent subsystems that do not share a cache. So ranged reads of one
|
||||
* URL collapse into a single logical fetch, and the ratio is built from those.
|
||||
* Raw counts stay in the output as diagnostics.
|
||||
*/
|
||||
function countLogicalFetches(requests) {
|
||||
const rangedUrls = new Set();
|
||||
let fetches = 0;
|
||||
for (const request of requests) {
|
||||
const url = request.url.split("?")[0];
|
||||
if (!request.ranged) {
|
||||
fetches += 1;
|
||||
continue;
|
||||
}
|
||||
if (rangedUrls.has(url)) continue;
|
||||
rangedUrls.add(url);
|
||||
fetches += 1;
|
||||
}
|
||||
return fetches;
|
||||
}
|
||||
|
||||
function summariseRequests(completed, wallClockMs) {
|
||||
const media = completed.filter((request) => MEDIA_EXTENSIONS.test(request.url));
|
||||
const images = completed.filter((request) => IMAGE_EXTENSIONS.test(request.url));
|
||||
const distinct = (requests) => new Set(requests.map((request) => request.url.split("?")[0])).size;
|
||||
const distinctMediaSources = distinct(media);
|
||||
const mediaFetches = countLogicalFetches(media);
|
||||
if (distinctMediaSources === 0) {
|
||||
throw new Error("No media requests observed; the project under test carries no media");
|
||||
}
|
||||
@@ -589,9 +619,11 @@ function summariseRequests(completed, wallClockMs) {
|
||||
requests: completed.length,
|
||||
bytes: sumBytes(completed),
|
||||
mediaRequests: media.length,
|
||||
mediaRangedRequests: media.filter((request) => request.ranged).length,
|
||||
mediaFetches,
|
||||
mediaBytes: sumBytes(media),
|
||||
distinctMediaSources,
|
||||
mediaRequestsPerDistinctSource: round(media.length / distinctMediaSources, 2),
|
||||
mediaRequestsPerDistinctSource: round(mediaFetches / distinctMediaSources, 2),
|
||||
imageRequests: images.length,
|
||||
distinctImageSources: distinct(images),
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user