Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add live performance counters #12343

Merged
merged 20 commits into from
Nov 4, 2022
Merged

Conversation

karimnaaji
Copy link
Contributor

@karimnaaji karimnaaji commented Oct 26, 2022

This PR adds live (production build) performance counters recorded through telemetry to our events API. The server schema and addition is described in https://github.com/mapbox/event-schema/pull/242 for server side ingestion (which should be merged prior to merging this PR). These counters will serve to monitor performance on real environment, and allow us to support the resource bundling effort.

Here is an example of the counters, metadata and attributes that are being collected:

attributes

{name: 'style', value: 'mapbox:streets-v11'}
{name: 'terrain', value: 'false'}
{name: 'fog', value: 'false'}
{name: 'projection', value: 'mercator'}

counters

{name: 'javascriptTransferStart', value: '56.8999999910593'}
{name: 'javascriptTransferEnd', value: '83.8999999910593'}
{name: 'cssTransferStart', value: '57.8999999910593'}
{name: 'cssTransferEnd', value: '73.8999999910593'}
{name: 'styleTransferStart', value: {name: 'styleTransferEnd', value: '1168.0999999940395'}
{name: 'tilejsonTransferStart', value: '1419.5'}
{name: 'tilejsonTransferEnd', value: '1479.0999999940395'}
{name: 'spriteTransferStart', value: '1420.2999999970198'}
{name: 'spriteTransferEnd', value: '1498.0999999940395'}
{name: 'fontTransferStart', value: '1944.5'}
{name: 'fontTransferEnd', value: '1990.2999999970198'}

metadata

{name: 'devicePixelRatio', value: '2'}
{name: 'connectionEffectiveType', value: '4g'}
{name: 'cpuCores', value: '8'}
{name: 'userAgent', value: 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) Ap…KHTML, like Gecko) Chrome/107.0.0.0 Safari/537.36'}
{name: 'screenWidth', value: '2880'}
{name: 'screenHeight', value: '1800'}
{name: 'windowWidth', value: '1000'}
{name: 'windowHeight', value: '590'}
{name: 'mapWidth', value: '1000'}
{name: 'mapHeight', value: '590'}
{name: 'webglRenderer', value: 'ANGLE (Intel Inc., Intel(R) Iris(TM) Plus Graphics 655, OpenGL 4.1)'}
{name: 'webglVendor', value: 'Google Inc. (Intel {name: 'sdkVersion', value: '2.12.0-dev'}
{name: 'sdkIdentifier', value: 'mapbox-gl-js'}

Most of the context specific information is necessary to bucket performance traces in comparable groups. For example, we wouldn't want to compare viewport sizes that are widely different for rendering performance, but it is probably ok to do so for network and resource fetching performance comparisons.

Some of the attributes also provide us functionality usage information, such as terrain, fog and projection being used. Since these may use very different code paths in our codebase, it's important for us to bucket them separately when comparing and retrieving performance knowledge.

For now, this PR focuses on resource fetching information, for fonts, style, tilejson, sprites and code. Time to render content (TTRC) and rendering performance counters will be introduced separately.

resource fetching range

Resource loading that are seen from chrome performance tab usually involves the timing including both the fetching and the processing of the received data:

Screen Shot 2022-10-27 at 1 27 46 PM

in this PR the timing as referred to spriteTransferStart and spriteTransferEnd refers to the networkTransfer time mentioned above ranged from the earliest request for a resource category (css, javascript, sprites...) to the latest. For example, if two sprites network transfer duration were observed between the ranges (15ms, 80ms) and (20ms, 100ms), we will return the range (15ms, 100ms).

interaction range

One addition to this PR is the introduction of interaction range timings

I have considered adding an interaction history to our metrics, so that we can differentiate between a map that has interactions (where loading is similar to the context of benchmap, where you just load a map without any interaction), and not (for example a more complex interaction of user zooming in, panning... before the becomes idle). An interaction timeline would could have a format like this:

[
  interactionType [ timingStart, timingEnd ],
  interactionType [ timingStart, timingEnd ],
  ...
]

which would give, for example:

[
  zooming, 10, 20,
  panning, 15, 30,
  zooming, 50, 60
  ...
]

But for now, something as simple as:

interactionStart: timingStart
interactionEnd: timingEnd

is sufficient for our uses. It is less granular and only tells us the start and end of an any interaction, but that's enough for us to bucket all maps that do not have interaction on first load prior to being idle so that we compare them together.

The main idea being that we don't want to compare map performance for maps that don't have similar initial interaction behaviors and adding a full history of interaction will not be useful in order to do that bucketing. For example, we'd like to know when a map does a lot of extra tile loads before becoming idle due to excessive panning from the user since performance may be fairly different from a map without it.

It's important to note that this interaction range may be rounded to the ms due to the use of performance.now().

opting-out

This PR adds a map constructor option to opt-out of performance collection.

limitations

  • There is currently no way of consistently knowing whether a resource was cached or not (Safari doesn't support decodedBodySize and transferSize), this also limits information about network transfer sizes for cors resources
  • There is no way to retrieve CPU vendor information, so only webgl vendor information is included
  • Network speed information can only be retrieved through the networkEffectiveType and may not always be included depending on support

benchmark

Screen Shot 2022-10-27 at 4 57 06 PM

Launch Checklist

  • briefly describe the changes in this PR
  • write tests for all new functionality
  • document any changes to public APIs
  • post benchmark scores
  • manually test the debug page
  • apply changelog label ('bug', 'feature', 'docs', etc) or use the label 'skip changelog'
  • add an entry inside this element for inclusion in the mapbox-gl-js changelog: <changelog>Add live performance counters</changelog>

sdkVersion,
skuId: SKU_ID,
skuToken: this.skuToken,
userId: this.anonId

Check failure

Code scanning / CodeQL

Insecure randomness

This security context depends on a cryptographically insecure random number at [Math.random()](1).
sdkVersion,
skuId: SKU_ID,
"enabled.telemetry": false,
userId: this.anonId

Check failure

Code scanning / CodeQL

Insecure randomness

This security context depends on a cryptographically insecure random number at [Math.random()](1).
@karimnaaji karimnaaji marked this pull request as ready for review October 27, 2022 21:03
@karimnaaji karimnaaji requested a review from a team as a code owner October 27, 2022 21:03
src/util/config.js Outdated Show resolved Hide resolved
src/ui/map.js Outdated Show resolved Hide resolved
Copy link
Contributor

@stepankuzmin stepankuzmin left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall this looks good to me! However, could you please ensure that we don't accidentally drop any payload from the existing events such as MapLoadEvent, MapSessionAPI, and TurnstileEvent?

src/util/live_performance.js Outdated Show resolved Hide resolved
src/util/mapbox.js Outdated Show resolved Hide resolved
src/util/live_performance.js Outdated Show resolved Hide resolved
src/util/live_performance.js Outdated Show resolved Hide resolved
src/util/live_performance.js Outdated Show resolved Hide resolved
src/util/live_performance.js Outdated Show resolved Hide resolved
src/util/live_performance.js Outdated Show resolved Hide resolved
src/ui/map.js Outdated Show resolved Hide resolved
@karimnaaji karimnaaji force-pushed the karim/live-performance-counters branch from 6ce835b to e9c4e0b Compare November 4, 2022 21:23
@karimnaaji karimnaaji merged commit ea99e55 into main Nov 4, 2022
@karimnaaji karimnaaji deleted the karim/live-performance-counters branch November 4, 2022 21:35
avpeery pushed a commit that referenced this pull request Nov 7, 2022
* Add resource performance counters

* Add mapbox URL regexs

* Fix inverted gl VENDOR/RENDERER

* Add unit tests

* Add unit tests

* Add unit tests

* Fix lint

* Add map constructor option enablePerformanceMetricsCollection

* Add unit tests for metrics collection map option

* Add unit tests for live_performance

* Fix lint

* Fix lint

* Apply review comments

* Address some review comments

* Update style format

* Remove harwdare concurrency

* Address review comments

* Revert unused

* Store fullLoad before sending the event

* Fix lint
avpeery added a commit that referenced this pull request Nov 7, 2022
* Add resource performance counters

* Add mapbox URL regexs

* Fix inverted gl VENDOR/RENDERER

* Add unit tests

* Add unit tests

* Add unit tests

* Fix lint

* Add map constructor option enablePerformanceMetricsCollection

* Add unit tests for metrics collection map option

* Add unit tests for live_performance

* Fix lint

* Fix lint

* Apply review comments

* Address some review comments

* Update style format

* Remove harwdare concurrency

* Address review comments

* Revert unused

* Store fullLoad before sending the event

* Fix lint

Co-authored-by: Karim Naaji <karim.naaji@gmail.com>
@rafraser
Copy link

I'm a little concerned about the lack of communication from Mapbox about this feature. It looks like this has some serious implications for our product's privacy policy.

I understand that this is incredibly valuable data to help improve the product - I'm just not happy that this has been essentially snuck into a release, defaulting to collecting quite detailed data.

@mathewantony31
Copy link

@rafraser thanks for flagging your concern, we're updating our release notes to provide additional clarity. Mapbox takes data privacy and security very seriously. In line with our privacy by design practices, the GL JS live performance counter was carefully designed so that user-level metrics and identifiers are not collected. We welcome any follow-on questions you may have regarding our ongoing commitment to data privacy and security.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants