{
- return [
+ this.tileIDs = tileIDs || [
new OverscaledTileID(12, 0, 12, 655, 1583),
new OverscaledTileID(8, 0, 8, 40, 98),
new OverscaledTileID(4, 0, 4, 3, 6),
@@ -34,7 +30,7 @@ export default class Layout extends Benchmark {
return this.parser.setup();
})
.then(() => {
- return Promise.all(this.locations.map(tileID => this.parser.fetchTile(tileID)));
+ return Promise.all(this.tileIDs.map(tileID => this.parser.fetchTile(tileID)));
})
.then((tiles) => {
this.tiles = tiles;
diff --git a/bench/benchmarks/remove_paint_state.js b/bench/benchmarks/remove_paint_state.js
index a67f9b32f6a..191bf243f6c 100644
--- a/bench/benchmarks/remove_paint_state.js
+++ b/bench/benchmarks/remove_paint_state.js
@@ -68,7 +68,7 @@ class RemovePaintState extends Benchmark {
}
}
-class PropertyLevelRemove extends RemovePaintState {
+export class PropertyLevelRemove extends RemovePaintState {
bench() {
for (let i = 0; i < this.numFeatures; i += 50) {
@@ -82,7 +82,7 @@ class PropertyLevelRemove extends RemovePaintState {
}
}
-class FeatureLevelRemove extends RemovePaintState {
+export class FeatureLevelRemove extends RemovePaintState {
bench() {
for (let i = 0; i < this.numFeatures; i += 50) {
@@ -96,7 +96,7 @@ class FeatureLevelRemove extends RemovePaintState {
}
}
-class SourceLevelRemove extends RemovePaintState {
+export class SourceLevelRemove extends RemovePaintState {
bench() {
for (let i = 0; i < this.numFeatures; i += 50) {
@@ -109,9 +109,3 @@ class SourceLevelRemove extends RemovePaintState {
}
}
-
-export default [
- PropertyLevelRemove,
- FeatureLevelRemove,
- SourceLevelRemove
-];
diff --git a/bench/benchmarks/worker_transfer.js b/bench/benchmarks/worker_transfer.js
index 2feb7b9c2a8..e1245ca6808 100644
--- a/bench/benchmarks/worker_transfer.js
+++ b/bench/benchmarks/worker_transfer.js
@@ -84,5 +84,5 @@ export default class WorkerTransfer extends Benchmark {
function barePayload(obj) {
// strip all transferables from a worker payload, because we can't transfer them repeatedly in the bench:
// as soon as it's transfered once, it's no longer available on the main thread
- return JSON.parse(JSON.stringify(obj, (key, value) => ArrayBuffer.isView(value) ? {} : value));
+ return JSON.parse(JSON.stringify(obj, (key, value) => ArrayBuffer.isView(value) ? {} : value) || '{}');
}
diff --git a/bench/benchmarks_view.js b/bench/benchmarks_view.js
index f3cc6cc62d6..b6ce6a080c8 100644
--- a/bench/benchmarks_view.js
+++ b/bench/benchmarks_view.js
@@ -1,12 +1,89 @@
import React from 'react';
import ReactDOM from 'react-dom';
import * as d3 from 'd3';
-import Axis from './lib/axis';
-import { kde, probabilitiesOfSuperiority } from './lib/statistics';
+import { kde, probabilitiesOfSuperiority, summaryStatistics, regression } from './lib/statistics';
const versionColor = d3.scaleOrdinal(['#1b9e77', '#7570b3', '#d95f02']);
const formatSample = d3.format(".3r");
+function identity(x) {
+ return x;
+}
+function translateX(x) {
+ return `translate(${x + 0.5},0)`;
+}
+function translateY(y) {
+ return `translate(0,${y + 0.5})`;
+}
+function number(scale) {
+ return function(d) {
+ return +scale(d);
+ };
+}
+function center(scale) {
+ let offset = Math.max(0, scale.bandwidth() - 1) / 2; // Adjust for 0.5px offset.
+ if (scale.round()) offset = Math.round(offset);
+ return function(d) {
+ return +scale(d) + offset;
+ };
+}
+
+class Axis extends React.Component {
+ render() {
+ const scale = this.props.scale;
+ const orient = this.props.orientation || 'left';
+ const tickArguments = this.props.ticks ? [].concat(this.props.ticks) : [];
+ const tickValues = this.props.tickValues || null;
+ const tickFormat = this.props.tickFormat || null;
+ const tickSizeInner = this.props.tickSize || this.props.tickSizeInner || 6;
+ const tickSizeOuter = this.props.tickSize || this.props.tickSizeOuter || 6;
+ const tickPadding = this.props.tickPadding || 3;
+
+ const k = orient === 'top' || orient === 'left' ? -1 : 1;
+ const x = orient === 'left' || orient === 'right' ? 'x' : 'y';
+ const transform = orient === 'top' || orient === 'bottom' ? translateX : translateY;
+
+ const values = tickValues == null ? (scale.ticks ? scale.ticks(...tickArguments) : scale.domain()) : tickValues;
+ const format = tickFormat == null ? (scale.tickFormat ? scale.tickFormat(...tickArguments) : identity) : tickFormat;
+ const spacing = Math.max(tickSizeInner, 0) + tickPadding;
+ const range = scale.range();
+ const range0 = +range[0] + 0.5;
+ const range1 = +range[range.length - 1] + 0.5;
+ const position = (scale.bandwidth ? center : number)(scale.copy());
+
+ return (
+
+
+ {values.map((d, i) =>
+
+
+ {format(d)}
+
+ )}
+ {this.props.children}
+
+ );
+ }
+}
+
class StatisticsPlot extends React.Component {
constructor(props) {
super(props);
@@ -377,19 +454,12 @@ class BenchmarkRow extends React.Component {
}
class BenchmarksTable extends React.Component {
- constructor(props) {
- super(props);
- this.state = {sharing: false};
- this.share = this.share.bind(this);
- }
-
render() {
return (
- {this.state.sharing && }
Mapbox GL JS Benchmarks – {
this.props.finished ?
- Finished :
+ Finished :
Running}
{this.props.benchmarks.map((benchmark, i) => {
return ;
@@ -397,29 +467,9 @@ class BenchmarksTable extends React.Component {
);
}
-
- share() {
- document.querySelectorAll('script').forEach(e => e.remove());
- const share = document.querySelector('.share');
- share.style.display = 'none';
-
- const body = JSON.stringify({
- "public": true,
- "files": {
- "index.html": {
- "content": document.body.parentElement.outerHTML
- }
- }
- });
- this.setState({sharing: true});
-
- fetch('https://api.github.com/gists', { method: 'POST', body })
- .then(response => response.json())
- .then(json => { window.location = `https://bl.ocks.org/anonymous/raw/${json.id}/`; });
- }
}
-export default function updateUI(benchmarks, finished) {
+function updateUI(benchmarks, finished) {
finished = !!finished;
ReactDOM.render(
@@ -427,3 +477,51 @@ export default function updateUI(benchmarks, finished) {
document.getElementById('benchmarks')
);
}
+
+export function run(benchmarks) {
+ const filter = window.location.hash.substr(1);
+ if (filter) benchmarks = benchmarks.filter(({name}) => name === filter);
+
+ for (const benchmark of benchmarks) {
+ for (const version of benchmark.versions) {
+ version.status = 'waiting';
+ version.logs = [];
+ version.samples = [];
+ version.summary = {};
+ }
+ }
+
+ updateUI(benchmarks);
+
+ let promise = Promise.resolve();
+
+ benchmarks.forEach(bench => {
+ bench.versions.forEach(version => {
+ promise = promise.then(() => {
+ version.status = 'running';
+ updateUI(benchmarks);
+
+ return version.bench.run()
+ .then(measurements => {
+ // scale measurements down by iteration count, so that
+ // they represent (average) time for a single iteration
+ const samples = measurements.map(({time, iterations}) => time / iterations);
+ version.status = 'ended';
+ version.samples = samples;
+ version.summary = summaryStatistics(samples);
+ version.regression = regression(measurements);
+ updateUI(benchmarks);
+ })
+ .catch(error => {
+ version.status = 'errored';
+ version.error = error;
+ updateUI(benchmarks);
+ });
+ });
+ });
+ });
+
+ promise = promise.then(() => {
+ updateUI(benchmarks, true);
+ });
+}
diff --git a/bench/lib/axis.js b/bench/lib/axis.js
deleted file mode 100644
index a1872a5bac1..00000000000
--- a/bench/lib/axis.js
+++ /dev/null
@@ -1,85 +0,0 @@
-import React from 'react';
-
-function identity(x) {
- return x;
-}
-
-function translateX(x) {
- return `translate(${x + 0.5},0)`;
-}
-
-function translateY(y) {
- return `translate(0,${y + 0.5})`;
-}
-
-function number(scale) {
- return function(d) {
- return +scale(d);
- };
-}
-
-function center(scale) {
- let offset = Math.max(0, scale.bandwidth() - 1) / 2; // Adjust for 0.5px offset.
- if (scale.round()) offset = Math.round(offset);
- return function(d) {
- return +scale(d) + offset;
- };
-}
-
-class Axis extends React.Component {
- render() {
- const scale = this.props.scale;
- const orient = this.props.orientation || 'left';
- const tickArguments = this.props.ticks ? [].concat(this.props.ticks) : [];
- const tickValues = this.props.tickValues || null;
- const tickFormat = this.props.tickFormat || null;
- const tickSizeInner = this.props.tickSize || this.props.tickSizeInner || 6;
- const tickSizeOuter = this.props.tickSize || this.props.tickSizeOuter || 6;
- const tickPadding = this.props.tickPadding || 3;
-
- const k = orient === 'top' || orient === 'left' ? -1 : 1;
- const x = orient === 'left' || orient === 'right' ? 'x' : 'y';
- const transform = orient === 'top' || orient === 'bottom' ? translateX : translateY;
-
- const values = tickValues == null ? (scale.ticks ? scale.ticks(...tickArguments) : scale.domain()) : tickValues;
- const format = tickFormat == null ? (scale.tickFormat ? scale.tickFormat(...tickArguments) : identity) : tickFormat;
- const spacing = Math.max(tickSizeInner, 0) + tickPadding;
- const range = scale.range();
- const range0 = +range[0] + 0.5;
- const range1 = +range[range.length - 1] + 0.5;
- const position = (scale.bandwidth ? center : number)(scale.copy());
-
- return (
-
-
- {values.map((d, i) =>
-
-
- {format(d)}
-
- )}
- {this.props.children}
-
- );
- }
-}
-
-export default Axis;
diff --git a/bench/lib/style_locations.js b/bench/lib/style_locations.js
index 2366bc565ce..77b2515314e 100644
--- a/bench/lib/style_locations.js
+++ b/bench/lib/style_locations.js
@@ -1,94 +1,23 @@
+import styleBenchmarkLocations from '@mapbox/gazetteer/mapbox-streets/style-benchmark-locations.json';
+import MercatorCoordinate from '../../src/geo/mercator_coordinate';
import { OverscaledTileID } from '../../src/source/tile_id';
-export default [
- {
- "description": "Road labels – Houston, z12",
- "tileID": [new OverscaledTileID(12, 0, 12, 962, 1692)],
- "zoom": 12,
- "center": [-95.392263, 29.799396]
- },
- {
- "description": "Road labels – Houston, z13",
- "tileID": [new OverscaledTileID(13, 0, 13, 1925, 3386)],
- "zoom": 13,
- "center": [-95.38116, 29.74916]
- },
- {
- "description": "High zoom labels (also: buildings, roads) – New York City, z16",
- "tileID": [new OverscaledTileID(16, 0, 16, 19299, 24629)],
- "zoom": 16,
- "center": [-73.984682, 40.757660]
- },
- {
- "description": "High zoom labels (also: buildings, roads) – New York City, z17",
- "tileID": [new OverscaledTileID(17, 0, 17, 19299, 24629)],
- "zoom": 17,
- "center": [-73.984682, 40.757660]
- },
- {
- "description": "High zoom cjk labels, when using local lang (also: buildings, roads) – Tokyo, z16",
- "tileID": [new OverscaledTileID(16, 0, 16, 58210, 25803)],
- "zoom": 16,
- "center": [139.759860, 35.69522]
- },
- {
- "description": "High zoom cjk labels, when using local lang (also: buildings, roads) – Tokyo, z17",
- "tileID": [new OverscaledTileID(17, 0, 17, 58210, 25803)],
- "zoom": 17,
- "center": [139.759860, 35.69522]
- },
- {
- "description": "Water – Finland, z10",
- "tileID": [new OverscaledTileID(10, 0, 10, 590, 288)],
- "zoom": 10,
- "center": [27.602348, 61.520945]
- },
- {
- "description": "Landuse – Paris, z11",
- "tileID": [new OverscaledTileID(11, 0, 11, 1036, 705)],
- "zoom": 11,
- "center": [2.209530, 48.745030]
- },
- {
- "description": "Buildings – LA, z16",
- "tileID": [new OverscaledTileID(16, 0, 16, 11229, 26180)],
- "zoom": 6,
- "center": [-118.314417, 33.995654]
- },
- {
- "description": "High zoom (roads, paths, landuse, labels) – Paris, 15",
- "tileID": [new OverscaledTileID(15, 0, 15, 16594, 11271)],
- "zoom": 15,
- "center": [2.315725, 48.866517]
- },
- {
- "description": "High zoom (pedestrian polygon fills, roads, paths, landuse, labels) – Paris, z16.25",
- "tileID": [new OverscaledTileID(17, 0, 17, 33189, 22543)],
- "zoom": 16.25,
- "center": [2.315725, 48.866517]
- },
- {
- "description": "Hillshading – Switzerland, z9",
- "tileID": [new OverscaledTileID(9, 0, 9, 268, 181)],
- "zoom": 9,
- "center": [8.835221, 46.317157]
- },
- {
- "description": "Hillshading and contours – Switzerland, z12",
- "tileID": [new OverscaledTileID(12, 0, 12, 2148, 1452)],
- "zoom": 12,
- "center": [8.835221, 46.317157]
- },
- {
- "description": "Landcover – Germany z6",
- "tileID": [new OverscaledTileID(6, 0, 6, 33, 21)],
- "zoom": 6,
- "center": [8.429493, 51.056406]
- },
- {
- "description": "Landcover – Germany z8",
- "tileID": [new OverscaledTileID(8, 0, 8, 133, 86)],
- "zoom": 8,
- "center": [7.762074, 50.322133]
- }
-];
+export default styleBenchmarkLocations.features.map(feature => {
+ const { coordinates } = feature.geometry;
+ const { zoom } = feature.properties;
+ const { x, y } = MercatorCoordinate.fromLngLat({
+ lng: coordinates[0],
+ lat: coordinates[1]
+ });
+
+ const scale = Math.pow(2, zoom);
+ const tileX = Math.floor(x * scale);
+ const tileY = Math.floor(y * scale);
+
+ return {
+ description: feature.properties['place_name'],
+ tileID: [new OverscaledTileID(zoom, 0, zoom, tileX, tileY)],
+ zoom,
+ center: coordinates
+ };
+});
diff --git a/bench/rollup_config_benchmarks.js b/bench/rollup_config_benchmarks.js
new file mode 100644
index 00000000000..fd690cd11e2
--- /dev/null
+++ b/bench/rollup_config_benchmarks.js
@@ -0,0 +1,60 @@
+import fs from 'fs';
+import sourcemaps from 'rollup-plugin-sourcemaps';
+import replace from 'rollup-plugin-replace';
+import {plugins} from '../build/rollup_plugins';
+
+let styles = ['mapbox://styles/mapbox/streets-v10'];
+
+if (process.env.MAPBOX_STYLES) {
+ styles = process.env.MAPBOX_STYLES
+ .split(',')
+ .map(style => style.match(/\.json$/) ? require(style) : style);
+}
+
+const replaceConfig = {
+ 'process.env.BENCHMARK_VERSION': JSON.stringify(process.env.BENCHMARK_VERSION),
+ 'process.env.MAPBOX_ACCESS_TOKEN': JSON.stringify(process.env.MAPBOX_ACCESS_TOKEN),
+ 'process.env.MapboxAccessToken': JSON.stringify(process.env.MapboxAccessToken),
+ 'process.env.MAPBOX_STYLES': JSON.stringify(styles),
+ 'process.env.NODE_ENV': JSON.stringify('production')
+};
+
+const allPlugins = plugins(true, true).concat(replace(replaceConfig));
+const intro = fs.readFileSync('rollup/bundle_prelude.js', 'utf8');
+
+const splitConfig = (name) => [{
+ input: [`bench/${name}/benchmarks.js`, 'src/source/worker.js'],
+ output: {
+ dir: `rollup/build/benchmarks/${name}`,
+ format: 'amd',
+ indent: false,
+ sourcemap: 'inline',
+ chunkFileNames: 'shared.js'
+ },
+ plugins: allPlugins
+}, {
+ input: `rollup/benchmarks_${name}.js`,
+ output: {
+ file: `bench/${name}/benchmarks_generated.js`,
+ format: 'umd',
+ indent: false,
+ sourcemap: true,
+ intro
+ },
+ treeshake: false,
+ plugins: [sourcemaps()],
+}];
+
+const viewConfig = {
+ input: 'bench/benchmarks_view.js',
+ output: {
+ name: 'Benchmarks',
+ file: 'bench/benchmarks_view_generated.js',
+ format: 'umd',
+ indent: false,
+ sourcemap: true
+ },
+ plugins: allPlugins
+};
+
+export default splitConfig('versions').concat(splitConfig('styles')).concat(viewConfig);
diff --git a/bench/styles/benchmarks.js b/bench/styles/benchmarks.js
index e0ccdac9ea2..05f3905cba7 100644
--- a/bench/styles/benchmarks.js
+++ b/bench/styles/benchmarks.js
@@ -1,40 +1,6 @@
import mapboxgl from '../../src';
import accessToken from '../lib/access_token';
import locations from '../lib/style_locations';
-import { summaryStatistics, regression } from '../lib/statistics';
-import updateUI from '../benchmarks_view';
-
-mapboxgl.accessToken = accessToken;
-
-const benchmarks = [];
-const filter = window.location.hash.substr(1);
-
-function register(Benchmark, locations, options) {
- const name = Benchmark.name;
-
- if (filter && name !== filter)
- return;
-
- const benchmark = {
- name: Benchmark.name,
- versions: []
- };
-
- if (options) Object.assign(benchmark, options);
-
- process.env.MAPBOX_STYLES.forEach(style => {
- const { name } = style;
- benchmark.versions.push({
- name: name ? name : style.replace('mapbox://styles/', ''),
- bench: new Benchmark(style, locations),
- status: 'waiting',
- logs: [],
- samples: [],
- summary: {}
- });
- });
- benchmarks.push(benchmark);
-}
import StyleLayerCreate from '../benchmarks/style_layer_create';
import Validate from '../benchmarks/style_validate';
@@ -43,52 +9,37 @@ import Paint from '../benchmarks/paint';
import QueryPoint from '../benchmarks/query_point';
import QueryBox from '../benchmarks/query_box';
-register(StyleLayerCreate);
-register(Validate);
-locations.forEach(location => register(Layout, location.tileID, {location}));
-locations.forEach(location => register(Paint, [location], {location}));
-register(QueryPoint, locations);
-register(QueryBox, locations);
-
import getWorkerPool from '../../src/util/global_worker_pool';
-let promise = Promise.resolve();
+mapboxgl.accessToken = accessToken;
+
+const benchmarks = window.benchmarks = [];
+
+function register(name, Benchmark, locations, location) {
+ const versions = [];
+
+ for (const style of process.env.MAPBOX_STYLES) {
+ versions.push({
+ name: style.name || style.replace('mapbox://styles/', ''),
+ bench: new Benchmark(style, locations)
+ });
+ }
+ benchmarks.push({name, versions, location});
+}
-promise = promise.then(() => {
+register('StyleLayerCreate', StyleLayerCreate);
+register('Validate', Validate);
+locations.forEach(location => register('Layout', Layout, location.tileID, location));
+locations.forEach(location => register('Paint', Paint, [location], location));
+register('QueryPoint', QueryPoint, locations);
+register('QueryBox', QueryBox, locations);
+
+Promise.resolve().then(() => {
// Ensure the global worker pool is never drained. Browsers have resource limits
// on the max number of workers that can be created per page.
// We do this async to avoid creating workers before the worker bundle blob
// URL has been set up, which happens after this module is executed.
getWorkerPool().acquire(-1);
});
-benchmarks.forEach(bench => {
- bench.versions.forEach(version => {
- promise = promise.then(() => {
- version.status = 'running';
- updateUI(benchmarks);
-
- return version.bench.run()
- .then(measurements => {
- // scale measurements down by iteration count, so that
- // they represent (average) time for a single iteration
- const samples = measurements.map(({time, iterations}) => time / iterations);
- version.status = 'ended';
- version.samples = samples;
- version.summary = summaryStatistics(samples);
- version.regression = regression(measurements);
- updateUI(benchmarks);
- })
- .catch(error => {
- version.status = 'errored';
- version.error = error;
- updateUI(benchmarks);
- });
- });
- });
-
- promise = promise.then(() => {
- updateUI(benchmarks, true);
- });
-});
export default mapboxgl;
diff --git a/bench/styles/index.html b/bench/styles/index.html
index cb828dde442..4344efa5444 100644
--- a/bench/styles/index.html
+++ b/bench/styles/index.html
@@ -8,12 +8,15 @@
-
+
+