Add a feature to save benchmark data as CSV

This commit is contained in:
Patrick Walton 2017-10-05 10:55:52 -07:00
parent b6a60ef987
commit d4c7fa74bd
3 changed files with 64 additions and 12 deletions

View File

@ -58,6 +58,8 @@
</table> </table>
</div> </div>
<div class="modal-footer"> <div class="modal-footer">
<button type="button" class="btn btn-secondary"
id="pf-benchmark-results-save-csv-button">Save CSV&hellip;</button>
<button type="button" class="btn btn-primary" <button type="button" class="btn btn-primary"
id="pf-benchmark-results-close-button">Close</button> id="pf-benchmark-results-close-button">Close</button>
</div> </div>

View File

@ -9,6 +9,7 @@
// except according to those terms. // except according to those terms.
import * as glmatrix from 'gl-matrix'; import * as glmatrix from 'gl-matrix';
import * as _ from 'lodash';
import * as opentype from "opentype.js"; import * as opentype from "opentype.js";
import {AntialiasingStrategy, AntialiasingStrategyName, NoAAStrategy} from "./aa-strategy"; import {AntialiasingStrategy, AntialiasingStrategyName, NoAAStrategy} from "./aa-strategy";
@ -22,7 +23,7 @@ import {ShaderMap, ShaderProgramSource} from "./shader-loader";
import SSAAStrategy from './ssaa-strategy'; import SSAAStrategy from './ssaa-strategy';
import {BUILTIN_FONT_URI, ExpandedMeshData, GlyphStore, PathfinderFont, TextFrame} from "./text"; import {BUILTIN_FONT_URI, ExpandedMeshData, GlyphStore, PathfinderFont, TextFrame} from "./text";
import {TextRun} from "./text"; import {TextRun} from "./text";
import {assert, PathfinderError, unwrapNull} from "./utils"; import {assert, PathfinderError, unwrapNull, unwrapUndef} from "./utils";
import {DemoView, MonochromeDemoView, Timings } from "./view"; import {DemoView, MonochromeDemoView, Timings } from "./view";
const STRING: string = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; const STRING: string = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
@ -34,17 +35,14 @@ const TEXT_COLOR: number[] = [0, 0, 0, 255];
const MIN_FONT_SIZE: number = 6; const MIN_FONT_SIZE: number = 6;
const MAX_FONT_SIZE: number = 200; const MAX_FONT_SIZE: number = 200;
const RUNS: number = 8;
const ANTIALIASING_STRATEGIES: AntialiasingStrategyTable = { const ANTIALIASING_STRATEGIES: AntialiasingStrategyTable = {
ecaa: ECAAMonochromeStrategy, ecaa: ECAAMonochromeStrategy,
none: NoAAStrategy, none: NoAAStrategy,
ssaa: SSAAStrategy, ssaa: SSAAStrategy,
}; };
interface ElapsedTime {
size: number;
time: number;
}
interface AntialiasingStrategyTable { interface AntialiasingStrategyTable {
none: typeof NoAAStrategy; none: typeof NoAAStrategy;
ssaa: typeof SSAAStrategy; ssaa: typeof SSAAStrategy;
@ -67,6 +65,7 @@ class BenchmarkAppController extends DemoAppController<BenchmarkTestView> {
private expandedMeshes: ExpandedMeshData; private expandedMeshes: ExpandedMeshData;
private pixelsPerEm: number; private pixelsPerEm: number;
private currentRun: number;
private elapsedTimes: ElapsedTime[]; private elapsedTimes: ElapsedTime[];
private partitionTime: number; private partitionTime: number;
@ -82,6 +81,10 @@ class BenchmarkAppController extends DemoAppController<BenchmarkTestView> {
unwrapNull(document.getElementById('pf-benchmark-results-partitioning-time')) as unwrapNull(document.getElementById('pf-benchmark-results-partitioning-time')) as
HTMLSpanElement; HTMLSpanElement;
const resultsSaveCSVButton =
unwrapNull(document.getElementById('pf-benchmark-results-save-csv-button'));
resultsSaveCSVButton.addEventListener('click', () => this.saveCSV(), false);
const resultsCloseButton = const resultsCloseButton =
unwrapNull(document.getElementById('pf-benchmark-results-close-button')); unwrapNull(document.getElementById('pf-benchmark-results-close-button'));
resultsCloseButton.addEventListener('click', () => { resultsCloseButton.addEventListener('click', () => {
@ -136,6 +139,7 @@ class BenchmarkAppController extends DemoAppController<BenchmarkTestView> {
private runBenchmark(): void { private runBenchmark(): void {
this.pixelsPerEm = MIN_FONT_SIZE; this.pixelsPerEm = MIN_FONT_SIZE;
this.currentRun = 0;
this.elapsedTimes = []; this.elapsedTimes = [];
this.view.then(view => this.runOneBenchmarkTest(view)); this.view.then(view => this.runOneBenchmarkTest(view));
} }
@ -146,7 +150,16 @@ class BenchmarkAppController extends DemoAppController<BenchmarkTestView> {
view.pixelsPerEm = this.pixelsPerEm; view.pixelsPerEm = this.pixelsPerEm;
}); });
renderedPromise.then(elapsedTime => { renderedPromise.then(elapsedTime => {
this.elapsedTimes.push({ size: this.pixelsPerEm, time: elapsedTime }); if (this.currentRun === 0)
this.elapsedTimes.push(new ElapsedTime(this.pixelsPerEm));
unwrapUndef(_.last(this.elapsedTimes)).times.push(elapsedTime);
this.currentRun++;
if (this.currentRun === RUNS) {
unwrapUndef(_.last(this.elapsedTimes)).times.sort((a, b) => a - b);
this.currentRun = 0;
if (this.pixelsPerEm === MAX_FONT_SIZE) { if (this.pixelsPerEm === MAX_FONT_SIZE) {
this.showResults(); this.showResults();
@ -154,6 +167,8 @@ class BenchmarkAppController extends DemoAppController<BenchmarkTestView> {
} }
this.pixelsPerEm++; this.pixelsPerEm++;
}
this.runOneBenchmarkTest(view); this.runOneBenchmarkTest(view);
}); });
} }
@ -176,6 +191,26 @@ class BenchmarkAppController extends DemoAppController<BenchmarkTestView> {
window.jQuery(this.resultsModal).modal(); window.jQuery(this.resultsModal).modal();
} }
private saveCSV(): void {
let output = "Font size,Time per glyph\n";
for (const elapsedTime of this.elapsedTimes)
output += `${elapsedTime.size},${elapsedTime.time}\n`;
// https://stackoverflow.com/a/30832210
const file = new Blob([output], {type: 'text/csv'});
const a = document.createElement('a');
const url = URL.createObjectURL(file);
a.href = url;
a.download = "pathfinder-benchmark-results.csv";
document.body.appendChild(a);
a.click();
window.setTimeout(() => {
document.body.removeChild(a);
URL.revokeObjectURL(url);
}, 0);
}
} }
class BenchmarkTestView extends MonochromeDemoView { class BenchmarkTestView extends MonochromeDemoView {
@ -311,6 +346,21 @@ class BenchmarkTestView extends MonochromeDemoView {
} }
} }
class ElapsedTime {
readonly size: number;
readonly times: number[];
constructor(size: number) {
this.size = size;
this.times = [];
}
get time(): number {
// TODO(pcwalton): Use interquartile mean instead?
return this.times[Math.floor(this.times.length / 2)];
}
}
function main() { function main() {
const controller = new BenchmarkAppController; const controller = new BenchmarkAppController;
window.addEventListener('load', () => controller.start(), false); window.addEventListener('load', () => controller.start(), false);