From e075a44a191a1488554a37aa69d45783e5e75460 Mon Sep 17 00:00:00 2001 From: Vladimir Agafonkin Date: Thu, 16 Aug 2018 15:51:18 -0700 Subject: [PATCH 1/5] make the layout bench more extensible --- bench/benchmarks/layout.js | 40 +++++++++++++++++++++++++------------- 1 file changed, 26 insertions(+), 14 deletions(-) diff --git a/bench/benchmarks/layout.js b/bench/benchmarks/layout.js index f6860c1d753..b102c460080 100644 --- a/bench/benchmarks/layout.js +++ b/bench/benchmarks/layout.js @@ -66,13 +66,6 @@ export default class Layout extends Benchmark { this.glyphs = {}; this.icons = {}; - const preloadGlyphs = (params, callback) => { - style.getGlyphs('', params, (err, glyphs) => { - this.glyphs[JSON.stringify(params)] = glyphs; - callback(err, glyphs); - }); - }; - const preloadImages = (params, callback) => { style.getImages('', params, (err, icons) => { this.icons[JSON.stringify(params)] = icons; @@ -80,27 +73,32 @@ export default class Layout extends Benchmark { }); }; - return this.bench(preloadGlyphs, preloadImages); + const preloadGlyphs = (params, callback) => { + style.getGlyphs('', params, (err, glyphs) => { + this.glyphs[JSON.stringify(params)] = glyphs; + callback(err, glyphs); + }); + }; + + return this.parseTiles(preloadImages, preloadGlyphs); }); } - bench(getGlyphs: Function = (params, callback) => callback(null, this.glyphs[JSON.stringify(params)]), - getImages: Function = (params, callback) => callback(null, this.icons[JSON.stringify(params)])) { + parseTiles(loadImages: Function, loadGlyphs: Function) { + let promise: Promise = Promise.resolve(); const actor = { send(action, params, callback) { setTimeout(() => { if (action === 'getImages') { - getImages(params, callback); + loadImages(params, callback); } else if (action === 'getGlyphs') { - getGlyphs(params, callback); + loadGlyphs(params, callback); } else assert(false); }, 0); } }; - let promise: Promise = Promise.resolve(); - for (const {tileID, buffer} of this.tiles) { promise = promise.then(() => { const workerTile = new WorkerTile({ @@ -126,9 +124,23 @@ export default class Layout extends Benchmark { const parse = promisify(workerTile.parse.bind(workerTile)); return parse(tile, this.layerIndex, actor); + }).then((data) => { + this.onTileParse(data); }); } return promise; } + + onTileParse(data: any) { + /* eslint no-unused-vars: 0 */ + // noop + } + + bench() { + const loadGlyphs = (params, callback) => callback(null, this.glyphs[JSON.stringify(params)]); + const loadImages = (params, callback) => callback(null, this.icons[JSON.stringify(params)]); + + return this.parseTiles(loadImages, loadGlyphs); + } } From e5adac052ab99090dd363234602678900f6fb2fa Mon Sep 17 00:00:00 2001 From: Vladimir Agafonkin Date: Thu, 16 Aug 2018 17:06:36 -0700 Subject: [PATCH 2/5] add a worker transfer benchmark --- bench/benchmarks.js | 2 ++ bench/benchmarks/worker_transfer.js | 56 +++++++++++++++++++++++++++++ 2 files changed, 58 insertions(+) create mode 100644 bench/benchmarks/worker_transfer.js diff --git a/bench/benchmarks.js b/bench/benchmarks.js index 83ee21fd21b..048dc6502e3 100644 --- a/bench/benchmarks.js +++ b/bench/benchmarks.js @@ -17,6 +17,7 @@ function register(Benchmark) { import Layout from './benchmarks/layout'; import LayoutDDS from './benchmarks/layout_dds'; +import WorkerTransfer from './benchmarks/worker_transfer'; import Paint from './benchmarks/paint'; import PaintStates from './benchmarks/paint_states'; import LayerBenchmarks from './benchmarks/layers'; @@ -31,6 +32,7 @@ import FilterEvaluate from './benchmarks/filter_evaluate'; register(Layout); register(LayoutDDS); +register(WorkerTransfer); register(Paint); register(PaintStates); LayerBenchmarks.forEach(register); diff --git a/bench/benchmarks/worker_transfer.js b/bench/benchmarks/worker_transfer.js new file mode 100644 index 00000000000..e4abfcf3e07 --- /dev/null +++ b/bench/benchmarks/worker_transfer.js @@ -0,0 +1,56 @@ +// @flow + +import Layout from './layout'; +import { serialize } from '../../src/util/web_worker_transfer'; + +export default class WorkerTransfer extends Layout { + payload: Array; + worker: Worker; + + setup(): Promise { + this.payload = []; + const promise = super.setup(); + + const src = ` + onmessage = (e) => { + postMessage(e.data); + }; + `; + const url = window.URL.createObjectURL(new Blob([src], {type: 'text/javascript'})); + this.worker = new Worker(url); + + return promise.then(() => { + for (const key in this.glyphs) this.payload.push(barePayload(this.glyphs[key])); + for (const key in this.icons) this.payload.push(barePayload(this.icons[key])); + // console.log(this.payload.map(p => JSON.stringify(p).length)); + }); + } + + onTileParse(data: any) { + this.payload.push(barePayload(data)); + } + + sendPayload(obj: any) { + return new Promise((resolve) => { + this.worker.onmessage = () => resolve(); + this.worker.postMessage(obj); + }); + } + + bench(): Promise { + let promise: Promise = Promise.resolve(); + + for (const obj of this.payload) { + promise = promise.then(() => { + return this.sendPayload(obj); + }); + } + + return promise; + } +} + +function barePayload(obj) { + // strip all transferables from a worker payload + return JSON.parse(JSON.stringify(serialize(obj, []), (key, value) => ArrayBuffer.isView(value) ? {} : value)); +} From e5a891b5a7cd26664d20a85bec9d6bd9a167c502 Mon Sep 17 00:00:00 2001 From: John Firebaugh Date: Fri, 17 Aug 2018 12:15:41 -0700 Subject: [PATCH 3/5] Extract and reuse utility methods from Layout benchmark --- bench/benchmarks/layout.js | 117 ++++++---------------------- bench/benchmarks/layout_dds.js | 54 ++++++++----- bench/benchmarks/worker_transfer.js | 60 +++++++++++--- bench/lib/fetch_style.js | 9 +++ bench/lib/fetch_tiles.js | 17 ++++ bench/lib/parse_tiles.js | 63 +++++++++++++++ src/style-spec/types.js | 1 + 7 files changed, 197 insertions(+), 124 deletions(-) create mode 100644 bench/lib/fetch_style.js create mode 100644 bench/lib/fetch_tiles.js create mode 100644 bench/lib/parse_tiles.js diff --git a/bench/benchmarks/layout.js b/bench/benchmarks/layout.js index b102c460080..c1029376cde 100644 --- a/bench/benchmarks/layout.js +++ b/bench/benchmarks/layout.js @@ -1,65 +1,35 @@ // @flow import Benchmark from '../lib/benchmark'; - +import fetchStyle from '../lib/fetch_style'; import createStyle from '../lib/create_style'; -import VT from '@mapbox/vector-tile'; -import Protobuf from 'pbf'; -import assert from 'assert'; -import promisify from 'pify'; -import WorkerTile from '../../src/source/worker_tile'; +import fetchTiles from '../lib/fetch_tiles'; +import parseTiles from '../lib/parse_tiles'; import StyleLayerIndex from '../../src/style/style_layer_index'; import deref from '../../src/style-spec/deref'; import { OverscaledTileID } from '../../src/source/tile_id'; -import { normalizeStyleURL, normalizeSourceURL, normalizeTileURL } from '../../src/util/mapbox'; - -import type {TileJSON} from '../../src/types/tilejson'; -import type {StyleSpecification} from '../../src/style-spec/types'; -// Note: this class is extended in turn by the LayoutDDS benchmark. export default class Layout extends Benchmark { glyphs: Object; icons: Object; - workerTile: WorkerTile; layerIndex: StyleLayerIndex; tiles: Array<{tileID: OverscaledTileID, buffer: ArrayBuffer}>; - tileIDs(): Array { - return [ + setup(): Promise { + const tileIDs = [ new OverscaledTileID(12, 0, 12, 655, 1583), new OverscaledTileID(8, 0, 8, 40, 98), new OverscaledTileID(4, 0, 4, 3, 6), new OverscaledTileID(0, 0, 0, 0, 0) ]; - } - - sourceID(): string { - return 'composite'; - } - - fetchStyle(): Promise { - return fetch(normalizeStyleURL(`mapbox://styles/mapbox/streets-v9`)) - .then(response => response.json()); - } - - fetchTiles(styleJSON: StyleSpecification): Promise> { - const sourceURL: string = (styleJSON.sources[this.sourceID()]: any).url; - return fetch(normalizeSourceURL(sourceURL)) - .then(response => response.json()) - .then((tileJSON: TileJSON) => { - return Promise.all(this.tileIDs().map(tileID => { - return fetch((normalizeTileURL(tileID.canonical.url(tileJSON.tiles)))) - .then(response => response.arrayBuffer()) - .then(buffer => ({tileID, buffer})); - })); - }); - } - setup(): Promise { - return this.fetchStyle() + return fetchStyle(`mapbox://styles/mapbox/streets-v9`) .then((styleJSON) => { this.layerIndex = new StyleLayerIndex(deref(styleJSON.layers)); - return Promise.all([createStyle(styleJSON), this.fetchTiles(styleJSON)]); + return Promise.all([ + createStyle(styleJSON), + fetchTiles((styleJSON.sources.composite: any).url, tileIDs) + ]); }) .then(([style, tiles]) => { this.tiles = tiles; @@ -80,67 +50,24 @@ export default class Layout extends Benchmark { }); }; - return this.parseTiles(preloadImages, preloadGlyphs); + return parseTiles('composite', + this.tiles, + this.layerIndex, + preloadImages, + preloadGlyphs) + .then(() => {}); }); } - parseTiles(loadImages: Function, loadGlyphs: Function) { - let promise: Promise = Promise.resolve(); - - const actor = { - send(action, params, callback) { - setTimeout(() => { - if (action === 'getImages') { - loadImages(params, callback); - } else if (action === 'getGlyphs') { - loadGlyphs(params, callback); - } else assert(false); - }, 0); - } - }; - - for (const {tileID, buffer} of this.tiles) { - promise = promise.then(() => { - const workerTile = new WorkerTile({ - tileID: tileID, - zoom: tileID.overscaledZ, - tileSize: 512, - overscaling: 1, - showCollisionBoxes: false, - source: this.sourceID(), - uid: '0', - maxZoom: 22, - pixelRatio: 1, - request: { - url: '' - }, - angle: 0, - pitch: 0, - cameraToCenterDistance: 0, - cameraToTileDistance: 0 - }); - - const tile = new VT.VectorTile(new Protobuf(buffer)); - const parse = promisify(workerTile.parse.bind(workerTile)); - - return parse(tile, this.layerIndex, actor); - }).then((data) => { - this.onTileParse(data); - }); - } - - return promise; - } - - onTileParse(data: any) { - /* eslint no-unused-vars: 0 */ - // noop - } - bench() { const loadGlyphs = (params, callback) => callback(null, this.glyphs[JSON.stringify(params)]); const loadImages = (params, callback) => callback(null, this.icons[JSON.stringify(params)]); - return this.parseTiles(loadImages, loadGlyphs); + return parseTiles('composite', + this.tiles, + this.layerIndex, + loadImages, + loadGlyphs) + .then(() => {}); } } diff --git a/bench/benchmarks/layout_dds.js b/bench/benchmarks/layout_dds.js index 0751faf96fa..348079c5de8 100644 --- a/bench/benchmarks/layout_dds.js +++ b/bench/benchmarks/layout_dds.js @@ -1,26 +1,24 @@ // @flow -import Layout from './layout'; - +import assert from 'assert'; +import Benchmark from '../lib/benchmark'; +import fetchTiles from '../lib/fetch_tiles'; +import parseTiles from '../lib/parse_tiles'; +import StyleLayerIndex from '../../src/style/style_layer_index'; import { OverscaledTileID } from '../../src/source/tile_id'; -import type {StyleSpecification} from '../../src/style-spec/types'; - const LAYER_COUNT = 2; -export default class LayoutDDS extends Layout { - tileIDs(): Array { - return [ +export default class LayoutDDS extends Benchmark { + layerIndex: StyleLayerIndex; + tiles: Array<{tileID: OverscaledTileID, buffer: ArrayBuffer}>; + + setup(): Promise { + const tileIDs = [ new OverscaledTileID(15, 0, 15, 9373, 12535) ]; - } - sourceID(): string { - return 'mapbox'; - } - - fetchStyle(): Promise { - const style = { + const styleJSON = { "version": 8, "sources": { "mapbox": { "type": "vector", "url": "mapbox://mapbox.mapbox-streets-v7" } @@ -85,14 +83,34 @@ export default class LayoutDDS extends Layout { } ]; - while (style.layers.length < LAYER_COUNT) { + while (styleJSON.layers.length < LAYER_COUNT) { for (const layer of layers) { - style.layers.push(Object.assign(({}: any), layer, { - id: layer.id + style.layers.length + styleJSON.layers.push(Object.assign(({}: any), layer, { + id: layer.id + styleJSON.layers.length })); } } - return Promise.resolve(style); + this.layerIndex = new StyleLayerIndex(styleJSON.layers); + + return fetchTiles(styleJSON.sources.mapbox.url, tileIDs) + .then(tiles => { + this.tiles = tiles; + return parseTiles('mapbox', + this.tiles, + this.layerIndex, + () => assert(false), // The style above doesn't use any glyphs or icons. + () => assert(false)); + }) + .then(() => {}); + } + + bench() { + return parseTiles('mapbox', + this.tiles, + this.layerIndex, + () => assert(false), + () => assert(false)) + .then(() => {}); } } diff --git a/bench/benchmarks/worker_transfer.js b/bench/benchmarks/worker_transfer.js index e4abfcf3e07..4809cef09e7 100644 --- a/bench/benchmarks/worker_transfer.js +++ b/bench/benchmarks/worker_transfer.js @@ -1,15 +1,23 @@ // @flow -import Layout from './layout'; +import Benchmark from '../lib/benchmark'; +import fetchStyle from '../lib/fetch_style'; +import createStyle from '../lib/create_style'; +import fetchTiles from '../lib/fetch_tiles'; +import parseTiles from '../lib/parse_tiles'; + import { serialize } from '../../src/util/web_worker_transfer'; +import StyleLayerIndex from '../../src/style/style_layer_index'; +import {OverscaledTileID} from '../../src/source/tile_id'; +import deref from '../../src/style-spec/deref'; -export default class WorkerTransfer extends Layout { +export default class WorkerTransfer extends Benchmark { + layerIndex: StyleLayerIndex; payload: Array; worker: Worker; setup(): Promise { this.payload = []; - const promise = super.setup(); const src = ` onmessage = (e) => { @@ -19,15 +27,45 @@ export default class WorkerTransfer extends Layout { const url = window.URL.createObjectURL(new Blob([src], {type: 'text/javascript'})); this.worker = new Worker(url); - return promise.then(() => { - for (const key in this.glyphs) this.payload.push(barePayload(this.glyphs[key])); - for (const key in this.icons) this.payload.push(barePayload(this.icons[key])); - // console.log(this.payload.map(p => JSON.stringify(p).length)); - }); - } + const tileIDs = [ + new OverscaledTileID(12, 0, 12, 655, 1583), + new OverscaledTileID(8, 0, 8, 40, 98), + new OverscaledTileID(4, 0, 4, 3, 6), + new OverscaledTileID(0, 0, 0, 0, 0) + ]; - onTileParse(data: any) { - this.payload.push(barePayload(data)); + return fetchStyle(`mapbox://styles/mapbox/streets-v9`) + .then((styleJSON) => { + this.layerIndex = new StyleLayerIndex(deref(styleJSON.layers)); + return Promise.all([ + createStyle(styleJSON), + fetchTiles((styleJSON.sources.composite: any).url, tileIDs) + ]); + }) + .then(([style, tiles]) => { + const preloadImages = (params, callback) => { + style.getImages('', params, (err, icons) => { + this.payload.push(barePayload(icons)); + callback(err, icons); + }); + }; + + const preloadGlyphs = (params, callback) => { + style.getGlyphs('', params, (err, glyphs) => { + this.payload.push(barePayload(glyphs)); + callback(err, glyphs); + }); + }; + + return parseTiles('composite', + tiles, + this.layerIndex, + preloadImages, + preloadGlyphs); + }).then((tileResults) => { + for (const data of tileResults) this.payload.push(barePayload(data)); + // console.log(this.payload.map(p => JSON.stringify(p).length)); + }); } sendPayload(obj: any) { diff --git a/bench/lib/fetch_style.js b/bench/lib/fetch_style.js new file mode 100644 index 00000000000..e2e9a2ac221 --- /dev/null +++ b/bench/lib/fetch_style.js @@ -0,0 +1,9 @@ +// @flow + +import type {StyleSpecification} from '../../src/style-spec/types'; +import {normalizeStyleURL} from '../../src/util/mapbox'; + +export default function fetchStyle(url: string): Promise { + return fetch(normalizeStyleURL(url)) + .then(response => response.json()); +} diff --git a/bench/lib/fetch_tiles.js b/bench/lib/fetch_tiles.js new file mode 100644 index 00000000000..fff0cfc9407 --- /dev/null +++ b/bench/lib/fetch_tiles.js @@ -0,0 +1,17 @@ +// @flow + +import {OverscaledTileID} from '../../src/source/tile_id'; +import {normalizeSourceURL, normalizeTileURL} from '../../src/util/mapbox'; +import type {TileJSON} from '../../src/types/tilejson'; + +export default function fetchTiles(sourceURL: string, tileIDs: Array): Promise> { + return fetch(normalizeSourceURL(sourceURL)) + .then(response => response.json()) + .then((tileJSON: TileJSON) => { + return Promise.all(tileIDs.map(tileID => { + return fetch(normalizeTileURL(tileID.canonical.url(tileJSON.tiles))) + .then(response => response.arrayBuffer()) + .then(buffer => ({tileID, buffer})); + })); + }); +} diff --git a/bench/lib/parse_tiles.js b/bench/lib/parse_tiles.js new file mode 100644 index 00000000000..0b540483b45 --- /dev/null +++ b/bench/lib/parse_tiles.js @@ -0,0 +1,63 @@ +// @flow + +import assert from 'assert'; +import promisify from 'pify'; +import Protobuf from 'pbf'; +import VT from '@mapbox/vector-tile'; + +import WorkerTile from '../../src/source/worker_tile'; +import {type WorkerTileResult} from '../../src/source/worker_source'; +import {OverscaledTileID} from '../../src/source/tile_id'; +import StyleLayerIndex from '../../src/style/style_layer_index'; + +export default function parseTiles(sourceID: string, + tiles: Array<{tileID: OverscaledTileID, buffer: ArrayBuffer}>, + layerIndex: StyleLayerIndex, + loadImages: Function, + loadGlyphs: Function): Promise> { + let promise: Promise = Promise.resolve(); + + const actor = { + send(action, params, callback) { + setTimeout(() => { + if (action === 'getImages') { + loadImages(params, callback); + } else if (action === 'getGlyphs') { + loadGlyphs(params, callback); + } else assert(false); + }, 0); + } + }; + + const results = []; + for (const {tileID, buffer} of tiles) { + promise = promise.then(() => { + const workerTile = new WorkerTile({ + tileID: tileID, + zoom: tileID.overscaledZ, + tileSize: 512, + overscaling: 1, + showCollisionBoxes: false, + source: sourceID, + uid: '0', + maxZoom: 22, + pixelRatio: 1, + request: { + url: '' + }, + angle: 0, + pitch: 0, + cameraToCenterDistance: 0, + cameraToTileDistance: 0 + }); + + const tile = new VT.VectorTile(new Protobuf(buffer)); + const parse = promisify(workerTile.parse.bind(workerTile)); + + return parse(tile, layerIndex, actor) + .then(result => results.push(result)); + }); + } + + return promise.then(() => results); +} diff --git a/src/style-spec/types.js b/src/style-spec/types.js index a65db4ff90f..79f2a51383d 100644 --- a/src/style-spec/types.js +++ b/src/style-spec/types.js @@ -408,3 +408,4 @@ export type LayerSpecification = | RasterLayerSpecification | HillshadeLayerSpecification | BackgroundLayerSpecification; + From 2a6944bf80f8fddf753def13f41bfcc49bd06e4d Mon Sep 17 00:00:00 2001 From: Vladimir Agafonkin Date: Fri, 17 Aug 2018 13:53:56 -0700 Subject: [PATCH 4/5] refactor benchmarks further --- bench/benchmarks/layout.js | 67 ++++--------- bench/benchmarks/layout_dds.js | 38 ++++---- bench/benchmarks/worker_transfer.js | 55 ++++------- bench/lib/create_style.js | 24 ----- bench/lib/fetch_tiles.js | 17 ---- bench/lib/parse_tiles.js | 63 ------------- bench/lib/tile_parser.js | 141 ++++++++++++++++++++++++++++ 7 files changed, 196 insertions(+), 209 deletions(-) delete mode 100644 bench/lib/create_style.js delete mode 100644 bench/lib/fetch_tiles.js delete mode 100644 bench/lib/parse_tiles.js create mode 100644 bench/lib/tile_parser.js diff --git a/bench/benchmarks/layout.js b/bench/benchmarks/layout.js index c1029376cde..6763b296f0d 100644 --- a/bench/benchmarks/layout.js +++ b/bench/benchmarks/layout.js @@ -2,18 +2,12 @@ import Benchmark from '../lib/benchmark'; import fetchStyle from '../lib/fetch_style'; -import createStyle from '../lib/create_style'; -import fetchTiles from '../lib/fetch_tiles'; -import parseTiles from '../lib/parse_tiles'; -import StyleLayerIndex from '../../src/style/style_layer_index'; -import deref from '../../src/style-spec/deref'; +import TileParser from '../lib/tile_parser'; import { OverscaledTileID } from '../../src/source/tile_id'; export default class Layout extends Benchmark { - glyphs: Object; - icons: Object; - layerIndex: StyleLayerIndex; tiles: Array<{tileID: OverscaledTileID, buffer: ArrayBuffer}>; + parser: TileParser; setup(): Promise { const tileIDs = [ @@ -22,52 +16,29 @@ export default class Layout extends Benchmark { new OverscaledTileID(4, 0, 4, 3, 6), new OverscaledTileID(0, 0, 0, 0, 0) ]; - return fetchStyle(`mapbox://styles/mapbox/streets-v9`) .then((styleJSON) => { - this.layerIndex = new StyleLayerIndex(deref(styleJSON.layers)); - return Promise.all([ - createStyle(styleJSON), - fetchTiles((styleJSON.sources.composite: any).url, tileIDs) - ]); + this.parser = new TileParser(styleJSON, 'composite'); + return this.parser.setup(); + }) + .then(() => { + return Promise.all(tileIDs.map(tileID => this.parser.fetchTile(tileID))); }) - .then(([style, tiles]) => { + .then((tiles) => { this.tiles = tiles; - this.glyphs = {}; - this.icons = {}; - - const preloadImages = (params, callback) => { - style.getImages('', params, (err, icons) => { - this.icons[JSON.stringify(params)] = icons; - callback(err, icons); - }); - }; - - const preloadGlyphs = (params, callback) => { - style.getGlyphs('', params, (err, glyphs) => { - this.glyphs[JSON.stringify(params)] = glyphs; - callback(err, glyphs); - }); - }; - - return parseTiles('composite', - this.tiles, - this.layerIndex, - preloadImages, - preloadGlyphs) - .then(() => {}); - }); + // parse tiles once to populate glyph/icon cache + return Promise.all(tiles.map(tile => this.parser.parseTile(tile))); + }) + .then(() => {}); } bench() { - const loadGlyphs = (params, callback) => callback(null, this.glyphs[JSON.stringify(params)]); - const loadImages = (params, callback) => callback(null, this.icons[JSON.stringify(params)]); - - return parseTiles('composite', - this.tiles, - this.layerIndex, - loadImages, - loadGlyphs) - .then(() => {}); + let promise = Promise.resolve(); + for (const tile of this.tiles) { + promise = promise.then(() => { + return this.parser.parseTile(tile).then(() => {}); + }); + } + return promise; } } diff --git a/bench/benchmarks/layout_dds.js b/bench/benchmarks/layout_dds.js index 348079c5de8..887056cb12e 100644 --- a/bench/benchmarks/layout_dds.js +++ b/bench/benchmarks/layout_dds.js @@ -1,17 +1,15 @@ // @flow -import assert from 'assert'; import Benchmark from '../lib/benchmark'; -import fetchTiles from '../lib/fetch_tiles'; -import parseTiles from '../lib/parse_tiles'; -import StyleLayerIndex from '../../src/style/style_layer_index'; +import TileParser from '../lib/tile_parser'; import { OverscaledTileID } from '../../src/source/tile_id'; + const LAYER_COUNT = 2; export default class LayoutDDS extends Benchmark { - layerIndex: StyleLayerIndex; tiles: Array<{tileID: OverscaledTileID, buffer: ArrayBuffer}>; + parser: TileParser; setup(): Promise { const tileIDs = [ @@ -91,26 +89,26 @@ export default class LayoutDDS extends Benchmark { } } - this.layerIndex = new StyleLayerIndex(styleJSON.layers); - - return fetchTiles(styleJSON.sources.mapbox.url, tileIDs) - .then(tiles => { + this.parser = new TileParser(styleJSON, 'mapbox'); + return this.parser.setup() + .then(() => { + return Promise.all(tileIDs.map(tileID => this.parser.fetchTile(tileID))); + }) + .then((tiles) => { this.tiles = tiles; - return parseTiles('mapbox', - this.tiles, - this.layerIndex, - () => assert(false), // The style above doesn't use any glyphs or icons. - () => assert(false)); + // parse tiles once to populate glyph/icon cache + return Promise.all(tiles.map(tile => this.parser.parseTile(tile))); }) .then(() => {}); } bench() { - return parseTiles('mapbox', - this.tiles, - this.layerIndex, - () => assert(false), - () => assert(false)) - .then(() => {}); + let promise = Promise.resolve(); + for (const tile of this.tiles) { + promise = promise.then(() => { + return this.parser.parseTile(tile).then(() => {}); + }); + } + return promise; } } diff --git a/bench/benchmarks/worker_transfer.js b/bench/benchmarks/worker_transfer.js index 4809cef09e7..ea587c20106 100644 --- a/bench/benchmarks/worker_transfer.js +++ b/bench/benchmarks/worker_transfer.js @@ -2,17 +2,13 @@ import Benchmark from '../lib/benchmark'; import fetchStyle from '../lib/fetch_style'; -import createStyle from '../lib/create_style'; -import fetchTiles from '../lib/fetch_tiles'; -import parseTiles from '../lib/parse_tiles'; - +import TileParser from '../lib/tile_parser'; +import { OverscaledTileID } from '../../src/source/tile_id'; import { serialize } from '../../src/util/web_worker_transfer'; -import StyleLayerIndex from '../../src/style/style_layer_index'; -import {OverscaledTileID} from '../../src/source/tile_id'; -import deref from '../../src/style-spec/deref'; +import { values } from '../../src/util/util'; export default class WorkerTransfer extends Benchmark { - layerIndex: StyleLayerIndex; + parser: TileParser; payload: Array; worker: Worker; @@ -36,35 +32,18 @@ export default class WorkerTransfer extends Benchmark { return fetchStyle(`mapbox://styles/mapbox/streets-v9`) .then((styleJSON) => { - this.layerIndex = new StyleLayerIndex(deref(styleJSON.layers)); - return Promise.all([ - createStyle(styleJSON), - fetchTiles((styleJSON.sources.composite: any).url, tileIDs) - ]); + this.parser = new TileParser(styleJSON, 'composite'); + return this.parser.setup(); }) - .then(([style, tiles]) => { - const preloadImages = (params, callback) => { - style.getImages('', params, (err, icons) => { - this.payload.push(barePayload(icons)); - callback(err, icons); - }); - }; - - const preloadGlyphs = (params, callback) => { - style.getGlyphs('', params, (err, glyphs) => { - this.payload.push(barePayload(glyphs)); - callback(err, glyphs); - }); - }; - - return parseTiles('composite', - tiles, - this.layerIndex, - preloadImages, - preloadGlyphs); + .then(() => { + return Promise.all(tileIDs.map(tileID => this.parser.fetchTile(tileID))); + }) + .then((tiles) => { + return Promise.all(tiles.map(tile => this.parser.parseTile(tile))); }).then((tileResults) => { - for (const data of tileResults) this.payload.push(barePayload(data)); - // console.log(this.payload.map(p => JSON.stringify(p).length)); + this.payload = tileResults.map(barePayload) + .concat(values(this.parser.icons).map(barePayload)) + .concat(values(this.parser.glyphs).map(barePayload)); }); } @@ -89,6 +68,8 @@ export default class WorkerTransfer extends Benchmark { } function barePayload(obj) { - // strip all transferables from a worker payload - return JSON.parse(JSON.stringify(serialize(obj, []), (key, value) => ArrayBuffer.isView(value) ? {} : value)); + // 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 + const str = JSON.stringify(serialize(obj, []), (key, value) => ArrayBuffer.isView(value) ? {} : value); + return JSON.parse(str); } diff --git a/bench/lib/create_style.js b/bench/lib/create_style.js deleted file mode 100644 index 622247c0c8a..00000000000 --- a/bench/lib/create_style.js +++ /dev/null @@ -1,24 +0,0 @@ -// @flow - -import Style from '../../src/style/style'; - -import { Evented } from '../../src/util/evented'; - -import type {StyleSpecification} from '../../src/style-spec/types'; - -class StubMap extends Evented { - _transformRequest(url) { - return { url }; - } -} - -export default function (styleJSON: StyleSpecification): Promise