Skip to content

Commit

Permalink
feat: result types
Browse files Browse the repository at this point in the history
  • Loading branch information
Diego Ferreiro Val committed Jun 18, 2019
1 parent edb9d25 commit f4f385b
Show file tree
Hide file tree
Showing 15 changed files with 223 additions and 169 deletions.
6 changes: 6 additions & 0 deletions packages/@best/runtime/src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,9 @@ export const HOOKS = {
AFTER,
};
export const RUN_BENCHMARK = 'run_benchmark';

export const PRIMITIVE_NODE_TYPES: { [key:string]: NodeTypes } = {
GROUP: "group",
BENCHMARK: "benchmark",
RUN: "run"
};
9 changes: 3 additions & 6 deletions packages/@best/runtime/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,11 @@ export * from './primitives';

declare var window: any;

const setupBenchmark = (config: any) => initializeBenchmarkConfig(config);
const runBenchmark = async (config?: any) => {
const setupBenchmark = (config: BenchmarkConfig) => initializeBenchmarkConfig(config);
const runBenchmark = async (config?: BenchmarkConfig) => {
if (config) {
setupBenchmark(config);
}

const benchmarkState = getBenckmarkState();
const benchmarkResults = await _runBenchmark(benchmarkState);
return benchmarkResults;
Expand All @@ -18,11 +17,9 @@ const runBenchmark = async (config?: any) => {
// Expose BEST API
const BEST = { setupBenchmark, runBenchmark };
window.BEST = BEST;

// TODO: Double check in engine
// This will probably have to go in globals or something like that
window.process = { env: { NODE_ENV: 'development' } };

// Auto-load
window.addEventListener('load', async () => {
const config = setupBenchmark(window.BEST_CONFIG);
if (config.autoStart) {
Expand Down
38 changes: 22 additions & 16 deletions packages/@best/runtime/src/primitives-handler.ts
Original file line number Diff line number Diff line change
@@ -1,33 +1,33 @@
import { makeDescribe, makeBenchmark, makeBenchmarkRun } from './utils/primitives-nodes';

const handler = (event: any, state: any) => {
switch (event.name) {
const handler = (event: PrimitiveNode, state: BenchmarkState) => {
switch (event.nodeType) {
case 'start_describe_definition': {
const { blockName, mode } = event;
const { currentDescribeBlock } = state;
const describeBlock = makeDescribe(blockName, currentDescribeBlock, mode);
const { nodeName, mode } = event;
const currentDescribeBlock = state.currentDescribeBlock as RuntimeNodeDescribe;
const describeBlock = makeDescribe(nodeName, currentDescribeBlock, mode);
currentDescribeBlock.children.push(describeBlock);
state.currentDescribeBlock = describeBlock;
break;
}

case 'start_benchmark_definition': {
const { blockName, mode } = event;
const { currentDescribeBlock } = state;
const describeBlock = makeBenchmark(blockName, currentDescribeBlock, mode);
currentDescribeBlock.children.push(describeBlock);
state.currentDescribeBlock = describeBlock;
const { nodeName, mode } = event;
const currentDescribeBlock = state.currentDescribeBlock as RuntimeNodeDescribe;
const benchmarkBlock = makeBenchmark(nodeName, currentDescribeBlock, mode);
currentDescribeBlock.children.push(benchmarkBlock);
state.currentDescribeBlock = benchmarkBlock;
break;
}

case 'finish_describe_definition':
case 'finish_benchmark_definition': {
const { currentDescribeBlock } = state;
const currentDescribeBlock = state.currentDescribeBlock as RuntimeNodeDescribe | RuntimeNodeBenchmark;
if (!currentDescribeBlock) {
throw new Error(`"currentDescribeBlock" has to be there since we're finishing its definition.`);
}

if (currentDescribeBlock.children.length === 0 && !currentDescribeBlock.run) {
if (currentDescribeBlock.type === "benchmark" && !currentDescribeBlock.run) {
throw new Error(
`Benchmark "${
currentDescribeBlock.name
Expand All @@ -38,21 +38,27 @@ const handler = (event: any, state: any) => {
if (currentDescribeBlock.parent) {
state.currentDescribeBlock = currentDescribeBlock.parent;
}

break;
}

case 'add_hook': {
const { currentDescribeBlock } = state;
const { fn, hookType: type } = event;
currentDescribeBlock.hooks.push({ fn, type });

if (fn && type) {
currentDescribeBlock.hooks.push({ fn, type });
}
break;
}

case 'run_benchmark': {
const { currentDescribeBlock } = state;
const currentDescribeBlock = state.currentDescribeBlock as RuntimeNodeBenchmark;
const { fn } = event;
const benchmark = makeBenchmarkRun(fn, currentDescribeBlock);
currentDescribeBlock.run = benchmark;
if (fn) {
const benchmark = makeBenchmarkRun(fn, currentDescribeBlock);
currentDescribeBlock.run = benchmark;
}
break;
}

Expand Down
16 changes: 8 additions & 8 deletions packages/@best/runtime/src/primitives.ts
Original file line number Diff line number Diff line change
@@ -1,33 +1,33 @@
import { dispatch } from './state';
import { HOOKS, RUN_BENCHMARK, MODES } from './constants';

const _dispatchDescribe = (blockName: string, blockFn: Function, mode?: string) => {
dispatch({ blockName, mode, name: 'start_describe_definition' });
const _dispatchDescribe = (nodeName: string, blockFn: Function, mode?: string) => {
dispatch({ nodeName, mode, nodeType: 'start_describe_definition' });
blockFn();
dispatch({ name: 'finish_describe_definition' });
dispatch({ nodeName, nodeType: 'finish_describe_definition' });
};

const describe = (blockName: string, blockFn: Function) => _dispatchDescribe(blockName, blockFn);
describe.only = (blockName: string, blockFn: Function) => _dispatchDescribe(blockName, blockFn, MODES.ONLY);
describe.skip = (blockName: string, blockFn: Function) => _dispatchDescribe(blockName, blockFn, MODES.SKIP);

const _dispatchBenchmark = (blockName: any, blockFn: Function, mode?: string) => {
dispatch({ blockName, mode, name: 'start_benchmark_definition' });
const _dispatchBenchmark = (nodeName: any, blockFn: Function, mode?: string) => {
dispatch({ nodeName, mode, nodeType: 'start_benchmark_definition' });
blockFn();
dispatch({ name: 'finish_benchmark_definition' });
dispatch({ nodeName, nodeType: 'finish_benchmark_definition' });
};

const benchmark = (benchmarkName: string, fn: Function) => _dispatchBenchmark(benchmarkName, fn);
benchmark.only = (benchmarkName: string, fn: Function) => _dispatchBenchmark(benchmarkName, fn, MODES.ONLY);
benchmark.skip = (benchmarkName: string, fn: Function) => _dispatchBenchmark(benchmarkName, fn, MODES.SKIP);

const _addHook = (fn: Function, hookType: string) => dispatch({ fn, hookType, name: 'add_hook' });
const _addHook = (fn: Function, hookType: string) => dispatch({ nodeName: 'hook', fn, hookType, nodeType: 'add_hook' });
const beforeAll = (fn: Function) => _addHook(fn, HOOKS.BEFORE_ALL);
const beforeEach = (fn: Function) => _addHook(fn, HOOKS.BEFORE_EACH);
const before = (fn: Function) => _addHook(fn, HOOKS.BEFORE);
const afterAll = (fn: Function) => _addHook(fn, HOOKS.AFTER_ALL);
const afterEach = (fn: Function) => _addHook(fn, HOOKS.AFTER_EACH);
const after = (fn: Function) => _addHook(fn, HOOKS.AFTER);
const run = (fn: Function) => dispatch({ fn, name: RUN_BENCHMARK });
const run = (fn: Function) => dispatch({ nodeName: 'run', fn, nodeType: RUN_BENCHMARK });

export { describe, benchmark, beforeAll, beforeEach, before, afterAll, afterEach, after, run };
8 changes: 5 additions & 3 deletions packages/@best/runtime/src/results.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
export function normalizeResults(benchmarkState: any) {
const { benchmarkName, executedIterations, executedTime, results } = benchmarkState;
import { BenchmarkResults } from "@best/types";

export function normalizeResults(benchmarkState: BenchmarkState): BenchmarkResults {
const { benchmarkName, executedIterations, executedTime: aggregate, results } = benchmarkState;

return {
benchmarkName,
executedIterations,
executedTime,
aggregate,
results,
};
}
42 changes: 22 additions & 20 deletions packages/@best/runtime/src/run_iteration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ const _initHandlers = () =>
return o;
}, {});

const _initHooks = (hooks: Function[]) =>
const _initHooks = (hooks: RuntimeHook[]) =>
hooks.reduce((m, { type, fn }: any) => {
m[type].push(fn);
return m;
Expand All @@ -27,7 +27,7 @@ function endMeasure(markName: string) {
performance.clearMeasures(markName);
}

const executeBenchmark = async (benchmarkNode: any, markName: string, { useMacroTaskAfterBenchmark }: any) => {
const executeBenchmark = async (benchmarkNode: RuntimeNodeRunner, markName: string, { useMacroTaskAfterBenchmark }: { useMacroTaskAfterBenchmark: boolean } ) => {
// Force garbage collection before executing an iteration (--js-flags=--expose-gc)
_forceGC();
return new Promise((resolve, reject) => {
Expand All @@ -40,26 +40,26 @@ const executeBenchmark = async (benchmarkNode: any, markName: string, { useMacro

try {
await benchmarkNode.fn();
benchmarkNode.metrics.runDuration = formatTime(time() - benchmarkNode.startedAt);
benchmarkNode.metrics.script = formatTime(time() - benchmarkNode.startedAt);

if (useMacroTaskAfterBenchmark) {
withMacroTask(async () => {
await nextTick();
benchmarkNode.duration = formatTime(time() - benchmarkNode.startedAt);
benchmarkNode.aggregate = formatTime(time() - benchmarkNode.startedAt);
if (process.env.NODE_ENV !== 'production') {
endMeasure(markName);
}
resolve();
})();
} else {
benchmarkNode.duration = formatTime(time() - benchmarkNode.startedAt);
benchmarkNode.aggregate = formatTime(time() - benchmarkNode.startedAt);
if (process.env.NODE_ENV !== 'production') {
endMeasure(markName);
}
resolve();
}
} catch (e) {
benchmarkNode.duration = -1;
benchmarkNode.aggregate = -1;
if (process.env.NODE_ENV !== 'production') {
endMeasure(markName);
}
Expand All @@ -69,7 +69,7 @@ const executeBenchmark = async (benchmarkNode: any, markName: string, { useMacro
});
};

export const runBenchmarkIteration = async (node: any, opts: any) => {
export const runBenchmarkIteration = async (node: RuntimeNode, opts: { useMacroTaskAfterBenchmark: boolean }): Promise<RuntimeNode> => {
const { hooks, children, run } = node;
const hookHandlers = _initHooks(hooks);

Expand All @@ -79,20 +79,22 @@ export const runBenchmarkIteration = async (node: any, opts: any) => {
}

// -- For each children ----
for (const child of children) {
// -- Before Each ----
for (const hook of hookHandlers[HOOKS.BEFORE_EACH]) {
await hook();
}
if (children) {
for (const child of children) {
// -- Before Each ----
for (const hook of hookHandlers[HOOKS.BEFORE_EACH]) {
await hook();
}

// -- Traverse Child ----
node.startedAt = formatTime(time());
await runBenchmarkIteration(child, opts);
node.duration = formatTime(time() - node.startedAt);
// -- Traverse Child ----
node.startedAt = formatTime(time());
await runBenchmarkIteration(child, opts);
node.aggregate = formatTime(time() - node.startedAt);

// -- After Each Child ----
for (const hook of hookHandlers[HOOKS.AFTER_EACH]) {
await hook();
// -- After Each Child ----
for (const hook of hookHandlers[HOOKS.AFTER_EACH]) {
await hook();
}
}
}

Expand All @@ -112,7 +114,7 @@ export const runBenchmarkIteration = async (node: any, opts: any) => {
// -- Run ----
node.startedAt = formatTime(time());
await executeBenchmark(run, markName, opts);
node.duration = formatTime(time() - node.startedAt);
node.aggregate = formatTime(time() - node.startedAt);

// -- After ----
if (process.env.NODE_ENV !== 'production') {
Expand Down
29 changes: 15 additions & 14 deletions packages/@best/runtime/src/runner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,30 +2,31 @@ import { getBenchmarkRootNode } from './state';
import { runBenchmarkIteration } from './run_iteration';
import { normalizeResults } from './results';
import { validateState } from "./utils/validate";
import { BenchmarkResultNode, ResultNodeTypes, BenchmarkResults } from "@best/types";

function collectResults(node: any) {
const { name, duration, startedAt, run } = node;
const resultNode: any = { name, duration, startedAt };
function collectNodeResults(node: RuntimeNode): BenchmarkResultNode {
const { name, aggregate, startedAt, run, children } = node;
const type = node.type as ResultNodeTypes;
const resultNode: BenchmarkResultNode = { type, name, aggregate, startedAt };

if (run) {
resultNode.duration = run.duration;
resultNode.runDuration = run.runDuration;
} else {
resultNode.benchmarks = node.children.map((c: any) => collectResults(c));
resultNode.aggregate = run.aggregate;
resultNode.metrics = { script: run.metrics.script };
} else if (children) {
resultNode.nodes = children.map((c: RuntimeNode) => collectNodeResults(c));
}

return resultNode;
}

async function runIterations(config: any): Promise<any> {
async function runIterations(config: BenchmarkState): Promise<BenchmarkState> {
if (config.executedTime < config.maxDuration || config.executedIterations < config.minSampleCount) {
const { useMacroTaskAfterBenchmark } = config;
const benchmark = await runBenchmarkIteration(getBenchmarkRootNode(), {
useMacroTaskAfterBenchmark,
});
const results = collectResults(benchmark);

const benchmark = await runBenchmarkIteration(getBenchmarkRootNode(), { useMacroTaskAfterBenchmark });
const results = collectNodeResults(benchmark);
config.results.push(results);
config.executedTime += benchmark.duration;
config.executedTime += benchmark.aggregate;
config.executedIterations += 1;

if (!config.iterateOnClient) {
Expand All @@ -38,7 +39,7 @@ async function runIterations(config: any): Promise<any> {
return config;
}

export async function runBenchmark(benchmarkState: any) {
export async function runBenchmark(benchmarkState: BenchmarkState): Promise<BenchmarkResults> {
validateState(benchmarkState);
if (benchmarkState.benchmarkDefinitionError) {
throw benchmarkState.benchmarkDefinitionError;
Expand Down
36 changes: 9 additions & 27 deletions packages/@best/runtime/src/state.ts
Original file line number Diff line number Diff line change
@@ -1,40 +1,22 @@
import primitivesHandler from './primitives-handler';
import { makeDescribe } from './utils/primitives-nodes';
import DEFAULT_STATE from './utils/default-state';
import cloneState from "./utils/clone-state";

declare var BEST_CONFIG: any

const eventHandlers = [
primitivesHandler,
// formatNodeAssertErrors,
];

function _benchmarkTitle() {
return typeof BEST_CONFIG !== 'undefined' ? BEST_CONFIG.benchmarkName : 'ROOT_DESCRIBE_BLOCK';
}
const ROOT_DESCRIBE_BLOCK_NAME = _benchmarkTitle();
declare var BEST_CONFIG: any;
const eventHandlers = [ primitivesHandler];
const ROOT_DESCRIBE_BLOCK_NAME = typeof BEST_CONFIG !== 'undefined' ? BEST_CONFIG.benchmarkName : 'ROOT_DESCRIBE_BLOCK';
const ROOT_DESCRIBE_BLOCK = makeDescribe(ROOT_DESCRIBE_BLOCK_NAME);

const STATE: any = Object.assign({}, DEFAULT_STATE, {
const STATE: BenchmarkState = Object.assign({}, DEFAULT_STATE, {
currentDescribeBlock: ROOT_DESCRIBE_BLOCK,
rootDescribeBlock: ROOT_DESCRIBE_BLOCK,
});

const _getInternalState = () => STATE;
const _cloneState = (state: any) => {
const stateClone = Object.assign({}, state);

if (stateClone.children) {
stateClone.children = stateClone.children.map((c: any) => _cloneState(c));
}

return stateClone;
};

export const getBenckmarkState = () => _cloneState(STATE);
export const getBenckmarkState = () => cloneState(STATE);
export const getBenchmarkRootNode = () => getBenckmarkState().rootDescribeBlock;

export const initializeBenchmarkConfig = (newOpts: any) => {
export const initializeBenchmarkConfig = (newOpts: BenchmarkConfig): BenchmarkConfig => {
if (newOpts.iterations !== undefined) {
if (newOpts.iterateOnClient === undefined) {
newOpts.iterateOnClient = true;
Expand All @@ -47,10 +29,10 @@ export const initializeBenchmarkConfig = (newOpts: any) => {
};

// PROTECTED: Should only be used by the primitives
export function dispatch(event: any) {
export function dispatch(event: PrimitiveNode) {
try {
for (const handler of eventHandlers) {
handler(event, _getInternalState());
handler(event, STATE);
}
} catch (err) {
STATE.benchmarkDefinitionError = err;
Expand Down
Loading

0 comments on commit f4f385b

Please sign in to comment.