Skip to content

Instantly share code, notes, and snippets.

@igrigorik
Last active April 29, 2023 15:04
Show Gist options
  • Star 16 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save igrigorik/97dfe5ea9b4a85162e25 to your computer and use it in GitHub Desktop.
Save igrigorik/97dfe5ea9b4a85162e25 to your computer and use it in GitHub Desktop.
Mechanism to communicate server timing data to the client (Server Timing)

Navigation and Resource Timing provides timing data for the fetch, but currently there is no interoperable way for the server to communicate own timing information to the client. For example:

  • What steps were taken to generate the resource, and how long each took. Many sites already embed this type of information via HTML comments - e.g. wordpress emits <!--Page generated in X.X seconds.--> , and many sites provide more detailed stats (cache, db, generation) to enable performance debugging.
  • If proxied, where was the time spent - e.g. time to fetch from origin, time to process response, etc.

Instead of relying on arbitrary HTML comments, we can define an HTTP header that can be used to send key-value pairs in a well defined format. Making this data available via a well defined interface would...

  • Allow UA and other developer tools to automatically annotate appropriate timelines.
  • Allow analytics vendors to gather this data for operational analysis.
  • Allows proxies and CDNs to append custom timing data without modifying the response, to provide better visibility into cache/proxy/CDN performance.

For example, given the following response...

HTTP/1.1 200 OK
Content-Type: text/html; charset=utf-8
Cache-Control: max-age=360, public
Transfer-Encoding: chunked
Server-Timing: db=150; cache=22; render=45.2

The database time was 150ms, cache lookups took 22ms, and render time was 45.2ms. Combined with NT/RT timing data, this provides a significant improvement in telemetry for the generated response.

Note...

  • UA and other tools should support and process HTTP trailers to allow the server to append the timing information at the end of the response, to avoid unnecessary buffering, etc.
  • The data format is kept intentionally simple and flat; we want to encourage better perf visibility, but we also don't want to incur huge overhead in HTTP headers.
  • The server is in full control of what data it returns and to whom - i.e. data may be provided to auth'ed users only, omitted entirely if under load, etc.

Rough proposal... commence <hand waving>

Server-Timing header field is used to communicate a set of comma separated field-values:

  • order of field-values is not significant
  • each field-value contains a server-defined mark name and duration value
  • duration values are floats and report processing time in milliseconds
  • if duplicate mark names are provided (e.g. a=1,b=2,a=3), last one wins (i.e. a=3).

Given above structure, the UA can automatically parse and annotate relevant timelines. For example:

  • We can extend PerformanceNavigationTiming and PerformanceResourceTiming interfaces.
    • readonly attribute Array serverEntries, or some such...
  • Above attribute would contain an array of ServerEntry entries.
    • interface ServerEntry : PerformanceEntry {}; (PE)
      • readonly attribute DOMString name - initialized to server specified metric name.
      • readonly attribute DOMString entryType - set to server.
      • readonly attribute DOMHighResTimeStamp startTime - set to nil or 0.
      • readonly attribute DOMHighResTimeStamp duration - set to server specified duration.

For Navigation Timing, you could then access this data via:

window.performance.timing.serverEntries.forEach(function(entry) { 
  // process entry.name, entry.duration...
});

</hand waving>


Additional thoughts and considerations...

  • At TPAC we discussed this idea in the context of "automatically initialized user marks", but treating these entries as such runs into a problem of naming collisions and attribution - e.g. multiple resources trying to report "db" time. Instead, attaching these marks to each resource (and navigation), allows each resource to carry its own information without collisions, and it avoids polluting the user timeline.
  • Could/should this stand as its own spec that extends Nav Timing and Resource Timing? Server Timing? This would allow us to avoid replicating language in both places.
@leeight
Copy link

leeight commented Nov 8, 2014

+1

@karlcow
Copy link

karlcow commented Nov 8, 2014

