Skip to content

Commit

Permalink
Improves benchmark suites
Browse files Browse the repository at this point in the history
  • Loading branch information
jacomyal committed Nov 30, 2023
1 parent d101400 commit 0cd8eaa
Show file tree
Hide file tree
Showing 7 changed files with 200,066 additions and 95 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ This will generate a JSON report at `test/e2e/reports/my-report.json`.
Then, you can compare it to some reference report, by running:

```bash
npm run e2e:compare-benchmarks -- --reference reference-report.json --report my-report.json
npm run e2e:compare-benchmarks -- --reference test/e2e/reports/reference-report.json --report test/e2e/reports/my-report.json
```

## Website
Expand Down
18 changes: 16 additions & 2 deletions test/e2e/bin/benchmark.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { writeFileSync } from "fs";
import { execSync } from "child_process";
import commandLineArgs, { OptionDefinition } from "command-line-args";

import benchmarkTests from "../suites/benchmarks";
Expand All @@ -19,10 +20,23 @@ function getNowString() {
addZeros(d.getSeconds())
);
}
function getCurrentGitBranch(): string {
try {
return execSync("git rev-parse --abbrev-ref HEAD", { encoding: "utf-8" }).trim();
} catch (error) {
console.error("Erreur lors de la récupération de la branche Git :", error instanceof Error ? error.message : error);
return "N/A";
}
}

const OPTIONS: OptionDefinition[] = [
{ name: "filename", alias: "f", type: String, defaultValue: `${getNowString()}-report.json` },
{ name: "runs", alias: "r", type: Number, defaultValue: 10 },
{
name: "filename",
alias: "f",
type: String,
defaultValue: `${getNowString()}-${getCurrentGitBranch()}-report.json`,
},
{ name: "runs", alias: "r", type: Number, defaultValue: 5 },
{ name: "noHeadless", type: Boolean, defaultValue: false },
];

