Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions contributor_docs/performance_testing.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<!-- Guide to writing performance tests for p5.js source code. -->

# Performance Testing

Performance testing is an essential part of measuring how fasst isolated code paths take to execute under a known range of conditions.

Implementation notes:

- All pre-existing benchmarks included the full p5 instance setup which adds ~50ms to each test. The typography performance tests show how to isolate performance testing away from setup overhead.
- The `textToPoints() single word, with render` test draws the calculated points, others just run `textToPoints()`.

## Typography Tests

To isolate typography tests, run the following:

```shell
npx vitest bench test/bench/typography.bench.js --reporter=verbose
```
125 changes: 125 additions & 0 deletions test/bench/typography.bench.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
import { bench, describe } from "vitest";
import p5 from "../../src/app";
import { WEBGL, WEBGPU } from "../../src/core/constants";

const fontFile = "../../test/manual-test-examples/type/font/LiberationSans-Bold.ttf";

const strs = {
single: "Performance",
ten: "Performance testing 10 words at a time is exhaustive! Right?",
paragraph: Array.from({ length: 10 }, (_, i) =>
`${i === 0 ? "\t": ""}Performance is vital in all aspects of text rendering, even 10 lines at a time. This is line ${i + 1} of 10.`
).join("\n") // This will hit around 15fps, 21275 points
};

// Parameterizing test cases by function ensures consitency in test parameters across all renderers.
// Future tests should follow a similar format (e.g. TO_CONTOURS_CASES, etc)
const TO_POINTS_CASES = [
{label: "textToPoints() single word", str: strs.single, textSize: 20, sampleFactor: 0.5, points: 317, variance: 5, render: false},
{label: "textToPoints() single word, 150pt", str: strs.single, textSize: 150, sampleFactor: 0.5, points: 2336, variance: 50, render: false},
{label: "textToPoints() single word, with render", str: strs.single, textSize: 20, sampleFactor: 0.5, points: 317, variance: 5, render: true},
{label: "textToPoints() 10 words", str: strs.ten, textSize: 20, sampleFactor: 0.5, points: 1453, variance: 5, render: false},
{label: "textToPoints() paragraph", str: strs.paragraph, textSize: 20, sampleFactor: 0.5, points: 21275, variance: 50, render: false},
];

async function bootstrap(w = 400, h = 400, renderer = undefined) {
var myp5;
var font;
new p5(function (p) {
p.setup = async function () {
myp5 = p;
font = await p.loadFont(fontFile);
p.createCanvas(w, h, renderer);
};
});
await vi.waitFor(() => {
if (myp5 === undefined) throw new Error("not ready");
});
return { myp5, font };
}

function drawPoints(myp5, points) {
for (let point of points) {
myp5.point(point.x, point.y);
}
}

const options = { iterations: 20, time: 500 };
Comment thread
shakeelmohamed marked this conversation as resolved.

describe("Typography: bench 2D", function() {
var myp5, font;

for (let testCase of TO_POINTS_CASES) {
bench(
testCase.label,
async () => {
const points = font.textToPoints(testCase.str, 10, 20, { sampleFactor: testCase.sampleFactor });
assert.closeTo(points.length, testCase.points, testCase.variance);
if (testCase.render) {
drawPoints(myp5, points);
}
},
{
...options,
setup: async () => {
({myp5, font} = await bootstrap());
myp5.textSize(testCase.textSize);
},
teardown: () => myp5.remove()
}
);
}

});

describe("Typography: bench WebGL", function() {
var myp5, font;

for (let testCase of TO_POINTS_CASES) {
bench(
testCase.label,
async () => {
const points = font.textToPoints(testCase.str, 10, 20, { sampleFactor: testCase.sampleFactor });
assert.closeTo(points.length, testCase.points, testCase.variance);
if (testCase.render) {
drawPoints(myp5, points);
}
},
{
...options,
setup: async () => {
({myp5, font} = await bootstrap(400, 400, WEBGL));
myp5.textSize(testCase.textSize);
},
teardown: () => myp5.remove()
}
);
}

});

describe("Typography: bench WebGPU", function() {
var myp5, font;

for (let testCase of TO_POINTS_CASES) {
bench(
testCase.label,
async () => {
const points = font.textToPoints(testCase.str, 10, 20, { sampleFactor: testCase.sampleFactor });
assert.closeTo(points.length, testCase.points, testCase.variance);
if (testCase.render) {
drawPoints(myp5, points);
}
},
{
...options,
setup: async () => {
({myp5, font} = await bootstrap(400, 400, WEBGPU));
myp5.textSize(testCase.textSize);
},
teardown: () => myp5.remove()
}
);
}

});