Interesting proposal in terms of geekiness.
What I would like to better understand is the set of practical applications it would allow, or the set of issues it would solve. Could you list those I guess it would help.

@eliperelman
Copy link

I really like this proposal! I do feel like the startTime property would be more useful though if we could set a non-zero value to it, understanding that it would be up to user-land code to ensure its validity. I don't believe that measures are the only useful data to pass. So maybe having Server Timing marks and measures in separate headers would be useful, just throwing ideas out there.

Use case: On Firefox OS, it would be valuable to specify in this header when the user initiated to open an app (these are all web-based). So in the homescreen, we could specify in the header that at a certain timestamp the user tapped on an icon. Drawback: not sure of the implications of introducing timestamps or possible negative values into the timeline of an application, but that is something we could discuss.

@mnot
Copy link

mnot commented Nov 8, 2014

+1

@yaelb
Copy link

yaelb commented Nov 9, 2014

+1

@bizzbyster
Copy link

+1

@igrigorik
Copy link
Author

@karlcow a few use cases...

  • Allow UA and other developer tools to automatically annotate appropriate timelines.
    • Instead of simply seeing "response took 1400ms", DevTools could surface additional markers to indicate where time was spent - e.g. database: 800ms, rendering: 200ms, queuing: 400ms, etc. Many frameworks and applications already implement this sort of logic in ad-hoc manner, which requires extra javascript and other hacks - e.g. see GitHub's solution. Providing a standard interface would allow UAs to surface this data in devtools and other places.
  • Allow analytics vendors to gather this data for operational analysis.
    • Once there is a standard interface, analytics / ops vendors can start auto-gather and surface this data to their customers. Right now, this is possible, but requires custom instrumentation on at least one side.
  • Allows proxies and CDNs to append custom timing data without modifying the response, to provide better visibility into cache/proxy/CDN performance - e.g. time-to-origin: 400ms, data-center: 23 (fastly, akamai)

... I'm sure there is more, but those are the highlights.

@64BitAsura
Copy link

But if this information available publicly, exposing what happening in server for a request. Which may be cause security threat for some use cases.

@igrigorik
Copy link
Author

@sambathl "The server is in full control of what data it returns and to whom - i.e. data may be provided to auth'ed users only, omitted entirely if under load, etc."

@nikmd23
Copy link

nikmd23 commented Nov 19, 2014

This is a tough problem to solve.

My open source project (Glimpse) started over three years ago with something very similar to what you are proposing here. Simple data keys containing server side performance metrics were stored in a special header and a client would render that information in the browser.

Duration information alone didn't paint a very compelling/useful picture. We quickly needed to break apart the "data access duration" into individual queries. Then we needed to add startTimes to each query so we could figure out which went first. (That's just for the db section.) Then we started running into browser errors because the header fields became too large. 😦

We've since moved to a different delivery mechanism. We have a header that points to a URI which returns a JSON description of the server side performance (plus other things that aren't relevant here). This works nicely since we don't have to worry about header size issues, and keeps a user's HTTP response small. In debugging scenarios the dev tools makes a follow up request to get server side metrics. The additional request is certainly the biggest downside here.

All that said I propose that instead of a standardized header, you focus on a standard JSON based mime type, which would allow a much richer description of server side activities.

I'm more that happy to walk you through the challenges the Glimpse project has had, as well as provide insight into what server side data our thousands of users request.

@igrigorik
Copy link
Author

For those that want to follow along, see: http://lists.w3.org/Archives/Public/public-web-perf/2014Nov/0029.html

@nikmd all of what you said mimics the Speed Tracer [1] experience, which provided similar implementation. However, going down that path adds a huge amount of unnecessary complexity for the use cases we're trying to address (see rough draft above). In fact, an out of band request doesn't address some of them - e.g. proxy annotations. I think detailed server-side reports are out-of-scope, and our goal here is to expose simple insights, which might then lead you to use much heavier tools to investigate further.

[1] https://developers.google.com/web-toolkit/speedtracer/

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