Expand Down
7 changes: 2 additions & 5 deletions test/e2e/bin/compare-benchmarks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,8 @@ async function exec() {
if (!report) throw new Error(`Cannot find report "${report}"`);
if (!reference) throw new Error(`Cannot find reference report "${reference}"`);

const cleanedReport = report.replace(/\.json$/, "") + ".json";
const cleanedReference = reference.replace(/\.json$/, "") + ".json";

process.env.REFERENCE_REPORT = path.join(__dirname, "../reports/", cleanedReference);
process.env.NEW_REPORT = path.join(__dirname, "../reports/", cleanedReport);
process.env.REFERENCE_REPORT = report;
process.env.NEW_REPORT = reference;

const mocha = new Mocha({
require: ["ts-node/register"],
Expand Down
134 changes: 52 additions & 82 deletions test/e2e/suites/benchmarks.ts
Original file line number Diff line number Diff line change
@@ -1,98 +1,68 @@
import { Page } from "puppeteer";

import { Tests } from "../utils";
import { Test, Tests } from "../utils";

const tests: Tests = [
{
name: "n-renders-small-scene",
scenario: async (page: Page): Promise<void> => {
await page.evaluate(() => {
const {
data: { arctic },
Sigma,
container,
rafNTimes,
} = dependencies;
const TIMES = 20;

new Sigma(arctic, container);
const METHODS = ["refresh", "render"] as const;
type Method = (typeof METHODS)[number];

return rafNTimes(() => {
// This simulates a layout iteration, that triggers a full reindex of the graph:
arctic.forEachNode((node) => arctic.mergeNodeAttributes(node, { x: Math.random(), y: Math.random() }));
}, 20);
});
},
},
{
name: "n-refreshes-small-scene",
scenario: async (page: Page): Promise<void> => {
await page.evaluate(() => {
const {
data: { arctic },
Sigma,
container,
rafNTimes,
} = dependencies;
const SIZES = ["small", "medium", "large"] as const;
type Size = (typeof SIZES)[number];

const sigma = new Sigma(arctic, container);
const camera = sigma.getCamera();

return rafNTimes(() => {
// This simulates a user interaction, that triggers a render of the graph:
camera.setState({ angle: camera.angle + 0.1 });
}, 20);
});
},
},
{
name: "n-renders-large-scene",
scenario: async (page: Page): Promise<void> => {
await page.evaluate(() => {
const {
data: { arctic },
Sigma,
container,
rafNTimes,
} = dependencies;
const SCREEN_SIZES: Record<Size, number> = {
small: 600,
medium: 1600,
large: 2600,
};
const GRAPHS: Record<Size, string> = {
small: "lesMiserables",
medium: "arctic",
large: "largeGraph",
};

new Sigma(arctic, container);
function getTest(method: Method, screenSize: Size, graphSize: Size): Test {
const graphKey = GRAPHS[graphSize];
const screenKey = SCREEN_SIZES[screenSize];

return rafNTimes(() => {
// This simulates a layout iteration, that triggers a full reindex of the graph:
arctic.forEachNode((node) => arctic.mergeNodeAttributes(node, { x: Math.random(), y: Math.random() }));
}, 20);
});
},
dimensions: {
width: 2600,
height: 2600,
},
},
{
name: "n-refreshes-large-scene",
return {
name: `${method}-${screenSize}-scene-${graphSize}-graph`,
scenario: async (page: Page): Promise<void> => {
await page.evaluate(() => {
const {
data: { arctic },
Sigma,
container,
rafNTimes,
} = dependencies;
await page.evaluate(
(method: string, graphKey: string, times: number) => {
const { data, Sigma, container, rafNTimes } = dependencies;

const sigma = new Sigma(arctic, container);
const camera = sigma.getCamera();
const graph = data[graphKey];
const sigma = new Sigma(graph, container);
const camera = sigma.getCamera();

return rafNTimes(() => {
// This simulates a user interaction, that triggers a render of the graph:
camera.setState({ angle: camera.angle + 0.1 });
}, 20);
});
switch (method) {
case "refresh":
return rafNTimes(() => {
// This simulates a layout iteration, that triggers a full reindex of the graph:
graph.forEachNode((node) => graph.mergeNodeAttributes(node, { x: Math.random(), y: Math.random() }));
}, times);
case "render":
return rafNTimes(() => {
// This simulates a user interaction, that triggers a render of the graph:
camera.setState({ angle: camera.angle + 0.1 });
}, times);
}
},
method,
graphKey,
TIMES,
);
},
dimensions: {
width: 2600,
height: 2600,
width: screenKey,
height: screenKey,
},
},
];
};
}

const tests: Tests = METHODS.flatMap((method) =>
SIZES.flatMap((screenSize) => SIZES.map((graphSize) => getTest(method, screenSize, graphSize))),
);

export default tests;
9 changes: 5 additions & 4 deletions test/e2e/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import fs from "fs";
import { PNG } from "pngjs";
import pixelmatch from "pixelmatch";
import Graph from "graphology";
import { GraphConstructor } from "graphology-types";

import Sigma from "../../src/sigma";

Expand All @@ -18,16 +17,18 @@ declare global {
const dependencies: TestDependencies;
}

export type Tests = Array<{
export type Test = {
name: string; // Name of the screenshot, without the extension like for example 'example-basic'
waitFor?: number; // Time to wait in ms before to take the screenshot
scenario: (page: Page) => Promise<void>;
failureThreshold?: number; // between 0 and 1, it's a percent. By default, it's a small epsilon.
dimensions?: { width: number; height: number };
}>;
};

export type Tests = Test[];

export type TestDependencies = {
Graph: GraphConstructor;
Graph: typeof Graph;
Sigma: typeof Sigma;
data: { [key: string]: Graph };
// eslint-disable-next-line @typescript-eslint/no-explicit-any
Expand Down
4 changes: 3 additions & 1 deletion test/e2e/web/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import EdgeTriangleProgram from "../../../src/rendering/webgl/programs/edge.tria
// Useful data
import ARCTIC from "./resources/arctic.json";
import LES_MISERABLES from "./resources/les-miserables.json";
import LARGE_GRAPH from "./resources/large-graph.json";

// Utils:
const rafNTimes = (fn: (step: number) => void, n: number) => {
Expand All @@ -39,6 +40,7 @@ const rafNTimes = (fn: (step: number) => void, n: number) => {
// Data:
const arctic = Graph.from(ARCTIC as SerializedGraph);
const lesMiserables = Graph.from(LES_MISERABLES as SerializedGraph);
const largeGraph = Graph.from(LARGE_GRAPH as SerializedGraph);

const container = document.getElementById("container") as HTMLElement;

Expand All @@ -54,7 +56,7 @@ globalize({
dependencies: {
Graph,
Sigma,
data: { arctic, lesMiserables },
data: { arctic, lesMiserables, largeGraph },
programs: {
NodeCircleProgram,
NodePointProgram,
Expand Down
Loading

0 comments on commit 0cd8eaa

Please sign in to comment.