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 toserver
.readonly attribute DOMHighResTimeStamp startTime
- set tonil
or0
.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.