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

Compressed ServerTiming #17

merged 7 commits into from Aug 30, 2017


Copy link

@cvazac cvazac commented Aug 22, 2017

Server-timing entries are included on resource- and navigation-timing entries as serverTiming. They must have a name, might have a non-empty description, and will likely have a non-zero duration. This compression is build on the presumption that resources will have server timing entries with unique durations pointing mostly to the same name and descriptions. There are two parts to this compression:

  1. a data structure containing all of the unique name and description pairs (an array of arrays)
  2. for each resource timing entry, a list of duration and index pairs, where duration is the duration of the server timing entry and the index identifies the name and description in 1)

For example, when:
resource1 has 2 entries: m1=value1;desc1, m2=value2;desc3
resource2 has 2 entries: m1=value3;desc1, m1=value4;desc2
-on the beacon, we will send a servertiming of: [[m1, desc1, desc2], [m2, desc3]], as there are three unique "pairs" of metric and description: m1/desc1, m1/desc2, and m2/desc3
-in the compressed resource timing data for resource1, we will add: value1:0.0 (value=value1, entryIndex=0, descriptionIndex=0) and value2:1.0 (value=value2, entryIndex=1, descriptionIndex=0)
In the compressed resource timing data for resource2, we will add: value3:0.0 (value=value3, entryIndex=0, descriptionIndex=0) and value4:0.1 (value=value4, entryIndex=0, descriptionIndex=1).

To save bytes, we will omit the zeroes, and irrelevant separators. So:
value:1.0 becomes value:1
value:0.1 becomes value:.1
value:0.0 becomes value

And last, if there is only one description for a given metric and it is === '', then we omit that array entry:
[["description1", ""]] becomes [["description1"]]

To test:
navigate to:

performance.getEntries().filter(e => e.serverTiming && e.serverTiming.length).reduce(function(arr, {serverTiming}) { arr = arr.concat(serverTiming); return arr; }, [])

return three entries:

  {name: "geoip", duration: 0.002274549, description: "geoip/geoip"}, 
  {name: "experiments", duration: 0.004756578, description: "api-v2/experiments"}, 
  {name: "geoip", duration: 0.001746519, description: "geoip/geoip"}

equals: [["geoip", "geoip/geoip"], ["experiments", "api-v2/experiments"]
(Note: that "geoip" is before "experiments")

As it turns out, all three server timing entries are on the navigation timing entry (base page), so step into the trie like this:
you get back:

In there you will find your three server timing entries.
Isolate the right dimension data: *30.002274549,0.004756578:1,0.001746519
lop off the *3 to get: 0.002274549,0.004756578:1,0.001746519

split at the comma:
entry one: 0.002274549 (correlates to "geoip" / "geoip/geoip")
entry two: 0.004756578:1 (correlates to "experiments" / "api-v2/experiments")
entry three: 0.001746519 (correlates to "geoip" / "geoip/geoip")

Copy link

Not sure why the ESLint rules didn't have indent already! Just added it. I noticed there was a lot of places with 2-spaces instead of 4.

@@ -788,6 +805,22 @@

if (e.serverTiming.length) {
Copy link

Choose a reason for hiding this comment

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

We should probably add a check for serverTiming's being defined first.

Copy link

One thing I'm not sure how to handle is breaking compatibility with the previous return values for things like getResourceTiming(), etc.

Should we add an optional parameter to getResourceTiming() to return in the new { restiming, servertiming} format?

Or should we make a semver change to 1.x and call it a breaking change?

@@ -746,6 +754,57 @@
return o;

* @param {array} lookup server timing entries lookup
Copy link

Choose a reason for hiding this comment

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

Short description too? And for decompressServerTiming

* @param {string} prefix URL prefix for the current node
* @returns {ResourceTiming[]} ResourceTiming array
ResourceTimingDecompression.decompressResources = function(rt, prefix) {
ResourceTimingDecompression.decompressResources = function(rt, st, prefix) {
Copy link

Choose a reason for hiding this comment

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

Would prefer to add new parameters as the last one, in case anyone is using the existing decompressResources API.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I believe that prefix is only passed in from the recursive call, but it's up to you.

Copy link

One more thing, can you add a section to the README describing ServerTiming support and briefly how it's compressed? (something similar to this PR description is great)

Copy link
Contributor Author

cvazac commented Aug 23, 2017

if you don't want to make it as a breaking change, you could pass in an optional out param to getResourceTiming. getResourceTiming will still only return the rt-data. if out is supplied, we can stick servertiming lookup on it

@nicjansma nicjansma changed the title compressed server timing Compressed ServerTiming Aug 29, 2017
Copy link

After looking at publicly published packages depending on this one (zero), I'm OK with breaking the return value at this point. I'll bump the semver.

@nicjansma nicjansma merged commit fbdb291 into nicjansma:master Aug 30, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
None yet
None yet

Successfully merging this pull request may close these issues.

None yet

2 participants