@best/runner-headless
Version:
Best Runner (Headless)
121 lines • 4.68 kB
JavaScript
;
/*
* Copyright (c) 2019, salesforce.com, inc.
* All rights reserved.
* SPDX-License-Identifier: MIT
* For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/MIT
*/
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.removeTrace = exports.mergeTracedMetrics = exports.parseTrace = void 0;
const fs_1 = __importDefault(require("fs"));
const util_1 = require("util");
const types_1 = require("@best/types");
const asyncReadFile = (0, util_1.promisify)(fs_1.default.readFile);
const asyncUnlink = (0, util_1.promisify)(fs_1.default.unlink);
const asyncExists = (0, util_1.promisify)(fs_1.default.exists);
const TRACED_METRIC_EVENTS = ['Paint', 'Layout', 'UpdateLayoutTree', 'UpdateLayerTree', 'CompositeLayers'];
const TRACED_EVENT_NAME_ALIAS = { UpdateLayoutTree: 'RecalculateStyles' };
const isBeginPhase = (event) => {
return event.ph.toLowerCase() === 'b';
};
const isEndPhase = (event) => {
return event.ph.toLowerCase() === 'e';
};
const hasDurationPhased = (event) => {
return isBeginPhase(event) || isEndPhase(event);
};
const sumPairedMetrics = (events) => {
let duration = 0;
for (const event of events) {
if (isBeginPhase(event)) {
duration -= event.ts;
}
else if (isEndPhase(event)) {
duration += event.ts;
}
}
return duration;
};
// returns the total duration of all paints or layouts, etc in microseconds
const sumEventDurations = (events) => {
const pairedMetrics = events.filter(hasDurationPhased);
if (pairedMetrics.length > 0 && pairedMetrics.length % 2 === 0) {
return sumPairedMetrics(events);
}
return events.reduce((previous, current) => (previous += current.dur), 0);
};
const parseTrace = async (tracePath) => {
const file = await asyncReadFile(tracePath, 'utf8');
const trace = JSON.parse(file);
const tracedMetricEvents = trace.traceEvents.filter((event) => TRACED_METRIC_EVENTS.includes(event.name) || event.name.includes(`${types_1.BenchmarkMeasureType.Execute}/`));
const sortedEvents = tracedMetricEvents.sort((a, b) => a.ts - b.ts);
const groupedEvents = {};
let currentRun = false;
for (const event of sortedEvents) {
if (currentRun && TRACED_METRIC_EVENTS.includes(event.name)) {
if (groupedEvents[currentRun][event.name]) {
groupedEvents[currentRun][event.name].push(event);
}
else {
groupedEvents[currentRun][event.name] = [event];
}
}
else if (event.name.includes(`${types_1.BenchmarkMeasureType.Execute}/`)) {
if (isBeginPhase(event)) {
currentRun = event.name;
groupedEvents[event.name] = {};
}
else if (isEndPhase(event)) {
currentRun = false;
}
}
}
const tracedMetrics = Object.keys(groupedEvents).reduce((allMetrics, key) => {
const runName = key.replace(`${types_1.BenchmarkMeasureType.Execute}/`, '');
const metrics = Object.keys(groupedEvents[key]).reduce((acc, eventName) => {
const aliasEventName = TRACED_EVENT_NAME_ALIAS[eventName] || eventName;
const name = aliasEventName.toLowerCase();
return {
...acc,
[name]: sumEventDurations(groupedEvents[key][eventName]) / 1000,
};
}, {});
return {
...allMetrics,
[runName]: metrics,
};
}, {});
return tracedMetrics;
};
exports.parseTrace = parseTrace;
const mergeTracedMetricsIntoResultNode = (resultNode, parsedTrace) => {
if (resultNode.type === 'group') {
resultNode.nodes.forEach((node) => {
mergeTracedMetricsIntoResultNode(node, parsedTrace);
});
}
else if (resultNode.type === 'benchmark') {
const nodeTraces = parsedTrace[resultNode.name];
resultNode.metrics = {
...resultNode.metrics,
...nodeTraces,
};
}
};
const mergeTracedMetrics = (benchmarkResults, parsedTrace) => {
benchmarkResults.results.forEach((node) => {
mergeTracedMetricsIntoResultNode(node, parsedTrace);
});
};
exports.mergeTracedMetrics = mergeTracedMetrics;
const removeTrace = async (tracePath) => {
const fileExists = await asyncExists(tracePath);
if (fileExists) {
await asyncUnlink(tracePath);
}
};
exports.removeTrace = removeTrace;
//# sourceMappingURL=trace.js.map