Feature: Add metrics output from puppeteer.
This commit is contained in:
Родитель
db037352ff
Коммит
05a9242aa9
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
|
@ -1,17 +1,34 @@
|
||||||
import fs from 'fs';
|
import fs from 'fs';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
import * as tmp from 'tmp';
|
import * as tmp from 'tmp';
|
||||||
import puppeteer, { Browser, Page } from 'puppeteer';
|
import puppeteer, { Browser, Metrics, Page } from 'puppeteer';
|
||||||
|
|
||||||
import { cook, CookResult, Scenarios, ScenarioConfig } from '../flamegrill';
|
import { cook, Scenarios, ScenarioConfig } from '../flamegrill';
|
||||||
|
import { ScenarioProfile } from '../profile';
|
||||||
import { __unitTestHooks } from '../process/process';
|
import { __unitTestHooks } from '../process/process';
|
||||||
import { findRegressions } from '../analyze/regression';
|
import { analyzeFunctions } from '../analyze/functional';
|
||||||
|
|
||||||
// TODO: these are black box tests for now but should be refactored to be unit tests
|
// TODO: these are black box tests for now but should be refactored to be unit tests
|
||||||
// TODO: modules that output files should be modified not to and wrapped by a centralized file output helper
|
// TODO: modules that output files should be modified not to and wrapped by a centralized file output helper
|
||||||
// TODO: consider also making file output / github / CI integration another package within this repo
|
// TODO: consider also making file output / github / CI integration another package within this repo
|
||||||
|
|
||||||
describe('flamegrill', () => {
|
describe('flamegrill', () => {
|
||||||
|
const testMetrics: Metrics = {
|
||||||
|
Timestamp: 0,
|
||||||
|
Documents: 1,
|
||||||
|
Frames: 2,
|
||||||
|
JSEventListeners: 3,
|
||||||
|
Nodes: 4,
|
||||||
|
LayoutCount: 5,
|
||||||
|
RecalcStyleCount: 6,
|
||||||
|
LayoutDuration: 7,
|
||||||
|
RecalcStyleDuration: 8,
|
||||||
|
ScriptDuration: 9,
|
||||||
|
TaskDuration: 10,
|
||||||
|
JSHeapUsedSize: 11,
|
||||||
|
JSHeapTotalSize: 12
|
||||||
|
}
|
||||||
|
|
||||||
describe('cook', () => {
|
describe('cook', () => {
|
||||||
const profiles = require('../fixtures/profiles.json');
|
const profiles = require('../fixtures/profiles.json');
|
||||||
const util = require('../util');
|
const util = require('../util');
|
||||||
|
@ -28,7 +45,7 @@ describe('flamegrill', () => {
|
||||||
goto: jest.fn(() => {
|
goto: jest.fn(() => {
|
||||||
return Promise.resolve(null);
|
return Promise.resolve(null);
|
||||||
}),
|
}),
|
||||||
metrics: jest.fn(() => Promise.resolve({})),
|
metrics: jest.fn(() => Promise.resolve(testMetrics)),
|
||||||
setDefaultTimeout: jest.fn(() => {})
|
setDefaultTimeout: jest.fn(() => {})
|
||||||
} as unknown as Page;
|
} as unknown as Page;
|
||||||
|
|
||||||
|
@ -73,7 +90,7 @@ describe('flamegrill', () => {
|
||||||
|
|
||||||
it('generates expected output', async () => {
|
it('generates expected output', async () => {
|
||||||
const snapshotsDir = path.join(__dirname, '../fixtures/snapshots');
|
const snapshotsDir = path.join(__dirname, '../fixtures/snapshots');
|
||||||
const expectedResults = require('../fixtures/results.json');
|
const expectedResults = require(path.join(snapshotsDir, 'results.json'));
|
||||||
|
|
||||||
// Set up arr_diff to feed in predefined profiler log fixtures.
|
// Set up arr_diff to feed in predefined profiler log fixtures.
|
||||||
jest.spyOn(util, 'arr_diff').mockImplementation(() => {
|
jest.spyOn(util, 'arr_diff').mockImplementation(() => {
|
||||||
|
@ -94,10 +111,11 @@ describe('flamegrill', () => {
|
||||||
const testResults = await cook(scenarios, scenarioConfig);
|
const testResults = await cook(scenarios, scenarioConfig);
|
||||||
|
|
||||||
// The path will differ for every test run, so remove it before comparing results.
|
// The path will differ for every test run, so remove it before comparing results.
|
||||||
|
removePaths(expectedResults);
|
||||||
removePaths(testResults);
|
removePaths(testResults);
|
||||||
|
|
||||||
// Convenience line left commented out for updating expected output.
|
// Convenience line left commented out for updating expected output.
|
||||||
// fs.writeFileSync(path.join(outdir.name, "results.json"), JSON.stringify(testResults));
|
fs.writeFileSync(path.join(outdir.name, "results.json"), JSON.stringify(testResults));
|
||||||
|
|
||||||
expect(testResults).toEqual(expectedResults);
|
expect(testResults).toEqual(expectedResults);
|
||||||
|
|
||||||
|
@ -107,19 +125,32 @@ describe('flamegrill', () => {
|
||||||
expect(testFiles).toEqual(snapshotFiles);
|
expect(testFiles).toEqual(snapshotFiles);
|
||||||
|
|
||||||
testFiles.forEach(file => {
|
testFiles.forEach(file => {
|
||||||
// Some generated output creates files with \r\n. Some environments spit out \n.
|
let expectedFileContents;
|
||||||
// Ignore line break types when comparing results.
|
let testFileContents;
|
||||||
const analysis = fs.readFileSync(path.join(snapshotsDir, file), 'utf8').split(/\r?\n/g);
|
|
||||||
const output = fs.readFileSync(path.join(outdir.name, file), 'utf8').split(/\r?\n/g);
|
|
||||||
|
|
||||||
expect(output).toEqual(analysis);
|
if(file.includes('.json')) {
|
||||||
|
expectedFileContents = require(path.join(snapshotsDir, file));
|
||||||
|
testFileContents = require(path.join(outdir.name, file));
|
||||||
|
|
||||||
|
// The path will differ for every test run, so remove it before comparing results.
|
||||||
|
removePaths(expectedFileContents);
|
||||||
|
removePaths(testFileContents);
|
||||||
|
} else {
|
||||||
|
// Some generated output creates files with \r\n. Some environments spit out \n.
|
||||||
|
// Ignore line break types when comparing results.
|
||||||
|
expectedFileContents = fs.readFileSync(path.join(snapshotsDir, file), 'utf8').split(/\r?\n/g);
|
||||||
|
testFileContents = fs.readFileSync(path.join(outdir.name, file), 'utf8').split(/\r?\n/g);
|
||||||
|
}
|
||||||
|
|
||||||
|
expect(testFileContents).toEqual(expectedFileContents);
|
||||||
});
|
});
|
||||||
|
|
||||||
expect((testBrowser.close as jest.Mock).mock.calls.length).toEqual(1);
|
expect((testBrowser.close as jest.Mock).mock.calls.length).toEqual(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('errors on invalid profile logs', async () => {
|
it('errors on invalid profile logs', async () => {
|
||||||
const expectedResults = require('../fixtures/errors/errors.json');
|
const snapshotsDir = path.join(__dirname, '../fixtures/errors/snapshots');
|
||||||
|
const expectedResults = require(path.join(snapshotsDir, 'results.json'));
|
||||||
|
|
||||||
// Set up arr_diff to feed in predefined profiler log fixtures.
|
// Set up arr_diff to feed in predefined profiler log fixtures.
|
||||||
jest.spyOn(util, 'arr_diff').mockImplementation(() => {
|
jest.spyOn(util, 'arr_diff').mockImplementation(() => {
|
||||||
|
@ -130,6 +161,7 @@ describe('flamegrill', () => {
|
||||||
const testResults = await cook({ 'test': { scenario: 'testUrl' } }, scenarioConfig);
|
const testResults = await cook({ 'test': { scenario: 'testUrl' } }, scenarioConfig);
|
||||||
|
|
||||||
// The path will differ for every test run, so remove it before comparing results.
|
// The path will differ for every test run, so remove it before comparing results.
|
||||||
|
removePaths(expectedResults);
|
||||||
removePaths(testResults);
|
removePaths(testResults);
|
||||||
|
|
||||||
// Convenience line left commented out for updating expected output.
|
// Convenience line left commented out for updating expected output.
|
||||||
|
@ -137,19 +169,40 @@ describe('flamegrill', () => {
|
||||||
|
|
||||||
expect(testResults).toEqual(expectedResults);
|
expect(testResults).toEqual(expectedResults);
|
||||||
|
|
||||||
|
const snapshotFiles = fs.readdirSync(snapshotsDir);
|
||||||
const testFiles = fs.readdirSync(outdir.name);
|
const testFiles = fs.readdirSync(outdir.name);
|
||||||
expect(testFiles).toEqual(['test.err.txt']);
|
|
||||||
|
expect(testFiles).toEqual(snapshotFiles);
|
||||||
const errorFile = fs.readFileSync(path.join(outdir.name, 'test.err.txt'));
|
|
||||||
expect(errorFile.includes('Error: dispatchLogRow_: Can\'t parse tick,0xfffffffdeb11c0e4,55914,0,0x0,6, integer too large.')).toBeTruthy();
|
|
||||||
|
|
||||||
|
testFiles.forEach(file => {
|
||||||
|
let expectedFileContent;
|
||||||
|
let testFileContent;
|
||||||
|
|
||||||
|
if(file.includes('.json')) {
|
||||||
|
expectedFileContent = require(path.join(snapshotsDir, file));
|
||||||
|
testFileContent = require(path.join(outdir.name, file));
|
||||||
|
|
||||||
|
// The path will differ for every test run, so remove it before comparing results.
|
||||||
|
removePaths(expectedFileContent);
|
||||||
|
removePaths(testFileContent);
|
||||||
|
|
||||||
|
expect(testFileContent).toEqual(expectedFileContent);
|
||||||
|
} else if (file === 'test.err.txt') {
|
||||||
|
const errorFile = fs.readFileSync(path.join(outdir.name, 'test.err.txt'));
|
||||||
|
expect(errorFile.includes('Error: dispatchLogRow_: Can\'t parse tick,0xfffffffdeb11c0e4,55914,0,0x0,6, integer too large.')).toBeTruthy();
|
||||||
|
} else {
|
||||||
|
// Unknown file, test should be updated to check results.
|
||||||
|
expect(file).toEqual('');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
expect((testBrowser.close as jest.Mock).mock.calls.length).toEqual(1);
|
expect((testBrowser.close as jest.Mock).mock.calls.length).toEqual(1);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// These tests are technically redundant with cook tests but are left for now as they may be useful
|
// These tests are technically redundant with cook tests but are left for now as they may be useful
|
||||||
// as unit tests are added.
|
// as unit tests are added.
|
||||||
describe('generateFlamegraph, findRegressions', () => {
|
describe('generateFlamegraph, analyzeFunctions', () => {
|
||||||
const { processProfile } = __unitTestHooks;
|
const { processProfile } = __unitTestHooks;
|
||||||
const profiles = require('../fixtures/profiles.json');
|
const profiles = require('../fixtures/profiles.json');
|
||||||
const snapshotsDir = path.join(__dirname, '../fixtures/snapshots');
|
const snapshotsDir = path.join(__dirname, '../fixtures/snapshots');
|
||||||
|
@ -164,31 +217,37 @@ describe('flamegrill', () => {
|
||||||
|
|
||||||
// TODO: replace with processProfiles?
|
// TODO: replace with processProfiles?
|
||||||
await Promise.all(Object.keys(profiles).map(key => {
|
await Promise.all(Object.keys(profiles).map(key => {
|
||||||
let logfile = require.resolve(path.join('../fixtures', profiles[key].logFile));
|
const profile: ScenarioProfile = {
|
||||||
let outfile = path.join(outdir.name, key);
|
logFile: require.resolve(path.join('../fixtures', profiles[key].logFile)),
|
||||||
return processProfile(logfile, outfile)
|
metrics: testMetrics
|
||||||
|
};
|
||||||
|
const outfile = path.join(outdir.name, key);
|
||||||
|
return processProfile(profile, outfile)
|
||||||
}));
|
}));
|
||||||
|
|
||||||
await Promise.all(Object.keys(profiles).map(key => {
|
await Promise.all(Object.keys(profiles).map(key => {
|
||||||
let logfile = require.resolve(path.join('../fixtures', profiles[key].baseline.logFile));
|
const profile: ScenarioProfile = {
|
||||||
let outfile = path.join(outdir.name, key + '_base');
|
logFile: require.resolve(path.join('../fixtures', profiles[key].baseline.logFile)),
|
||||||
return processProfile(logfile, outfile)
|
metrics: testMetrics
|
||||||
|
};
|
||||||
|
const outfile = path.join(outdir.name, key + '_base');
|
||||||
|
return processProfile(profile, outfile)
|
||||||
}));
|
}));
|
||||||
|
|
||||||
Object.keys(profiles).forEach(key => {
|
Object.keys(profiles).forEach(key => {
|
||||||
// TODO: this code block is duplicating code in flamegrill.ts and should be removed as code is refactored.
|
// TODO: this code block is duplicating code in flamegrill.ts and should be removed as code is refactored.
|
||||||
let datafileBefore = path.join(outdir.name, key + '_base.data.js');
|
let datafileBasline = path.join(outdir.name, key + '_base.data.js');
|
||||||
let datafileAfter = path.join(outdir.name, key + '.data.js');
|
let datafile = path.join(outdir.name, key + '.data.js');
|
||||||
let regressionfile = path.join(outdir.name, key + '.regression.txt');
|
let regressionfile = path.join(outdir.name, key + '.regression.txt');
|
||||||
|
|
||||||
const analysis = findRegressions(datafileBefore, datafileAfter);
|
const analysis = analyzeFunctions(datafileBasline, datafile);
|
||||||
|
|
||||||
if(analysis.isRegression) {
|
if(analysis.isRegression) {
|
||||||
fs.writeFileSync(regressionfile, analysis.summary);
|
fs.writeFileSync(regressionfile, analysis.summary);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const snapshotFiles = fs.readdirSync(snapshotsDir);
|
const snapshotFiles = fs.readdirSync(snapshotsDir).filter(file => file !== 'results.json');
|
||||||
const testFiles = fs.readdirSync(outdir.name);
|
const testFiles = fs.readdirSync(outdir.name);
|
||||||
|
|
||||||
expect(testFiles).toEqual(snapshotFiles);
|
expect(testFiles).toEqual(snapshotFiles);
|
||||||
|
@ -213,7 +272,6 @@ describe('flamegrill', () => {
|
||||||
function removePaths<T>(obj: T) {
|
function removePaths<T>(obj: T) {
|
||||||
Object.keys(obj).forEach(key => {
|
Object.keys(obj).forEach(key => {
|
||||||
if (key.includes('File')) {
|
if (key.includes('File')) {
|
||||||
console.log(`key = ${key}`);
|
|
||||||
obj[key as keyof T] = path.basename(obj[key as keyof T] as any) as any;
|
obj[key as keyof T] = path.basename(obj[key as keyof T] as any) as any;
|
||||||
} else if (obj[key as keyof T] instanceof Object) {
|
} else if (obj[key as keyof T] instanceof Object) {
|
||||||
removePaths(obj[key as keyof T]);
|
removePaths(obj[key as keyof T]);
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { FunctionData, __unitTestHooks } from '../regression';
|
import { FunctionData, __unitTestHooks } from '../functional';
|
||||||
|
|
||||||
const { filterMinifiedNames, filterSystemNames } = __unitTestHooks;
|
const { filterMinifiedNames, filterSystemNames } = __unitTestHooks;
|
||||||
|
|
|
@ -2,15 +2,16 @@ import fs from 'fs';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
|
|
||||||
import { ScenarioConfig } from '../flamegrill';
|
import { ScenarioConfig } from '../flamegrill';
|
||||||
|
import { ScenarioProfiles } from '../profile';
|
||||||
import { ProcessedScenario, ProcessedScenarios } from '../process';
|
import { ProcessedScenario, ProcessedScenarios } from '../process';
|
||||||
|
|
||||||
import { findRegressions, RegressionOutput } from './regression';
|
import { analyzeFunctions, FunctionalAnalysis } from './functional';
|
||||||
|
|
||||||
export interface Analysis {
|
export interface Analysis {
|
||||||
numTicks: number;
|
numTicks: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface RegressionAnalysis extends RegressionOutput {
|
export interface RegressionAnalysis extends FunctionalAnalysis {
|
||||||
regressionFile?: string;
|
regressionFile?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -46,7 +47,7 @@ function analyzeScenario(scenario: ProcessedScenario, scenarioName: string, conf
|
||||||
|
|
||||||
if (scenario.baseline && scenario.baseline.output) {
|
if (scenario.baseline && scenario.baseline.output) {
|
||||||
let numTicksBaseline = getTicks(scenario.baseline.output.dataFile);
|
let numTicksBaseline = getTicks(scenario.baseline.output.dataFile);
|
||||||
let analysis: RegressionAnalysis = findRegressions(scenario.baseline.output.dataFile, scenario.output.dataFile);
|
let analysis: RegressionAnalysis = analyzeFunctions(scenario.baseline.output.dataFile, scenario.output.dataFile);
|
||||||
if (analysis.isRegression) {
|
if (analysis.isRegression) {
|
||||||
analysis.regressionFile = `${scenarioName}.regression.txt`;
|
analysis.regressionFile = `${scenarioName}.regression.txt`;
|
||||||
fs.writeFileSync(path.join(config.outDir, analysis.regressionFile), analysis.summary);
|
fs.writeFileSync(path.join(config.outDir, analysis.regressionFile), analysis.summary);
|
||||||
|
|
|
@ -47,7 +47,7 @@ export interface ProcessedData {
|
||||||
numTicks: number;
|
numTicks: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface RegressionOutput {
|
export interface FunctionalAnalysis {
|
||||||
summary: string;
|
summary: string;
|
||||||
isRegression: boolean;
|
isRegression: boolean;
|
||||||
}
|
}
|
||||||
|
@ -58,11 +58,11 @@ export interface RegressionOutput {
|
||||||
* @param {string} datafileBaseline Baseline data.
|
* @param {string} datafileBaseline Baseline data.
|
||||||
* @param {string} datafile Scenario data.
|
* @param {string} datafile Scenario data.
|
||||||
*/
|
*/
|
||||||
export function findRegressions(datafileBaseline: string, datafile: string): RegressionOutput {
|
export function analyzeFunctions(datafileBaseline: string, datafile: string): FunctionalAnalysis {
|
||||||
let summary = '';
|
let summary = '';
|
||||||
let isRegression = false;
|
let isRegression = false;
|
||||||
const dataBefore = readFlamegraphData(datafileBaseline);
|
const dataBaseline = readFlamegraphData(datafileBaseline);
|
||||||
const dataAfter = readFlamegraphData(datafile);
|
const data = readFlamegraphData(datafile);
|
||||||
|
|
||||||
// TODO: UNIT TESTS FOR EVERYONE!
|
// TODO: UNIT TESTS FOR EVERYONE!
|
||||||
// * function removed making other functions seem to be regressions when overall perf improves
|
// * function removed making other functions seem to be regressions when overall perf improves
|
||||||
|
@ -95,12 +95,12 @@ export function findRegressions(datafileBaseline: string, datafile: string): Reg
|
||||||
const regressions: FunctionRegression[] = [];
|
const regressions: FunctionRegression[] = [];
|
||||||
|
|
||||||
// Analyze data to find new functions and regressions.
|
// Analyze data to find new functions and regressions.
|
||||||
Object.keys(dataAfter.functionsMap).forEach(name => {
|
Object.keys(data.functionsMap).forEach(name => {
|
||||||
// In some scenarios (such as native button), a tick can represent more time than our base thresholds.
|
// In some scenarios (such as native button), a tick can represent more time than our base thresholds.
|
||||||
// In these cases, elevate the base threshold to the tick base * 2.
|
// In these cases, elevate the base threshold to the tick base * 2.
|
||||||
// For example, if base threshold reports new functions at 2% time consumed, but 1 tick is 4% time,
|
// For example, if base threshold reports new functions at 2% time consumed, but 1 tick is 4% time,
|
||||||
// then new functions will only be reported when > 8%.
|
// then new functions will only be reported when > 8%.
|
||||||
const minTicks = Math.min(dataBefore.numTicks, dataAfter.numTicks);
|
const minTicks = Math.min(dataBaseline.numTicks, data.numTicks);
|
||||||
const regressionNew = Math.max(1 / minTicks * 2, regressionNewBase);
|
const regressionNew = Math.max(1 / minTicks * 2, regressionNewBase);
|
||||||
const regressionDiff = Math.max(1 / minTicks * 2, regressionDiffBase);
|
const regressionDiff = Math.max(1 / minTicks * 2, regressionDiffBase);
|
||||||
|
|
||||||
|
@ -109,31 +109,31 @@ export function findRegressions(datafileBaseline: string, datafile: string): Reg
|
||||||
// console.log(`Modified base thresholds: regressionNew = ${regressionNew}, regressionDiff = ${regressionDiff}`);
|
// console.log(`Modified base thresholds: regressionNew = ${regressionNew}, regressionDiff = ${regressionDiff}`);
|
||||||
// }
|
// }
|
||||||
|
|
||||||
const after = dataAfter.functionsMap[name];
|
const functions = data.functionsMap[name];
|
||||||
const before = dataBefore.functionsMap[name];
|
const functionsBaseline = dataBaseline.functionsMap[name];
|
||||||
|
|
||||||
// TODO: This analysis should really account for the entire call hierarchy when comparing rather than just averaging.
|
// TODO: This analysis should really account for the entire call hierarchy when comparing rather than just averaging.
|
||||||
// For now just ignore spurious 1 tick instances by using the same number of instances for both.
|
// For now just ignore spurious 1 tick instances by using the same number of instances for both.
|
||||||
const instances = before ? Math.min(before.instances.length, after.instances.length) : after.instances.length;
|
const instances = functionsBaseline ? Math.min(functionsBaseline.instances.length, functions.instances.length) : functions.instances.length;
|
||||||
const afterTicksNormalized = calcTotalTicksNormalized(after.instances) / instances;
|
const ticksNormalized = calcTotalTicksNormalized(functions.instances) / instances;
|
||||||
|
|
||||||
if (!before) {
|
if (!functionsBaseline) {
|
||||||
if(afterTicksNormalized > regressionNew) {
|
if(ticksNormalized > regressionNew) {
|
||||||
newFunctions.push({ name, displayName: after.displayName });
|
newFunctions.push({ name, displayName: functions.displayName });
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
const beforeTicksNormalized = calcTotalTicksNormalized(before.instances) / instances;
|
const ticksNormalizedBaseline = calcTotalTicksNormalized(functionsBaseline.instances) / instances;
|
||||||
const percDiff = afterTicksNormalized - beforeTicksNormalized;
|
const percDiff = ticksNormalized - ticksNormalizedBaseline;
|
||||||
|
|
||||||
if (percDiff > regressionDiff) {
|
if (percDiff > regressionDiff) {
|
||||||
regressions.push({ name, displayName: after.displayName });
|
regressions.push({ name, displayName: functions.displayName });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
summary += `Results for ${path.basename(datafileBaseline)} => ${path.basename(datafile)}\n\n`;
|
summary += `Results for ${path.basename(datafileBaseline)} => ${path.basename(datafile)}\n\n`;
|
||||||
summary += `numTicks: ${dataBefore.numTicks} => ${dataAfter.numTicks}\n\n`;
|
summary += `numTicks: ${dataBaseline.numTicks} => ${data.numTicks}\n\n`;
|
||||||
|
|
||||||
if (regressions.length === 0 && newFunctions.length === 0) {
|
if (regressions.length === 0 && newFunctions.length === 0) {
|
||||||
summary += 'OK!';
|
summary += 'OK!';
|
||||||
|
@ -143,23 +143,23 @@ export function findRegressions(datafileBaseline: string, datafile: string): Reg
|
||||||
isRegression = true;
|
isRegression = true;
|
||||||
summary += 'Potential Regressions: \n';
|
summary += 'Potential Regressions: \n';
|
||||||
regressions.forEach(regression => {
|
regressions.forEach(regression => {
|
||||||
const after = dataAfter.functionsMap[regression.displayName];
|
const functions = data.functionsMap[regression.displayName];
|
||||||
const before = dataBefore.functionsMap[regression.displayName];
|
const functionsBaseline = dataBaseline.functionsMap[regression.displayName];
|
||||||
|
|
||||||
// Averaging prevents overexaggeration of recurisve functions, but can also underexaggerate their impact.
|
// Averaging prevents overexaggeration of recurisve functions, but can also underexaggerate their impact.
|
||||||
// Averaging can also cause spurious (1 tick samples of obj.computed, what causes these?) of functions to underexaggerate impact.
|
// Averaging can also cause spurious (1 tick samples of obj.computed, what causes these?) of functions to underexaggerate impact.
|
||||||
// TODO: Remove averaging when analysis takes into account call hierarchy.
|
// TODO: Remove averaging when analysis takes into account call hierarchy.
|
||||||
// For now just ignore spurious 1 tick instances by using the same number of instances for both.
|
// For now just ignore spurious 1 tick instances by using the same number of instances for both.
|
||||||
const instances = before ? Math.min(before.instances.length, after.instances.length) : after.instances.length;
|
const instances = functionsBaseline ? Math.min(functionsBaseline.instances.length, functions.instances.length) : functions.instances.length;
|
||||||
const afterTicksNormalized = calcTotalTicksNormalized(after.instances) / instances;
|
const ticksNormalized = calcTotalTicksNormalized(functions.instances) / instances;
|
||||||
const beforeTicksNormalized = before && calcTotalTicksNormalized(before.instances) / instances;
|
const ticksNormalizedBaseline = functionsBaseline && calcTotalTicksNormalized(functionsBaseline.instances) / instances;
|
||||||
|
|
||||||
const beforeTicksDisplay = beforeTicksNormalized ? (beforeTicksNormalized * 100).toFixed(0) : 'not present';
|
const ticksDisplayBaseline = ticksNormalizedBaseline ? (ticksNormalizedBaseline * 100).toFixed(0) : 'not present';
|
||||||
const afterTicksDisplay = afterTicksNormalized && (afterTicksNormalized * 100).toFixed(0);
|
const ticksDisplay = ticksNormalized && (ticksNormalized * 100).toFixed(0);
|
||||||
|
|
||||||
summary += ` ${regression.displayName}` +
|
summary += ` ${regression.displayName}` +
|
||||||
`, time consumed: ${beforeTicksDisplay}% => ` +
|
`, time consumed: ${ticksDisplayBaseline}% => ` +
|
||||||
`${afterTicksDisplay}% \n`;
|
`${ticksDisplay}% \n`;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -167,7 +167,7 @@ export function findRegressions(datafileBaseline: string, datafile: string): Reg
|
||||||
isRegression = true;
|
isRegression = true;
|
||||||
summary += '\nNew Functions: \n';
|
summary += '\nNew Functions: \n';
|
||||||
newFunctions.forEach(newFunction => {
|
newFunctions.forEach(newFunction => {
|
||||||
const ticksNormalized = calcTotalTicksNormalized(dataAfter.functionsMap[newFunction.displayName].instances);
|
const ticksNormalized = calcTotalTicksNormalized(data.functionsMap[newFunction.displayName].instances);
|
||||||
summary += ` ${newFunction.displayName}, time consumed = ${(ticksNormalized * 100).toFixed(0)}%\n`;
|
summary += ` ${newFunction.displayName}, time consumed = ${(ticksNormalized * 100).toFixed(0)}%\n`;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -327,7 +327,7 @@ if (require.main === module) {
|
||||||
});
|
});
|
||||||
|
|
||||||
scenarios.forEach(scenario => {
|
scenarios.forEach(scenario => {
|
||||||
const analysis = findRegressions(path.join(process.cwd(), `${scenario}_base.data.js`), path.join(process.cwd(), `${scenario}.data.js`));
|
const analysis = analyzeFunctions(path.join(process.cwd(), `${scenario}_base.data.js`), path.join(process.cwd(), `${scenario}.data.js`));
|
||||||
console.log(JSON.stringify(analysis));
|
console.log(JSON.stringify(analysis));
|
||||||
// processPerfData(path.join(process.cwd(), `${scenario}_base.js`), path.join(process.cwd(), `${scenario}.js`));
|
// processPerfData(path.join(process.cwd(), `${scenario}_base.js`), path.join(process.cwd(), `${scenario}.js`));
|
||||||
});
|
});
|
|
@ -1,13 +0,0 @@
|
||||||
{
|
|
||||||
"test": {
|
|
||||||
"profile": {
|
|
||||||
"logFile": "error.prof",
|
|
||||||
"metrics": {}
|
|
||||||
},
|
|
||||||
"processed": {
|
|
||||||
"error": {
|
|
||||||
"errorFile": "test.err.txt"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,27 @@
|
||||||
|
{
|
||||||
|
"test": {
|
||||||
|
"profile": {
|
||||||
|
"logFile": "C:\\Users\\Jason\\src\\flamegrill\\packages\\flamegrill\\src\\fixtures\\errors\\error.prof",
|
||||||
|
"metrics": {
|
||||||
|
"Timestamp": 0,
|
||||||
|
"Documents": 1,
|
||||||
|
"Frames": 2,
|
||||||
|
"JSEventListeners": 3,
|
||||||
|
"Nodes": 4,
|
||||||
|
"LayoutCount": 5,
|
||||||
|
"RecalcStyleCount": 6,
|
||||||
|
"LayoutDuration": 7,
|
||||||
|
"RecalcStyleDuration": 8,
|
||||||
|
"ScriptDuration": 9,
|
||||||
|
"TaskDuration": 10,
|
||||||
|
"JSHeapUsedSize": 11,
|
||||||
|
"JSHeapTotalSize": 12
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"processed": {
|
||||||
|
"error": {
|
||||||
|
"errorFile": "C:\\Users\\Jason\\AppData\\Local\\Temp\\tmp-31156P9K1pPOdnx3z\\test.err.txt"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,15 @@
|
||||||
|
C:\Users\Jason\src\flamegrill\packages\flamegrill\lib\tickprocessor.js:880
|
||||||
|
throw e;
|
||||||
|
^
|
||||||
|
|
||||||
|
Error: dispatchLogRow_: Can't parse tick,0xfffffffdeb11c0e4,55914,0,0x0,6, integer too large.
|
||||||
|
at TickProcessor.LogReader.dispatchLogRow_ (C:\Users\Jason\src\flamegrill\packages\flamegrill\lib\tickprocessor.js:835:19)
|
||||||
|
at TickProcessor.LogReader.processLogLine_ (C:\Users\Jason\src\flamegrill\packages\flamegrill\lib\tickprocessor.js:876:12)
|
||||||
|
at TickProcessor.LogReader.processLogLine (C:\Users\Jason\src\flamegrill\packages\flamegrill\lib\tickprocessor.js:736:10)
|
||||||
|
at TickProcessor.processLogFile (C:\Users\Jason\src\flamegrill\packages\flamegrill\lib\tickprocessor.js:2793:10)
|
||||||
|
at Object.<anonymous> (C:\Users\Jason\src\flamegrill\packages\flamegrill\lib\tickprocessor.js:3565:15)
|
||||||
|
at Module._compile (internal/modules/cjs/loader.js:778:30)
|
||||||
|
at Object.Module._extensions..js (internal/modules/cjs/loader.js:789:10)
|
||||||
|
at Module.load (internal/modules/cjs/loader.js:653:32)
|
||||||
|
at tryModuleLoad (internal/modules/cjs/loader.js:593:12)
|
||||||
|
at Function.Module._load (internal/modules/cjs/loader.js:585:3)
|
|
@ -1,678 +0,0 @@
|
||||||
{
|
|
||||||
"BaseButton": {
|
|
||||||
"profile": {
|
|
||||||
"logFile": "isolate-000001C8E897A980-9332-puppeteer.prof",
|
|
||||||
"metrics": {},
|
|
||||||
"baseline": {
|
|
||||||
"logFile": "isolate-000002716F92D960-27048-puppeteer.prof",
|
|
||||||
"metrics": {}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"processed": {
|
|
||||||
"output": {
|
|
||||||
"dataFile": "BaseButton.data.js",
|
|
||||||
"flamegraphFile": "BaseButton.html"
|
|
||||||
},
|
|
||||||
"baseline": {
|
|
||||||
"output": {
|
|
||||||
"dataFile": "BaseButton_base.data.js",
|
|
||||||
"flamegraphFile": "BaseButton_base.html"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"analysis": {
|
|
||||||
"numTicks": 327,
|
|
||||||
"baseline": {
|
|
||||||
"numTicks": 345
|
|
||||||
},
|
|
||||||
"regression": {
|
|
||||||
"summary": "Results for BaseButton_base.data.js => BaseButton.data.js\n\nnumTicks: 345 => 327\n\nOK!",
|
|
||||||
"isRegression": false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"BaseButtonNew": {
|
|
||||||
"profile": {
|
|
||||||
"logFile": "isolate-00000150C15DDCB0-8200-puppeteer.prof",
|
|
||||||
"metrics": {},
|
|
||||||
"baseline": {
|
|
||||||
"logFile": "isolate-000001C7CB0729F0-15316-puppeteer.prof",
|
|
||||||
"metrics": {}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"processed": {
|
|
||||||
"output": {
|
|
||||||
"dataFile": "BaseButtonNew.data.js",
|
|
||||||
"flamegraphFile": "BaseButtonNew.html"
|
|
||||||
},
|
|
||||||
"baseline": {
|
|
||||||
"output": {
|
|
||||||
"dataFile": "BaseButtonNew_base.data.js",
|
|
||||||
"flamegraphFile": "BaseButtonNew_base.html"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"analysis": {
|
|
||||||
"numTicks": 421,
|
|
||||||
"baseline": {
|
|
||||||
"numTicks": 426
|
|
||||||
},
|
|
||||||
"regression": {
|
|
||||||
"summary": "Results for BaseButtonNew_base.data.js => BaseButtonNew.data.js\n\nnumTicks: 426 => 421\n\nOK!",
|
|
||||||
"isRegression": false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"button": {
|
|
||||||
"profile": {
|
|
||||||
"logFile": "isolate-000001FA30C2C060-15348-puppeteer.prof",
|
|
||||||
"metrics": {},
|
|
||||||
"baseline": {
|
|
||||||
"logFile": "isolate-00000218B8DE6280-33408-puppeteer.prof",
|
|
||||||
"metrics": {}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"processed": {
|
|
||||||
"output": {
|
|
||||||
"dataFile": "button.data.js",
|
|
||||||
"flamegraphFile": "button.html"
|
|
||||||
},
|
|
||||||
"baseline": {
|
|
||||||
"output": {
|
|
||||||
"dataFile": "button_base.data.js",
|
|
||||||
"flamegraphFile": "button_base.html"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"analysis": {
|
|
||||||
"numTicks": 26,
|
|
||||||
"baseline": {
|
|
||||||
"numTicks": 28
|
|
||||||
},
|
|
||||||
"regression": {
|
|
||||||
"summary": "Results for button_base.data.js => button.data.js\n\nnumTicks: 28 => 26\n\nOK!",
|
|
||||||
"isRegression": false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"DefaultButton": {
|
|
||||||
"profile": {
|
|
||||||
"logFile": "isolate-0000026F3D5C86F0-32220-puppeteer.prof",
|
|
||||||
"metrics": {},
|
|
||||||
"baseline": {
|
|
||||||
"logFile": "isolate-000001A279165800-31988-puppeteer.prof",
|
|
||||||
"metrics": {}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"processed": {
|
|
||||||
"output": {
|
|
||||||
"dataFile": "DefaultButton.data.js",
|
|
||||||
"flamegraphFile": "DefaultButton.html"
|
|
||||||
},
|
|
||||||
"baseline": {
|
|
||||||
"output": {
|
|
||||||
"dataFile": "DefaultButton_base.data.js",
|
|
||||||
"flamegraphFile": "DefaultButton_base.html"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"analysis": {
|
|
||||||
"numTicks": 455,
|
|
||||||
"baseline": {
|
|
||||||
"numTicks": 528
|
|
||||||
},
|
|
||||||
"regression": {
|
|
||||||
"summary": "Results for DefaultButton_base.data.js => DefaultButton.data.js\n\nnumTicks: 528 => 455\n\nOK!",
|
|
||||||
"isRegression": false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"DefaultButtonNew": {
|
|
||||||
"profile": {
|
|
||||||
"logFile": "isolate-000001976475B760-12772-puppeteer.prof",
|
|
||||||
"metrics": {},
|
|
||||||
"baseline": {
|
|
||||||
"logFile": "isolate-000001AFA4995FB0-8920-puppeteer.prof",
|
|
||||||
"metrics": {}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"processed": {
|
|
||||||
"output": {
|
|
||||||
"dataFile": "DefaultButtonNew.data.js",
|
|
||||||
"flamegraphFile": "DefaultButtonNew.html"
|
|
||||||
},
|
|
||||||
"baseline": {
|
|
||||||
"output": {
|
|
||||||
"dataFile": "DefaultButtonNew_base.data.js",
|
|
||||||
"flamegraphFile": "DefaultButtonNew_base.html"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"analysis": {
|
|
||||||
"numTicks": 882,
|
|
||||||
"baseline": {
|
|
||||||
"numTicks": 923
|
|
||||||
},
|
|
||||||
"regression": {
|
|
||||||
"summary": "Results for DefaultButtonNew_base.data.js => DefaultButtonNew.data.js\n\nnumTicks: 923 => 882\n\nOK!",
|
|
||||||
"isRegression": false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"DetailsRow": {
|
|
||||||
"profile": {
|
|
||||||
"logFile": "isolate-000001C75B30DD10-19448-puppeteer.prof",
|
|
||||||
"metrics": {},
|
|
||||||
"baseline": {
|
|
||||||
"logFile": "isolate-0000016A4F24EAD0-27036-puppeteer.prof",
|
|
||||||
"metrics": {}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"processed": {
|
|
||||||
"output": {
|
|
||||||
"dataFile": "DetailsRow.data.js",
|
|
||||||
"flamegraphFile": "DetailsRow.html"
|
|
||||||
},
|
|
||||||
"baseline": {
|
|
||||||
"output": {
|
|
||||||
"dataFile": "DetailsRow_base.data.js",
|
|
||||||
"flamegraphFile": "DetailsRow_base.html"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"analysis": {
|
|
||||||
"numTicks": 2750,
|
|
||||||
"baseline": {
|
|
||||||
"numTicks": 1471
|
|
||||||
},
|
|
||||||
"regression": {
|
|
||||||
"summary": "Results for DetailsRow_base.data.js => DetailsRow.data.js\n\nnumTicks: 1471 => 2750\n\nPotential Regressions: \n ~DetailsRowBase.render, time consumed: 7% => 30% \n ~getClassNames, time consumed: 1% => 15% \n ~mergeStyleSets, time consumed: 0% => 37% \n ~styleToRegistration, time consumed: 0% => 27% \n",
|
|
||||||
"isRegression": true,
|
|
||||||
"regressionFile": "DetailsRow.regression.txt"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"DetailsRowFast": {
|
|
||||||
"profile": {
|
|
||||||
"logFile": "isolate-000001AB3AA2DE10-28068-puppeteer.prof",
|
|
||||||
"metrics": {},
|
|
||||||
"baseline": {
|
|
||||||
"logFile": "isolate-0000025EBEA9C020-13384-puppeteer.prof",
|
|
||||||
"metrics": {}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"processed": {
|
|
||||||
"output": {
|
|
||||||
"dataFile": "DetailsRowFast.data.js",
|
|
||||||
"flamegraphFile": "DetailsRowFast.html"
|
|
||||||
},
|
|
||||||
"baseline": {
|
|
||||||
"output": {
|
|
||||||
"dataFile": "DetailsRowFast_base.data.js",
|
|
||||||
"flamegraphFile": "DetailsRowFast_base.html"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"analysis": {
|
|
||||||
"numTicks": 2695,
|
|
||||||
"baseline": {
|
|
||||||
"numTicks": 1409
|
|
||||||
},
|
|
||||||
"regression": {
|
|
||||||
"summary": "Results for DetailsRowFast_base.data.js => DetailsRowFast.data.js\n\nnumTicks: 1409 => 2695\n\nPotential Regressions: \n ~DetailsRowBase.render, time consumed: 6% => 27% \n ~extractRules, time consumed: 0% => 20% \n ~getClassNames, time consumed: 1% => 14% \n ~mergeStyleSets, time consumed: 0% => 36% \n ~styleToRegistration, time consumed: 0% => 27% \n",
|
|
||||||
"isRegression": true,
|
|
||||||
"regressionFile": "DetailsRowFast.regression.txt"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"DetailsRowNoStyles": {
|
|
||||||
"profile": {
|
|
||||||
"logFile": "isolate-000001D1BFE31800-24432-puppeteer.prof",
|
|
||||||
"metrics": {},
|
|
||||||
"baseline": {
|
|
||||||
"logFile": "isolate-000001CEF69AFE10-4612-puppeteer.prof",
|
|
||||||
"metrics": {}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"processed": {
|
|
||||||
"output": {
|
|
||||||
"dataFile": "DetailsRowNoStyles.data.js",
|
|
||||||
"flamegraphFile": "DetailsRowNoStyles.html"
|
|
||||||
},
|
|
||||||
"baseline": {
|
|
||||||
"output": {
|
|
||||||
"dataFile": "DetailsRowNoStyles_base.data.js",
|
|
||||||
"flamegraphFile": "DetailsRowNoStyles_base.html"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"analysis": {
|
|
||||||
"numTicks": 1948,
|
|
||||||
"baseline": {
|
|
||||||
"numTicks": 1466
|
|
||||||
},
|
|
||||||
"regression": {
|
|
||||||
"summary": "Results for DetailsRowNoStyles_base.data.js => DetailsRowNoStyles.data.js\n\nnumTicks: 1466 => 1948\n\nPotential Regressions: \n ~CheckBase, time consumed: 1% => 15% \n ~DetailsRowCheckBase, time consumed: 3% => 14% \n\nNew Functions: \n ~mergeStyleSets, time consumed = 23%\n ~styleToRegistration, time consumed = 17%\n",
|
|
||||||
"isRegression": true,
|
|
||||||
"regressionFile": "DetailsRowNoStyles.regression.txt"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"DocumentCardTitle": {
|
|
||||||
"profile": {
|
|
||||||
"logFile": "isolate-000001658015DEE0-9140-puppeteer.prof",
|
|
||||||
"metrics": {},
|
|
||||||
"baseline": {
|
|
||||||
"logFile": "isolate-000002A0A0FDD770-30228-puppeteer.prof",
|
|
||||||
"metrics": {}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"processed": {
|
|
||||||
"output": {
|
|
||||||
"dataFile": "DocumentCardTitle.data.js",
|
|
||||||
"flamegraphFile": "DocumentCardTitle.html"
|
|
||||||
},
|
|
||||||
"baseline": {
|
|
||||||
"output": {
|
|
||||||
"dataFile": "DocumentCardTitle_base.data.js",
|
|
||||||
"flamegraphFile": "DocumentCardTitle_base.html"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"analysis": {
|
|
||||||
"numTicks": 16012,
|
|
||||||
"baseline": {
|
|
||||||
"numTicks": 15919
|
|
||||||
},
|
|
||||||
"regression": {
|
|
||||||
"summary": "Results for DocumentCardTitle_base.data.js => DocumentCardTitle.data.js\n\nnumTicks: 15919 => 16012\n\nOK!",
|
|
||||||
"isRegression": false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"MenuButton": {
|
|
||||||
"profile": {
|
|
||||||
"logFile": "isolate-0000023E414D6CE0-28460-puppeteer.prof",
|
|
||||||
"metrics": {},
|
|
||||||
"baseline": {
|
|
||||||
"logFile": "isolate-000002744B17D570-32064-puppeteer.prof",
|
|
||||||
"metrics": {}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"processed": {
|
|
||||||
"output": {
|
|
||||||
"dataFile": "MenuButton.data.js",
|
|
||||||
"flamegraphFile": "MenuButton.html"
|
|
||||||
},
|
|
||||||
"baseline": {
|
|
||||||
"output": {
|
|
||||||
"dataFile": "MenuButton_base.data.js",
|
|
||||||
"flamegraphFile": "MenuButton_base.html"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"analysis": {
|
|
||||||
"numTicks": 647,
|
|
||||||
"baseline": {
|
|
||||||
"numTicks": 590
|
|
||||||
},
|
|
||||||
"regression": {
|
|
||||||
"summary": "Results for MenuButton_base.data.js => MenuButton.data.js\n\nnumTicks: 590 => 647\n\nOK!",
|
|
||||||
"isRegression": false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"MenuButtonNew": {
|
|
||||||
"profile": {
|
|
||||||
"logFile": "isolate-0000021FD7B39BB0-28188-puppeteer.prof",
|
|
||||||
"metrics": {},
|
|
||||||
"baseline": {
|
|
||||||
"logFile": "isolate-0000028C417C8AC0-24936-puppeteer.prof",
|
|
||||||
"metrics": {}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"processed": {
|
|
||||||
"output": {
|
|
||||||
"dataFile": "MenuButtonNew.data.js",
|
|
||||||
"flamegraphFile": "MenuButtonNew.html"
|
|
||||||
},
|
|
||||||
"baseline": {
|
|
||||||
"output": {
|
|
||||||
"dataFile": "MenuButtonNew_base.data.js",
|
|
||||||
"flamegraphFile": "MenuButtonNew_base.html"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"analysis": {
|
|
||||||
"numTicks": 1548,
|
|
||||||
"baseline": {
|
|
||||||
"numTicks": 1581
|
|
||||||
},
|
|
||||||
"regression": {
|
|
||||||
"summary": "Results for MenuButtonNew_base.data.js => MenuButtonNew.data.js\n\nnumTicks: 1581 => 1548\n\nOK!",
|
|
||||||
"isRegression": false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"PrimaryButton": {
|
|
||||||
"profile": {
|
|
||||||
"logFile": "isolate-00000224DD39CC70-27088-puppeteer.prof",
|
|
||||||
"metrics": {},
|
|
||||||
"baseline": {
|
|
||||||
"logFile": "isolate-00000289B99F90F0-33752-puppeteer.prof",
|
|
||||||
"metrics": {}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"processed": {
|
|
||||||
"output": {
|
|
||||||
"dataFile": "PrimaryButton.data.js",
|
|
||||||
"flamegraphFile": "PrimaryButton.html"
|
|
||||||
},
|
|
||||||
"baseline": {
|
|
||||||
"output": {
|
|
||||||
"dataFile": "PrimaryButton_base.data.js",
|
|
||||||
"flamegraphFile": "PrimaryButton_base.html"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"analysis": {
|
|
||||||
"numTicks": 488,
|
|
||||||
"baseline": {
|
|
||||||
"numTicks": 496
|
|
||||||
},
|
|
||||||
"regression": {
|
|
||||||
"summary": "Results for PrimaryButton_base.data.js => PrimaryButton.data.js\n\nnumTicks: 496 => 488\n\nOK!",
|
|
||||||
"isRegression": false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"PrimaryButtonNew": {
|
|
||||||
"profile": {
|
|
||||||
"logFile": "isolate-000001D40015E310-20784-puppeteer.prof",
|
|
||||||
"metrics": {},
|
|
||||||
"baseline": {
|
|
||||||
"logFile": "isolate-000001C3BAC2EA80-32776-puppeteer.prof",
|
|
||||||
"metrics": {}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"processed": {
|
|
||||||
"output": {
|
|
||||||
"dataFile": "PrimaryButtonNew.data.js",
|
|
||||||
"flamegraphFile": "PrimaryButtonNew.html"
|
|
||||||
},
|
|
||||||
"baseline": {
|
|
||||||
"output": {
|
|
||||||
"dataFile": "PrimaryButtonNew_base.data.js",
|
|
||||||
"flamegraphFile": "PrimaryButtonNew_base.html"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"analysis": {
|
|
||||||
"numTicks": 922,
|
|
||||||
"baseline": {
|
|
||||||
"numTicks": 1001
|
|
||||||
},
|
|
||||||
"regression": {
|
|
||||||
"summary": "Results for PrimaryButtonNew_base.data.js => PrimaryButtonNew.data.js\n\nnumTicks: 1001 => 922\n\nOK!",
|
|
||||||
"isRegression": false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"SplitButton": {
|
|
||||||
"profile": {
|
|
||||||
"logFile": "isolate-000001D2DD15DB40-22696-puppeteer.prof",
|
|
||||||
"metrics": {},
|
|
||||||
"baseline": {
|
|
||||||
"logFile": "isolate-000001292C499B50-24060-puppeteer.prof",
|
|
||||||
"metrics": {}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"processed": {
|
|
||||||
"output": {
|
|
||||||
"dataFile": "SplitButton.data.js",
|
|
||||||
"flamegraphFile": "SplitButton.html"
|
|
||||||
},
|
|
||||||
"baseline": {
|
|
||||||
"output": {
|
|
||||||
"dataFile": "SplitButton_base.data.js",
|
|
||||||
"flamegraphFile": "SplitButton_base.html"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"analysis": {
|
|
||||||
"numTicks": 1293,
|
|
||||||
"baseline": {
|
|
||||||
"numTicks": 1355
|
|
||||||
},
|
|
||||||
"regression": {
|
|
||||||
"summary": "Results for SplitButton_base.data.js => SplitButton.data.js\n\nnumTicks: 1355 => 1293\n\nOK!",
|
|
||||||
"isRegression": false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"SplitButtonNew": {
|
|
||||||
"profile": {
|
|
||||||
"logFile": "isolate-0000027E6DE24B80-31272-puppeteer.prof",
|
|
||||||
"metrics": {},
|
|
||||||
"baseline": {
|
|
||||||
"logFile": "isolate-000002EAD2E39E10-33780-puppeteer.prof",
|
|
||||||
"metrics": {}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"processed": {
|
|
||||||
"output": {
|
|
||||||
"dataFile": "SplitButtonNew.data.js",
|
|
||||||
"flamegraphFile": "SplitButtonNew.html"
|
|
||||||
},
|
|
||||||
"baseline": {
|
|
||||||
"output": {
|
|
||||||
"dataFile": "SplitButtonNew_base.data.js",
|
|
||||||
"flamegraphFile": "SplitButtonNew_base.html"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"analysis": {
|
|
||||||
"numTicks": 3155,
|
|
||||||
"baseline": {
|
|
||||||
"numTicks": 3048
|
|
||||||
},
|
|
||||||
"regression": {
|
|
||||||
"summary": "Results for SplitButtonNew_base.data.js => SplitButtonNew.data.js\n\nnumTicks: 3048 => 3155\n\nOK!",
|
|
||||||
"isRegression": false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"Stack": {
|
|
||||||
"profile": {
|
|
||||||
"logFile": "isolate-000002958EF69420-30340-puppeteer.prof",
|
|
||||||
"metrics": {},
|
|
||||||
"baseline": {
|
|
||||||
"logFile": "isolate-00000199612E7F60-32084-puppeteer.prof",
|
|
||||||
"metrics": {}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"processed": {
|
|
||||||
"output": {
|
|
||||||
"dataFile": "Stack.data.js",
|
|
||||||
"flamegraphFile": "Stack.html"
|
|
||||||
},
|
|
||||||
"baseline": {
|
|
||||||
"output": {
|
|
||||||
"dataFile": "Stack_base.data.js",
|
|
||||||
"flamegraphFile": "Stack_base.html"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"analysis": {
|
|
||||||
"numTicks": 263,
|
|
||||||
"baseline": {
|
|
||||||
"numTicks": 251
|
|
||||||
},
|
|
||||||
"regression": {
|
|
||||||
"summary": "Results for Stack_base.data.js => Stack.data.js\n\nnumTicks: 251 => 263\n\nOK!",
|
|
||||||
"isRegression": false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"StackWithIntrinsicChildren": {
|
|
||||||
"profile": {
|
|
||||||
"logFile": "isolate-000002CB95DF62A0-29024-puppeteer.prof",
|
|
||||||
"metrics": {},
|
|
||||||
"baseline": {
|
|
||||||
"logFile": "isolate-000001F8F52C6E60-30996-puppeteer.prof",
|
|
||||||
"metrics": {}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"processed": {
|
|
||||||
"output": {
|
|
||||||
"dataFile": "StackWithIntrinsicChildren.data.js",
|
|
||||||
"flamegraphFile": "StackWithIntrinsicChildren.html"
|
|
||||||
},
|
|
||||||
"baseline": {
|
|
||||||
"output": {
|
|
||||||
"dataFile": "StackWithIntrinsicChildren_base.data.js",
|
|
||||||
"flamegraphFile": "StackWithIntrinsicChildren_base.html"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"analysis": {
|
|
||||||
"numTicks": 563,
|
|
||||||
"baseline": {
|
|
||||||
"numTicks": 596
|
|
||||||
},
|
|
||||||
"regression": {
|
|
||||||
"summary": "Results for StackWithIntrinsicChildren_base.data.js => StackWithIntrinsicChildren.data.js\n\nnumTicks: 596 => 563\n\nOK!",
|
|
||||||
"isRegression": false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"StackWithTextChildren": {
|
|
||||||
"profile": {
|
|
||||||
"logFile": "isolate-000001E2F953C450-33588-puppeteer.prof",
|
|
||||||
"metrics": {},
|
|
||||||
"baseline": {
|
|
||||||
"logFile": "isolate-000001AA84CA8D20-8016-puppeteer.prof",
|
|
||||||
"metrics": {}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"processed": {
|
|
||||||
"output": {
|
|
||||||
"dataFile": "StackWithTextChildren.data.js",
|
|
||||||
"flamegraphFile": "StackWithTextChildren.html"
|
|
||||||
},
|
|
||||||
"baseline": {
|
|
||||||
"output": {
|
|
||||||
"dataFile": "StackWithTextChildren_base.data.js",
|
|
||||||
"flamegraphFile": "StackWithTextChildren_base.html"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"analysis": {
|
|
||||||
"numTicks": 1978,
|
|
||||||
"baseline": {
|
|
||||||
"numTicks": 1928
|
|
||||||
},
|
|
||||||
"regression": {
|
|
||||||
"summary": "Results for StackWithTextChildren_base.data.js => StackWithTextChildren.data.js\n\nnumTicks: 1928 => 1978\n\nOK!",
|
|
||||||
"isRegression": false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"Text": {
|
|
||||||
"profile": {
|
|
||||||
"logFile": "isolate-00000257772F8820-33584-puppeteer.prof",
|
|
||||||
"metrics": {},
|
|
||||||
"baseline": {
|
|
||||||
"logFile": "isolate-000002236CE1DD30-25244-puppeteer.prof",
|
|
||||||
"metrics": {}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"processed": {
|
|
||||||
"output": {
|
|
||||||
"dataFile": "Text.data.js",
|
|
||||||
"flamegraphFile": "Text.html"
|
|
||||||
},
|
|
||||||
"baseline": {
|
|
||||||
"output": {
|
|
||||||
"dataFile": "Text_base.data.js",
|
|
||||||
"flamegraphFile": "Text_base.html"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"analysis": {
|
|
||||||
"numTicks": 206,
|
|
||||||
"baseline": {
|
|
||||||
"numTicks": 168
|
|
||||||
},
|
|
||||||
"regression": {
|
|
||||||
"summary": "Results for Text_base.data.js => Text.data.js\n\nnumTicks: 168 => 206\n\nOK!",
|
|
||||||
"isRegression": false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"Toggle": {
|
|
||||||
"profile": {
|
|
||||||
"logFile": "isolate-00000248C0C3E090-14868-puppeteer.prof",
|
|
||||||
"metrics": {},
|
|
||||||
"baseline": {
|
|
||||||
"logFile": "isolate-000001FCF48C0980-25140-puppeteer.prof",
|
|
||||||
"metrics": {}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"processed": {
|
|
||||||
"output": {
|
|
||||||
"dataFile": "Toggle.data.js",
|
|
||||||
"flamegraphFile": "Toggle.html"
|
|
||||||
},
|
|
||||||
"baseline": {
|
|
||||||
"output": {
|
|
||||||
"dataFile": "Toggle_base.data.js",
|
|
||||||
"flamegraphFile": "Toggle_base.html"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"analysis": {
|
|
||||||
"numTicks": 882,
|
|
||||||
"baseline": {
|
|
||||||
"numTicks": 454
|
|
||||||
},
|
|
||||||
"regression": {
|
|
||||||
"summary": "Results for Toggle_base.data.js => Toggle.data.js\n\nnumTicks: 454 => 882\n\nPotential Regressions: \n ~ToggleBase.render, time consumed: 9% => 53% \n ~getClassNames, time consumed: 2% => 47% \n ~mergeStyleSets, time consumed: 0% => 39% \n ~obj.<computed>, time consumed: 10% => 53% \n ~styleToRegistration, time consumed: 0% => 29% \n\nNew Functions: \n ~Toggle_styles_getStyles, time consumed = 6%\n ~_resolve, time consumed = 7%\n ~_styles, time consumed = 7%\n ~extractRules, time consumed = 42%\n ~getKeyForRules, time consumed = 8%\n",
|
|
||||||
"isRegression": true,
|
|
||||||
"regressionFile": "Toggle.regression.txt"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"ToggleNew": {
|
|
||||||
"profile": {
|
|
||||||
"logFile": "isolate-000002231747AC50-11576-puppeteer.prof",
|
|
||||||
"metrics": {},
|
|
||||||
"baseline": {
|
|
||||||
"logFile": "isolate-0000014BEA16EDB0-28552-puppeteer.prof",
|
|
||||||
"metrics": {}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"processed": {
|
|
||||||
"output": {
|
|
||||||
"dataFile": "ToggleNew.data.js",
|
|
||||||
"flamegraphFile": "ToggleNew.html"
|
|
||||||
},
|
|
||||||
"baseline": {
|
|
||||||
"output": {
|
|
||||||
"dataFile": "ToggleNew_base.data.js",
|
|
||||||
"flamegraphFile": "ToggleNew_base.html"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"analysis": {
|
|
||||||
"numTicks": 1165,
|
|
||||||
"baseline": {
|
|
||||||
"numTicks": 1102
|
|
||||||
},
|
|
||||||
"regression": {
|
|
||||||
"summary": "Results for ToggleNew_base.data.js => ToggleNew.data.js\n\nnumTicks: 1102 => 1165\n\nOK!",
|
|
||||||
"isRegression": false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -71,6 +71,8 @@ export async function cook(scenarios: Scenarios, userConfig?: ScenarioConfig): P
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
fs.writeFileSync(path.join(config.outDir, 'results.json'), JSON.stringify(results));
|
||||||
|
|
||||||
console.log('results: ');
|
console.log('results: ');
|
||||||
console.dir(results, { depth: null });
|
console.dir(results, { depth: null });
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,56 @@
|
||||||
|
import { Metrics } from 'puppeteer';
|
||||||
|
|
||||||
|
export function addMetrics(flamegraph: string, metrics: Metrics): string {
|
||||||
|
const metricsTableHeader = `
|
||||||
|
<details>
|
||||||
|
<summary>Metrics</summary>
|
||||||
|
<table>
|
||||||
|
<tr>
|
||||||
|
<th>
|
||||||
|
<a href="https://github.com/GoogleChrome/puppeteer/blob/master/docs/api.md#pagemetrics">Metric</a>
|
||||||
|
</th>
|
||||||
|
<th>Value</th>
|
||||||
|
</tr>
|
||||||
|
`;
|
||||||
|
const metricsTableFooter = `
|
||||||
|
</table>
|
||||||
|
</details>
|
||||||
|
`;
|
||||||
|
|
||||||
|
|
||||||
|
const metricsTableContents = Object
|
||||||
|
.keys(metrics)
|
||||||
|
.map(key => {
|
||||||
|
return `
|
||||||
|
<tr>
|
||||||
|
<td>${key}</td>
|
||||||
|
<td>${getFormattedValue(metrics[key as keyof Metrics], key as keyof Metrics)}</td>
|
||||||
|
</tr>
|
||||||
|
`;
|
||||||
|
})
|
||||||
|
.join('');
|
||||||
|
|
||||||
|
const metricsTable = metricsTableHeader + metricsTableContents + metricsTableFooter;
|
||||||
|
|
||||||
|
// Use placeholder in string to add metrics.
|
||||||
|
flamegraph = flamegraph
|
||||||
|
.split('<!-- /* METRICS_PLACEHOLDER */ -->')
|
||||||
|
.join(metricsTable);
|
||||||
|
|
||||||
|
return flamegraph;
|
||||||
|
};
|
||||||
|
|
||||||
|
function getFormattedValue(value: number, key: keyof Metrics): string {
|
||||||
|
switch(key) {
|
||||||
|
case 'JSHeapUsedSize':
|
||||||
|
case 'JSHeapTotalSize':
|
||||||
|
return value.toLocaleString('en') + ' bytes';
|
||||||
|
case 'LayoutDuration':
|
||||||
|
case 'RecalcStyleDuration':
|
||||||
|
case 'ScriptDuration':
|
||||||
|
case 'TaskDuration':
|
||||||
|
return value.toLocaleString('en', { maximumSignificantDigits: 3 }) + ' s';
|
||||||
|
default:
|
||||||
|
return value.toString();
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,10 +2,12 @@ import fs from 'fs';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
import cp from 'child_process';
|
import cp from 'child_process';
|
||||||
import concat from 'concat-stream';
|
import concat from 'concat-stream';
|
||||||
import flamebearer from './flamebearer';
|
|
||||||
|
|
||||||
import { ScenarioConfig } from '../flamegrill';
|
import { ScenarioConfig } from '../flamegrill';
|
||||||
import { ScenarioProfiles } from '../profile';
|
import { ScenarioProfile, ScenarioProfiles } from '../profile';
|
||||||
|
|
||||||
|
import flamebearer from './flamebearer';
|
||||||
|
import { addMetrics } from './metrics';
|
||||||
|
|
||||||
// TODO: is file output good enough here as an API? should this return programmatic results?
|
// TODO: is file output good enough here as an API? should this return programmatic results?
|
||||||
export interface ProcessedOutput {
|
export interface ProcessedOutput {
|
||||||
|
@ -42,10 +44,10 @@ export async function processProfiles(profiles: ScenarioProfiles, config: Requir
|
||||||
const outFileBaseline = path.join(config.outDir, `${scenarioName}_base`);
|
const outFileBaseline = path.join(config.outDir, `${scenarioName}_base`);
|
||||||
const result = profiles[scenarioName];
|
const result = profiles[scenarioName];
|
||||||
|
|
||||||
const processedScenario: ProcessedScenario = await processProfile(result.logFile, outFile);
|
const processedScenario: ProcessedScenario = await processProfile(result, outFile);
|
||||||
|
|
||||||
if(result.baseline) {
|
if(result.baseline) {
|
||||||
processedScenario.baseline = await processProfile(result.baseline.logFile, outFileBaseline);
|
processedScenario.baseline = await processProfile(result.baseline, outFileBaseline);
|
||||||
}
|
}
|
||||||
|
|
||||||
processedScenarios[scenarioName] = processedScenario;
|
processedScenarios[scenarioName] = processedScenario;
|
||||||
|
@ -54,8 +56,8 @@ export async function processProfiles(profiles: ScenarioProfiles, config: Requir
|
||||||
return processedScenarios;
|
return processedScenarios;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function processProfile(logFile: string, outFile: string): Promise<Processed> {
|
async function processProfile(profile: ScenarioProfile, outFile: string): Promise<Processed> {
|
||||||
return generateFlamegraph(logFile, outFile);
|
return generateFlamegraph(profile, outFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -66,10 +68,10 @@ async function processProfile(logFile: string, outFile: string): Promise<Process
|
||||||
* @param {string} outFile File path and base name for file output. Extensions will be added for each type of file output.
|
* @param {string} outFile File path and base name for file output. Extensions will be added for each type of file output.
|
||||||
* @returns {Promise<OutputFiles>} Promise resolving to generated files.
|
* @returns {Promise<OutputFiles>} Promise resolving to generated files.
|
||||||
*/
|
*/
|
||||||
async function generateFlamegraph(logFile: string, outFile: string): Promise<Processed> {
|
async function generateFlamegraph(profile: ScenarioProfile, outFile: string): Promise<Processed> {
|
||||||
// TODO: account for --windows, --unix and --mac arguments? what is the output difference with and without these args?
|
// TODO: account for --windows, --unix and --mac arguments? what is the output difference with and without these args?
|
||||||
// TODO: use cli
|
// TODO: use cli
|
||||||
const preprocessProc = cp.spawn(process.execPath, [tickprocessor, '--preprocess', '-j', logFile]);
|
const preprocessProc = cp.spawn(process.execPath, [tickprocessor, '--preprocess', '-j', profile.logFile]);
|
||||||
const flamegraphFile = outFile + '.html'
|
const flamegraphFile = outFile + '.html'
|
||||||
const dataFile = outFile + '.data.js';
|
const dataFile = outFile + '.data.js';
|
||||||
const errorFile = outFile + '.err.txt';
|
const errorFile = outFile + '.err.txt';
|
||||||
|
@ -86,7 +88,10 @@ async function generateFlamegraph(logFile: string, outFile: string): Promise<Pro
|
||||||
// This line writes intermediate streaming output for troubleshooting:
|
// This line writes intermediate streaming output for troubleshooting:
|
||||||
// fs.writeFileSync(flamegraphfile.split('.html').join('.preprocessed.log'), preprocessed);
|
// fs.writeFileSync(flamegraphfile.split('.html').join('.preprocessed.log'), preprocessed);
|
||||||
|
|
||||||
const [flamegraph, data] = flamebearer(preprocessed);
|
let [flamegraph, data] = flamebearer(preprocessed);
|
||||||
|
|
||||||
|
flamegraph = addMetrics(flamegraph, profile.metrics);
|
||||||
|
|
||||||
fs.writeFileSync(flamegraphFile, flamegraph);
|
fs.writeFileSync(flamegraphFile, flamegraph);
|
||||||
fs.writeFileSync(dataFile, data);
|
fs.writeFileSync(dataFile, data);
|
||||||
|
|
||||||
|
|
|
@ -36,6 +36,7 @@ export async function profile(scenarios: Scenarios, config: Required<ScenarioCon
|
||||||
|
|
||||||
const browser = await puppeteer.launch({
|
const browser = await puppeteer.launch({
|
||||||
headless: true,
|
headless: true,
|
||||||
|
// TODO: use --single-process arg?
|
||||||
args: [
|
args: [
|
||||||
'--flag-switches-begin',
|
'--flag-switches-begin',
|
||||||
'--no-sandbox',
|
'--no-sandbox',
|
||||||
|
|
Загрузка…
Ссылка в новой задаче