├── .nojekyll ├── .pr-preview.json ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE.md ├── PRIVACY_AND_SECURITY.md ├── README.md ├── doc ├── state-extensions-slides.pdf ├── tpac-2018-slides.pdf └── tpac-2021-slides.pdf ├── index.html ├── markers.md ├── perf.html.png └── w3c.json /.nojekyll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WICG/js-self-profiling/f7ba71f587976a9240cde8c486943e1d34c44140/.nojekyll -------------------------------------------------------------------------------- /.pr-preview.json: -------------------------------------------------------------------------------- 1 | { 2 | "src_file": "index.html", 3 | "type": "respec" 4 | } 5 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Code of Conduct 2 | 3 | All documentation, code and communication under this repository are covered by the [W3C Code of Ethics and Professional Conduct](https://www.w3.org/Consortium/cepc/). 4 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Web Platform Incubator Community Group 2 | 3 | This repository is being used for work in the Web Platform Incubator Community Group, governed by the [W3C Community License 4 | Agreement (CLA)](http://www.w3.org/community/about/agreements/cla/). To contribute, you must join 5 | the CG. 6 | 7 | If you are not the sole contributor to a contribution (pull request), please identify all 8 | contributors in the pull request's body or in subsequent comments. 9 | 10 | To add a contributor (other than yourself, that's automatic), mark them one per line as follows: 11 | 12 | ``` 13 | +@github_username 14 | ``` 15 | 16 | If you added a contributor by mistake, you can remove them in a comment with: 17 | 18 | ``` 19 | -@github_username 20 | ``` 21 | 22 | If you are making a pull request on behalf of someone else but you had no part in designing the 23 | feature, you can remove yourself with the above syntax. 24 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | All Reports in this Repository are licensed by Contributors under the 2 | [W3C Software and Document 3 | License](http://www.w3.org/Consortium/Legal/2015/copyright-software-and-document). Contributions to 4 | Specifications are made under the [W3C CLA](https://www.w3.org/community/about/agreements/cla/). 5 | -------------------------------------------------------------------------------- /PRIVACY_AND_SECURITY.md: -------------------------------------------------------------------------------- 1 | # Answers to [Security and Privacy Questionnaire](https://www.w3.org/TR/security-privacy-questionnaire/) 2 | 3 | ### 3.1 Does this specification deal with personally-identifiable information? 4 | 5 | No. 6 | 7 | 8 | ### 3.2 Does this specification deal with high-value data? 9 | 10 | No. 11 | 12 | 13 | ### 3.3 Does this specification introduce new state for an origin that persists across browsing sessions? 14 | 15 | No. 16 | 17 | 18 | ### 3.4 Does this specification expose persistent, cross-origin state to the web? 19 | 20 | No. 21 | 22 | 23 | ### 3.5 Does this specification expose any other data to an origin that it doesn’t currently have access to? 24 | 25 | No. The main concern here would be with cross-origin scripts, whose contents 26 | would not be visible to script ordinarily unless, they passed a CORS check. The 27 | spec therefore mandates such resources to pass a CORS check in order to be 28 | included in profiles. 29 | 30 | 31 | ### 3.6 Does this specification enable new script execution/loading mechanisms? 32 | 33 | No. 34 | 35 | 36 | ### 3.7 Does this specification allow an origin access to a user’s location? 37 | 38 | No. 39 | 40 | 41 | ### 3.8 Does this specification allow an origin access to sensors on a user’s device? 42 | 43 | No. 44 | 45 | 46 | ### 3.9 Does this specification allow an origin access to aspects of a user’s local computing environment? 47 | 48 | Not explicitly. However, the UA is free to select which sampling intervals it 49 | supports- conceivably, a UA could choose a sampling interval "optimal" for 50 | a device, such as the system clock interrupt interval. 51 | 52 | 53 | ### 3.10 Does this specification allow an origin access to other devices? 54 | 55 | No. 56 | 57 | 58 | ### 3.11 Does this specification allow an origin some measure of control over a user agent’s native UI? 59 | 60 | No. 61 | 62 | 63 | ### 3.12 Does this specification expose temporary identifiers to the web? 64 | 65 | No. 66 | 67 | 68 | ### 3.13 Does this specification distinguish between behavior in first-party and third-party contexts? 69 | 70 | No. 71 | 72 | 73 | ### 3.14 How should this specification work in the context of a user agent’s "incognito" mode? 74 | 75 | Semantics should be unchanged. 76 | 77 | 78 | ### 3.15 Does this specification persist data to a user’s local device? 79 | 80 | No. 81 | 82 | 83 | ### 3.16 Does this specification have a "Security Considerations" and "Privacy Considerations" section? 84 | 85 | Yes. 86 | 87 | 88 | ### 3.17 Does this specification allow downgrading default security characteristics? 89 | 90 | No. 91 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # JavaScript Self-Profiling API Proposal 2 | 3 | - [Specification](https://wicg.github.io/js-self-profiling) 4 | - [Web Platform Tests](https://wpt.fyi/results/js-self-profiling?label=experimental&label=master&aligned) 5 | - Slides and minutes from TPAC [2018](https://docs.google.com/document/d/1bYMLTkjcyOZR5Jt3vrulzMSoS32zOFtwyH33f6hW_C8/edit#heading=h.se3632b9q5z), [2019](https://docs.google.com/document/d/1-xMvUHAjqhQdegNqupxlqsLbfPHWq5MJ0iySg9Z1KBs/edit#heading=h.uq5au3okuh8b), [2020](https://docs.google.com/document/d/1inejuvPONXPOLKTCcUzOBhPh6QOckMcltnR-E3xyZVQ/edit#heading=h.9uskdhbxdwkg) 6 | - GitHub issues + [WICG discourse thread](https://discourse.wicg.io/t/proposal-an-api-to-allow-webpage-javascript-to-profile-its-own-performance/2818) 7 | 8 | ## Motivation 9 | 10 | Currently it is difficult for web developers to understand how their applications perform in the wide variety of conditions encountered on real user devices. A programmable JS profiling API is needed to collect JS profiles from real end-user environments. 11 | 12 | A native self-profiling API for JS code would also allow web developers to efficiently find hotspots in their JS code during page loads and user interactions, to assign CPU budgets to individual JS-implemented features on the page, to find unnecessary work being done on the client, and to find low-priority JS code executing in the background and wasting device power. 13 | 14 | Currently JS self-profiling can be accomplished by instrumenting individual JS functions with timing code but this is cumbersome, bloats JS size, changes the code (potentially altering performance characteristics), adds overhead from timing calls, and risks missing out on hotspots in unexpected corners. 15 | 16 | ### Facebook's Profiler Polyfill 17 | 18 | In an attempt to polyfill the missing self-profiling functionality, Facebook built and deployed its own in-page JS profiler implemented with JavaScript and SharedArrayBuffers. This JS profiler was implemented using a worker thread that signaled to the main thread when it needed to record its current stack. The worker thread would toggle a “capture stack now” flag in a SharedArrayBuffer every few milliseconds, and the value of this flag was read by instrumentation code that was inserted at transpilation time into the beginning of interesting JS functions running on the main thread. If the instrumentation code saw that the flag was set, it would capture the current JS stack (using the Error object) and add it to the running profile. 19 | 20 | This JS profiler was enabled for only a small percentage of Facebook users, and only instrumented functions of 10 statements or more in order to limit performance impact and to limit the quantity of profiling data collected. Nevertheless, we found it extremely valuable for understanding Facebook.com's performance in the field and for finding optimization opportunities. 21 | 22 | This polyfill implementation had some downsides: 23 | 24 | * The size overhead of the added instrumentation required limiting the fraction of functions instrumented (resulting in incomplete coverage) 25 | * The sampling “interrupt” was not instant so stacks were collected from the **_next_** instrumented function which added a lot of noise to the dataset and made it difficult to reason about 26 | * The performance overhead limited the sampling frequency and fraction of pageloads profiled 27 | * Our design depended on SharedArrayBuffers, which have been disabled on the Web for the time-being, so the profiler is disabled for now 28 | 29 | A browser-implemented profiling API would avoid these downsides. 30 | 31 | ### Wider Industry Interest 32 | 33 | It is cumbersome to manage instrumentation for performance measurement, regardless of whether it is inserted by build-time tooling (like Facebook's polyfill above) or inserted by hand in functions of interest. This API eliminates the need to maintain performance instrumentation and therefore allows smaller sites to deploy in-page JS profiling. 34 | 35 | We also expect that third-party analytics providers will offer libraries or infrastructure to record, ingest, aggregate and automatically analyze the collected profiles for optimization opportunities, thus further lowering the barrier to entry. 36 | 37 | Finally, several other Web properties with large codebases have expressed interest to us for using this API to better monitor their webapps performance in the field. 38 | 39 | ## API Overview 40 | 41 | Before developers can make use of the profiler, they'll first have to signal to the UA that they wish to profile by exposing the `Document-Policy: js-profiling` header. 42 | 43 | > This header ensures that any UA-specific profiling overhead is incurred only on loads that may profile. 44 | 45 | Developers will then be able to spin up a new `profiler` via `new Profiler(options)`, where `options` contains the following required fields: 46 | 47 | - `sampleInterval`: Target sample rate (in ms per sample) 48 | - The UA may choose a different sample rate than the one that the user requested (which must be the next lowest valid sampling interval). 49 | - The true sample rate of the profiler may be accessible via `profiler.sampleInterval`. 50 | - `maxBufferSize`: Maximum sample capacity (in samples) 51 | - If the sample buffer capacity is reached, the `samplebufferfull` event is sent to the `profiler` object. This stops profiling immediately. 52 | - The trace may still be collected via `profiler.stop()` when this occurs. 53 | 54 | Creating a new profiler starts profiling immediately. Once the developer wishes to stop profiling, calling `profiler.stop()` returns a promise containing a trace object that can be sent to a server for aggregation. 55 | 56 | > This trace is encoded in a trie format similar to the GeckoProfiler and Chrome tracing formats -- see the appendix for an overview of how stacks are represented. 57 | 58 | An example of how you might want to profile a pageload for server-side analysis is below: 59 | 60 | ```javascript 61 | const profiler = new Profiler({ 62 | sampleInterval: 10, // Target sampling every 10ms 63 | maxBufferSize: 10 * 100, // Cap at ~10s worth of samples 64 | }); 65 | 66 | async function collectAndSendTrace() { 67 | if (profiler.stopped) return; 68 | 69 | const trace = await profiler.stop(); 70 | const traceJson = JSON.stringify({ 71 | timing: performance.timing, 72 | trace, 73 | }); 74 | 75 | // Send the trace JSON to a server via Fetch/XHR 76 | sendTrace(traceJson); 77 | } 78 | 79 | profiler.addEventListener('samplebufferfull', collectAndSendTrace); 80 | window.addEventListener('load', collectAndSendTrace); 81 | 82 | // Rest of the page's JS initialization logic 83 | ``` 84 | 85 | ## Markers Extensions 86 | 87 | See [markers](markers.md) for detailed description of the proposal. 88 | 89 | ## Privacy and Security 90 | 91 | See the [Privacy and Security](https://wicg.github.io/js-self-profiling/#privacy-security) section of the spec. 92 | 93 | ## Appendix: Profile Format 94 | 95 | A trie-like approach is chosen for representing traces obtained from the profiler. There are examples of trie-based approaches in browsers today: 96 | 97 | * [Chrome's Trace Event format, specifically the stackFrames field](https://docs.google.com/document/d/1CvAClvFfyA5R-PhYUmn5OOQtYMH4h6I0nSsKchNAySU/preview#heading=h.yr703knxre9f) 98 | * [Firefox's Gecko Profiler format, specifically the stackTable field](https://github.com/devtools-html/perf.html/blob/master/docs-developer/gecko-profile-format.md#source-data-format) 99 | 100 | The API aims to provide deduplication of script resource URLs, stack frames, and stack sequences (through the aforementioned trie approach) to reduce memory pressure and trace size when sent over the network. 101 | 102 | The specification's processing model provides detail on how these traces are constructed. An example (encoded in JSON) can be found below: 103 | 104 | ```javascript 105 | { 106 | "resources" : [ 107 | "https://static.xx.fbcdn.net/rsrc.php/v3/yW/r/ZgaPtFDHPeq.js", 108 | "https://static.xx.fbcdn.net/rsrc.php/v3iMKu4/yW/l/en_US-i/gSq3sO3PcU1.js" 109 | ], 110 | "stacks" : [ 111 | { 112 | "frameId" : 0 113 | }, 114 | { 115 | "frameId" : 1, 116 | "parentId" : 0 117 | }, 118 | { 119 | "frameId" : 2, 120 | "parentId" : 1 121 | } 122 | ], 123 | "samples" : [ 124 | { 125 | "timestamp" : 1551.73499998637, 126 | "stackId": 2 127 | }, 128 | { 129 | "timestamp" : 1576.83999999426, 130 | "stackId": 1 131 | }, 132 | { 133 | "timestamp" : 1601.90499993041 134 | } 135 | ], 136 | "frames" : [ 137 | { 138 | "name" : "b", 139 | "resourceId" : 0, 140 | "line" : 23, 141 | "column" : 169 142 | }, 143 | { 144 | "name" : "l", 145 | "resourceId": 1, 146 | "line" : 313, 147 | "column" : 468 148 | }, 149 | { 150 | "name" : "a", 151 | "resourceId": 1, 152 | "line" : 313, 153 | "column" : 1325 154 | } 155 | ] 156 | } 157 | ``` 158 | 159 | The API may also be combined with other APIs such as [Compression Streams](https://wicg.github.io/compression/) in order to further reduce trace size. 160 | 161 | ### Visualization 162 | 163 | Mozilla's perf.html visualization tool for Firefox profiles or Chrome's trace-viewer (chrome://tracing) UI could be trivially adapted to visualize the data produced by this profiling API. 164 | 165 | ### perf.html 166 | 167 | As an illustration, a screenshot below from Mozilla's perf.html project shows the JS stack aggregation and timeline. It is able to show gaps where JavaScript was not executing, areas where there were long running events (red), and an aggregate view of the samples in the selected time range such as the 15 contiguous samples in function 'user.ts' highlighted in the screenshot below. 168 | 169 |  170 | 171 | -------------------------------------------------------------------------------- /doc/state-extensions-slides.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WICG/js-self-profiling/f7ba71f587976a9240cde8c486943e1d34c44140/doc/state-extensions-slides.pdf -------------------------------------------------------------------------------- /doc/tpac-2018-slides.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WICG/js-self-profiling/f7ba71f587976a9240cde8c486943e1d34c44140/doc/tpac-2018-slides.pdf -------------------------------------------------------------------------------- /doc/tpac-2021-slides.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WICG/js-self-profiling/f7ba71f587976a9240cde8c486943e1d34c44140/doc/tpac-2021-slides.pdf -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 | 5 |34 | This specification describes an API that allows web applications to control a sampling profiler for measuring client JavaScript execution times. 35 |
36 |42 | Complex web applications currently have limited visibility into where JS 43 | execution time is spent on clients. Without the ability to efficiently 44 | collect stack samples, applications are forced to instrument their code 45 | with profiling hooks that are imprecise and can significantly slow down 46 | execution. By providing an API to manipulate a sampling profiler, 47 | applications can gather rich execution data for aggregation and analysis 48 | with minimal overhead. 49 |
50 |The following example demonstrates how a user may profile an expensive operation, gathering JS execution samples every 10ms. The trace can be sent to a server for analysis to debug outliers and JS execution characteristics in aggregate.
53 |54 | const profiler = new Profiler({ sampleInterval: 10, maxBufferSize: 10000 }); 55 | const start = performance.now(); 56 | for (let i = 0; i < 1000000; i++) { 57 | doWork(); 58 | } 59 | const duration = performance.now() - start; 60 | const trace = await profiler.stop(); 61 | const traceJson = JSON.stringify({ 62 | duration, 63 | trace, 64 | }); 65 | sendTrace(traceJson); 66 |67 |
Another common real-world scenario is profiling JS across a pageload. This example profiles the onload event, sending performance timing data along with the trace.
68 |69 | const profiler = new Profiler({ sampleInterval: 10, maxBufferSize: 10000 }); 70 | 71 | window.addEventListener('load', async () => { 72 | const trace = await profiler.stop(); 73 | const traceJson = JSON.stringify({ 74 | timing: performance.timing, 75 | trace, 76 | }); 77 | sendTrace(traceJson); 78 | }); 79 | 80 | // Rest of the page's JS initialization logic 81 |82 |
89 | A sample is a descriptor of the 90 | instantaneous state of execution at a given point in time. Each sample is 91 | associated with a stack. 92 |
93 |94 | A stack is a list of frames that MUST be ordered 95 | sequentially from outermost to innermost frame. 96 |
97 |98 | A frame is an element in the context of a stack 99 | containing information about the current execution state. 100 |
101 |105 | A profiling session is an abstract producer of samples. Each session has: 106 |
107 |{started, paused, stopped}
.112 | The UA is NOT REQUIRED to take samples at this rate. However, it is 113 | RECOMMENDED that sampling is prioritized to take samples at this rate to 114 | produce higher quality traces. 115 |
116 |124 | Multiple profiling sessions on the same page SHOULD be supported. 125 |
126 |
129 | In the started
state, the UA SHOULD make a best-effort to
130 | capture samples by executing the take a sample algorithm [= in
131 | parallel =] each time the sample interval has elapsed.
132 | In the paused
and stopped
states, the UA SHOULD NOT capture samples.
133 |
135 | Profiling sessions MUST begin in the started
state.
136 |
138 | The UA MAY move a session from started
to paused
, and from paused
to started
.
139 |
141 | The user agent is RECOMMENDED to pause the sampling of a profiling session if the browsing context is not in the foreground. 142 |
143 |
144 | A stopped
session MUST NOT move to the started
or paused
states.
145 |
151 | To take a sample given a profiling session, perform the following steps: 152 |
153 |stopped
, and return.162 | To get a stack ID given an execution context stack bound to stack, perform the following steps: 163 |
undefined
.undefined
, return parentId.174 | To get a frame ID given an execution context bound to context, perform the following steps: 175 |
undefined
.ScriptOrModule
associated with context.ScriptOrModule
containing the function that invoked |instance|.
184 |
185 | The purpose of the above logic is to ensure that built-in functions invoked by inaccessible scripts are not exposed in traces, by using the ScriptOrModule
that invoked them for attribution.
186 |
188 | "[...] the ScriptOrModule
containing the function that invoked |instance|" should be defined more rigorously. We could leverage the top-most execution context on the stack that defines a ScriptOrModule
to provide this, but it's not ideal -- there may (theoretically) be other mechanisms for a builtin to be enqueued on the execution context stack, in which case the attribution would be invalid.
189 |
undefined
.true
, return undefined
.
198 | 199 | This check ensures that we avoid including stack frames from cross-origin scripts served in a CORS-cross-origin response. We may want to consider renaming muted errors to better reflect this use case. 200 |
201 |
217 | To get an element ID for an item in a list, run the following steps: 218 |
228 | [Exposed=Window] 229 | interface Profiler : EventTarget { 230 | readonly attribute DOMHighResTimeStamp sampleInterval; 231 | readonly attribute boolean stopped; 232 | 233 | constructor(ProfilerInitOptions options); 234 | Promise<ProfilerTrace> stop(); 235 | }; 236 |237 |
Each Profiler MUST be associated with exactly one profiling session.
238 |The sampleInterval attribute MUST reflect the sample interval of the associated profiling session expressed as a DOMHighResTimeStamp.
239 |The stopped attribute MUST be true if and only if the profiling session has state stopped
.
241 | {{Profiler}} is only exposed on {{Window}} until consensus is reached on [[Permissions-Policy]] and {{Worker}} integration. 242 |
243 |RangeError
."js-profiling"
in the Document. If the result is false, throw a "NotAllowedError"
DOMException.«[{{ProfilerTrace/resources}} → «», {{ProfilerTrace/frames}} → «», {{ProfilerTrace/stacks}} → «», {{ProfilerTrace/samples}} → «»]»
.265 | Stops the profiler and returns a trace. This method MUST run these steps: 266 |
267 |stopped
, return [= a promise rejected with =] an "InvalidStateError"
DOMException.
269 | stopped
.281 | Any samples taken after stop() is invoked SHOULD NOT be included by the profiling session. 282 |
283 |288 | typedef DOMString ProfilerResource; 289 | 290 | dictionary ProfilerTrace { 291 | required sequence<ProfilerResource> resources; 292 | required sequence<ProfilerFrame> frames; 293 | required sequence<ProfilerStack> stacks; 294 | required sequence<ProfilerSample> samples; 295 | }; 296 |297 |
The resources attribute MUST return the ProfilerResource list set by the take a sample algorithm.
298 | 299 |The frames attribute MUST return the ProfilerFrame list set by the take a sample algorithm.
300 |The stacks attribute MUST return the ProfilerStack list set by the take a sample algorithm.
301 |The samples attribute MUST return the ProfilerSample list set by the take a sample algorithm.
302 |303 | Inspired by the V8 trace event format 304 | and Gecko profile format, 305 | this representation is designed to be easily and efficiently serializable. 306 |
307 |310 | dictionary ProfilerSample { 311 | required DOMHighResTimeStamp timestamp; 312 | unsigned long long stackId; 313 | }; 314 |315 |
timestamp MUST return the value it was initialized to.
316 |stackId MUST return the value it was initialized to.
317 |321 | dictionary ProfilerStack { 322 | unsigned long long parentId; 323 | required unsigned long long frameId; 324 | }; 325 |326 |
parentId MUST return the value it was initialized to.
327 |frameId MUST return the value it was iniitalized to.
328 |332 | dictionary ProfilerFrame { 333 | required DOMString name; 334 | unsigned long long resourceId; 335 | unsigned long long line; 336 | unsigned long long column; 337 | }; 338 |339 |
name MUST return the value it was initialized to.
340 |resourceId MUST return the value it was initialized to.
341 |line MUST return the value it was initialized to.
342 |column MUST return the value it was initialized to.
343 |348 | dictionary ProfilerInitOptions { 349 | required DOMHighResTimeStamp sampleInterval; 350 | required unsigned long maxBufferSize; 351 | }; 352 |353 |
ProfilerInitOptions MUST support the following fields:
354 |
362 | This spec defines a configuration point in Document Policy with name js-profiling
. Its type is boolean
with default value false
.
363 |
365 | Document policy is leveraged to give UAs the ability to avoid storing
366 | required metadata for profiling when the document does not explicitly
367 | request it. While this metadata could conceivably be generated in
368 | response to a profiler being started, we store this bit on the document
369 | in order to signal to the engine as early as possible (as profiling early
370 | in page load is a common use case). This overhead may be non-trivial
371 | depending on the implementation, and therefore we default to
372 | false
.
373 |
378 | For the purposes of user-agent automation and application testing, this document defines the following [[WebDriver]] extension command. 379 |
380 |HTTP Method | 386 |URI Template | 387 |
---|---|
POST | 392 |`/session/{session id}/forcesample` | 393 |
397 | The Force Sample extension command forces all [=profiling sessions=] to [=take a sample=] for the purpose of enabling more deterministic testing. 398 |
399 |400 | The remote end steps are: 401 |
started
, [=take a sample=] with |session|.null
.The following sections detail some of the privacy and security choices of the API, illustrating protection strategies against various types of attacks.
417 |
420 | The API avoids exposing contents of cross-origin scripts by requiring all functions included via the take a sample algorithm to be defined in a script served with CORS-same-origin through the muted errors property. Browser builtins (such as performance.now()
) must also only be included when invoked from [= CORS-same-origin =] script.
421 |
423 | As a result, the API does not expose any new insight into the contents or execution characteristics of cross-origin script, beyond what is already possible through manual instrumentation. UAs are encouraged to verify this holds if they choose to support extremely low sample interval values (e.g. less than one millisecond). 424 |
425 |
429 | Cross-origin execution contexts should not be observable by the API through the realm check in the take a sample algorithm. Cross-origin iframes
and other execution contexts that share an agent with a profiler will therefore not have their execution observable through this API.
430 |
435 | Timing attacks remain a concern for any API that could introduce a new source of high-resolution timing information. Timestamps gathered in traces should be obtained from the same source as [[?HR-Time]]'s current high resolution time to avoid exposing a new vector for side-channel attacks. 436 |
437 | See [[?HR-Time]]'s discussion on clock resolution. 438 |
439 |