-
Notifications
You must be signed in to change notification settings - Fork 130
Description
Context
Common web performance metric and auditing tools (e.g. Lighthouse, PageSpeed Insights, WebPageTest) only focus on client-side performance in detail. Server-side performance gets reduced to a single metric (TTFB), simply because these tools cannot look "behind the scenes". This means we have no clear way to figure out how e.g. a feature in the Performance Lab plugin affects server-side performance in the lab or in the field.
The Server-Timing header is a standardized way to expose server-side metrics to the client-side. This way, performance tools can use and evaluate such data, which was previously hidden from them. Of course the server has to somehow measure and expose the results though, and that is what this issue is about.
Proposal
The Performance Lab plugin should come with a PHP API to centrally control the Server-Timing header which, most importantly, allows developers to pass identifiers for a metric and their values to the API, with the API then managing the header output.
This API should be part of the plugin infrastructure, i.e. not a module. The reason for that is that this API should be usable by any module to measure certain aspects of its performance impact, which would not be reliable if it was a module. Another reason to not make the API a module is that modules should come with functionality on their own, which would not be the case for this API. Last but not least, unlike the purpose of modules, this API should not be proposed for inclusion in WordPress core (at least not in the near term) - its main purpose is to allow us to gather server-side metrics in the lab and in the field, which we have not been able to so far.
Defaults
Primarily, individual modules of the plugin should use the API to measure specific parts of their execution relevant to the feature they implement, in order to see how they affect PHP performance. However, a single default is worth including, which is the overall WordPress execution time, which WordPress core already tracks itself using its timer_start() function.
High-level spec
- Class
Perflab_Server_Timing
:register_metric( string $metric_slug, callable $measure_callback, string|callable $access )
: Registers a metric and its measuring callback, to be added to the list of metrics. The measuring callback will only be executed if the access is satisfied by the current request.- Potentially for a more flexible API the signature of this method should use
array $args
as second parameter, but the exact parameters are outlined above for clarity.
- Potentially for a more flexible API the signature of this method should use
get_header_value() : string
: Returns the full Server-Timing header value, based on all registered metrics which have a value set.add_header()
: Adds the Server-Timing header, usingget_header_value()
.
- Function
perflab_server_timing()
: Initializes the main instance of thePerflab_Server_Timing
class and fires an action hook for any extension to integrate, passing the instance to the action as a parameter. - Function
perflab_wrap_server_timing( callable $callback, string $metric_slug, string|callable $access ) : callable
: Wraps a callback (e.g. of anadd_action()
oradd_filter()
call) into this function, which usesPerflab_Server_timing::register_metric()
internally to simply measure execution time of the$callback
function and add it to the Server-Timing header value.- This little utility will simplify usage of the API around hook callbacks and is inspired by this article.
Quality attributes (performance, privacy, security, accessibility)
- Header length: While it is perfectly acceptable to include various metrics and values in the Server-Timing header, it should not become too long in order to minimize the HTTP overhead. For that reason, the API should include validation to ensure the metric names are kept short and concise (exact character limit per metric TBD), and it should furthermore limit the overall number of metrics that can be included in the header as well.
- Timing overhead: While measuring time in PHP is generally considered harmless, an excessive number of timers may cause a performance regression. For example, WordPress core conditionally measures the time every individual database request takes, though it does so only conditionally if the
SAVEQUERIES
flag is set. Note that this has some overlap with the header length consideration above and will potentially already be satisfied by the solution for that. - Sensitive values: The values for each metric should be numeric, e.g. integers or floats. However, since the Server-Timing header is technically a string, any other value could also be rendered, which opens room for abuse, where code in the WordPress site could leak sensitive information as part of that value. To avoid that, the API should require all timing values to be numeric.
- Sensitive metrics: There are certain metrics which a site may want to measure but keep internal. For this purpose, the API should require for each metric to be registered with a certain access level definition, so that not every metric is public. This could either be a WordPress capability check or a shorthand such as “public” or “admin”.