Skip to content
File

Blob: src/workerd/api/performance.h

cpp636 lines
1// Copyright (c) 2017-2022 Cloudflare, Inc.
2// Licensed under the Apache 2.0 license found in the LICENSE file or at:
3// https://opensource.org/licenses/Apache-2.0
4 
5#pragma once
6 
7#include <workerd/api/basics.h>
8#include <workerd/io/compatibility-date.capnp.h>
9#include <workerd/jsg/jsg.h>
10 
11namespace workerd {
12class IsolateLimitEnforcer;
13};
14 
15namespace workerd::api {
16 
17// ======================================================================================
18// Performance API
19// ======================================================================================
20//
21// This implementation provides a subset of the Performance API for compatibility with
22// other JavaScript runtimes. We are not intending to fully implement in-worker
23// performance-timing feedback as Cloudflare Workers run in a different context than
24// traditional browser or Node.js environments.
25//
26// The APIs here are primarily provided to support code portability and to prevent
27// runtime errors when code expects these standard APIs to exist.
28//
29// Specifications:
30// - W3C Performance Timeline: https://w3c.github.io/performance-timeline/
31// - W3C User Timing: https://w3c.github.io/user-timing/
32// - MDN Documentation: https://developer.mozilla.org/en-US/docs/Web/API/Performance_API
33//
34// Current limitations:
35// - No actual performance metrics collection within workers
36// - PerformanceObserver is provided but with minimal functionality
37// - Most entry types are not supported
38// - Timing data may not reflect actual worker execution characteristics
39 
40class PerformanceEntry: public jsg::Object {
41 public:
42 PerformanceEntry(
43 kj::String name, kj::LiteralStringConst entryType, double startTime, double duration)
44 : name(kj::mv(name)),
45 entryType(kj::mv(entryType)),
46 startTime(startTime),
47 duration(duration) {}
48 
49 kj::StringPtr getName() {
50 return name;
51 };
52 kj::StringPtr getEntryType() {
53 return entryType;
54 };
55 double getStartTime() {
56 return startTime;
57 };
58 double getDuration() {
59 return duration;
60 };
61 
62 jsg::JsObject toJSON(jsg::Lock& js);
63 
64 JSG_RESOURCE_TYPE(PerformanceEntry) {
65 JSG_READONLY_PROTOTYPE_PROPERTY(name, getName);
66 JSG_READONLY_PROTOTYPE_PROPERTY(entryType, getEntryType);
67 JSG_READONLY_PROTOTYPE_PROPERTY(startTime, getStartTime);
68 JSG_READONLY_PROTOTYPE_PROPERTY(duration, getDuration);
69 JSG_METHOD(toJSON);
70 
71 JSG_TS_OVERRIDE({
72 toJSON(): object;
73 });
74 }
75 
76 protected:
77 kj::String name;
78 kj::LiteralStringConst entryType;
79 double startTime;
80 double duration;
81};
82 
83class PerformanceMark: public PerformanceEntry {
84 public:
85 friend class Performance;
86 
87 struct Options {
88 jsg::Optional<jsg::JsRef<jsg::JsObject>> detail;
89 jsg::Optional<double> startTime;
90 
91 JSG_STRUCT(detail, startTime);
92 };
93 
94 PerformanceMark(
95 kj::String name, jsg::Optional<jsg::JsRef<jsg::JsObject>> detail, double startTime)
96 : PerformanceEntry(kj::mv(name), "mark"_kjc, startTime, 0),
97 detail(kj::mv(detail)) {}
98 
99 static jsg::Ref<PerformanceMark> constructor(
100 jsg::Lock& js, kj::String name, jsg::Optional<Options> maybeOptions);
101 
102 jsg::JsValue getDetail(jsg::Lock& js) {
103 KJ_IF_SOME(d, detail) {
104 return d.getHandle(js);
105 }
106 return js.null();
107 }
108 
109 jsg::JsObject toJSON(jsg::Lock& js);
110 
111 JSG_RESOURCE_TYPE(PerformanceMark) {
112 JSG_INHERIT(PerformanceEntry);
113 JSG_READONLY_PROTOTYPE_PROPERTY(detail, getDetail);
114 JSG_METHOD(toJSON);
115 
116 JSG_TS_OVERRIDE({
117 toJSON(): object;
118 });
119 }
120 
121 private:
122 jsg::Optional<jsg::JsRef<jsg::JsObject>> detail;
123};
124 
125// UvMetricsInfo represents libuv event loop metrics.
126// In workerd, this returns stub values since actual libuv metrics are not available.
127struct UvMetricsInfo {
128 double loopCount;
129 double events;
130 double eventsWaiting;
131 
132 JSG_STRUCT(loopCount, events, eventsWaiting);
133};
134 
135// PerformanceNodeTiming provides Node.js-specific timing information.
136// In workerd, this returns stub values since actual Node.js startup metrics are not applicable.
137// This class is only exposed when the Node.js perf_hooks compat flag is enabled.
138//
139// Spec: https://nodejs.org/api/perf_hooks.html#class-performancenodetiming
140class PerformanceNodeTiming: public PerformanceEntry {
141 public:
142 PerformanceNodeTiming(): PerformanceEntry(kj::str("node"), "node"_kjc, 0, 0) {}
143 
144 static jsg::Ref<PerformanceNodeTiming> constructor() = delete;
145 
146 // All timing values return 0 as stubs since Node.js startup metrics
147 // are not applicable in the Workers context.
148 double getNodeStart() {
149 return 0;
150 }
151 double getV8Start() {
152 return 0;
153 }
154 double getBootstrapComplete() {
155 return 0;
156 }
157 double getEnvironment() {
158 return 0;
159 }
160 double getLoopStart() {
161 return 0;
162 }
163 double getLoopExit() {
164 return 0;
165 }
166 double getIdleTime() {
167 return 0;
168 }
169 
170 // uvMetricsInfo returns libuv event loop metrics.
171 // In workerd, this returns stub values since actual libuv metrics are not available.
172 // Spec: https://nodejs.org/api/perf_hooks.html#performancenodetiminguvmetricsinfo
173 UvMetricsInfo getUvMetricsInfo(jsg::Lock& js) {
174 return UvMetricsInfo{
175 .loopCount = 0,
176 .events = 0,
177 .eventsWaiting = 0,
178 };
179 }
180 
181 jsg::JsObject toJSON(jsg::Lock& js);
182 
183 // Node.js exposes these as instance properties (own properties on the object),
184 // not prototype properties. This matches Node.js behavior where:
185 // Reflect.ownKeys(performance.nodeTiming) includes all these properties
186 // Reflect.ownKeys(performance.nodeTiming.__proto__) only has constructor, toJSON
187 JSG_RESOURCE_TYPE(PerformanceNodeTiming) {
188 JSG_INHERIT(PerformanceEntry);
189 JSG_READONLY_INSTANCE_PROPERTY(nodeStart, getNodeStart);
190 JSG_READONLY_INSTANCE_PROPERTY(v8Start, getV8Start);
191 JSG_READONLY_INSTANCE_PROPERTY(bootstrapComplete, getBootstrapComplete);
192 JSG_READONLY_INSTANCE_PROPERTY(environment, getEnvironment);
193 JSG_READONLY_INSTANCE_PROPERTY(loopStart, getLoopStart);
194 JSG_READONLY_INSTANCE_PROPERTY(loopExit, getLoopExit);
195 JSG_READONLY_INSTANCE_PROPERTY(idleTime, getIdleTime);
196 JSG_READONLY_INSTANCE_PROPERTY(uvMetricsInfo, getUvMetricsInfo);
197 JSG_METHOD(toJSON);
198 
199 JSG_TS_OVERRIDE({
200 toJSON(): object;
201 });
202 }
203};
204 
205class PerformanceMeasure: public PerformanceEntry {
206 public:
207 PerformanceMeasure(kj::String name, double startTime, double duration)
208 : PerformanceEntry(kj::mv(name), "measure"_kjc, startTime, duration) {}
209 
210 friend class Performance;
211 
212 struct Entry {
213 kj::String entryType;
214 kj::String name;
215 kj::OneOf<kj::Date, double> startTime;
216 double duration;
217 jsg::Optional<jsg::JsRef<jsg::JsObject>> detail;
218 
219 JSG_STRUCT(entryType, name, startTime, duration, detail);
220 };
221 
222 struct Options {
223 jsg::Optional<jsg::JsRef<jsg::JsObject>> detail;
224 jsg::Optional<double> start;
225 jsg::Optional<double> duration;
226 jsg::Optional<double> end;
227 
228 JSG_STRUCT(detail, start, duration, end);
229 };
230 
231 jsg::JsValue getDetail(jsg::Lock& js) {
232 KJ_IF_SOME(d, detail) {
233 return d.getHandle(js);
234 }
235 return js.null();
236 }
237 
238 jsg::JsObject toJSON(jsg::Lock& js);
239 
240 JSG_RESOURCE_TYPE(PerformanceMeasure) {
241 JSG_INHERIT(PerformanceEntry);
242 JSG_READONLY_PROTOTYPE_PROPERTY(detail, getDetail);
243 JSG_METHOD(toJSON);
244 
245 JSG_TS_OVERRIDE({
246 toJSON(): object;
247 });
248 }
249 
250 private:
251 jsg::Optional<jsg::JsRef<jsg::JsObject>> detail;
252};
253 
254class PerformanceResourceTiming: public PerformanceEntry {
255 public:
256 PerformanceResourceTiming(kj::String name, double startTime, double duration)
257 : PerformanceEntry(kj::mv(name), "resource"_kjc, startTime, duration) {}
258 
259 uint32_t getConnectEnd() {
260 return 0;
261 }
262 uint32_t getConnectStart() {
263 return 0;
264 }
265 uint32_t getDecodedBodySize() {
266 return 0;
267 }
268 uint32_t getDomainLookupEnd() {
269 return 0;
270 }
271 uint32_t getDomainLookupStart() {
272 return 0;
273 }
274 uint32_t getEncodedBodySize() {
275 return 0;
276 }
277 uint32_t getFetchStart() {
278 return 0;
279 }
280 jsg::JsString getInitiatorType(jsg::Lock& js) {
281 return js.str();
282 }
283 jsg::JsString getNextHopProtocol(jsg::Lock& js) {
284 return js.str();
285 }
286 uint32_t getRedirectEnd() {
287 return 0;
288 }
289 uint32_t getRedirectStart() {
290 return 0;
291 }
292 uint32_t getRequestStart() {
293 return 0;
294 }
295 uint32_t getResponseEnd() {
296 return 0;
297 }
298 uint32_t getResponseStart() {
299 return 0;
300 }
301 uint32_t getResponseStatus() {
302 return 0;
303 }
304 jsg::Optional<uint32_t> getSecureConnectionStart() {
305 return kj::none;
306 }
307 uint32_t getTransferSize() {
308 return 0;
309 }
310 uint32_t getWorkerStart() {
311 return 0;
312 }
313 
314 jsg::JsObject toJSON(jsg::Lock& js);
315 
316 JSG_RESOURCE_TYPE(PerformanceResourceTiming) {
317 JSG_INHERIT(PerformanceEntry);
318 JSG_READONLY_PROTOTYPE_PROPERTY(connectEnd, getConnectEnd);
319 JSG_READONLY_PROTOTYPE_PROPERTY(connectStart, getConnectStart);
320 JSG_READONLY_PROTOTYPE_PROPERTY(decodedBodySize, getDecodedBodySize);
321 JSG_READONLY_PROTOTYPE_PROPERTY(domainLookupEnd, getDomainLookupEnd);
322 JSG_READONLY_PROTOTYPE_PROPERTY(domainLookupStart, getDomainLookupStart);
323 JSG_READONLY_PROTOTYPE_PROPERTY(encodedBodySize, getEncodedBodySize);
324 JSG_READONLY_PROTOTYPE_PROPERTY(fetchStart, getFetchStart);
325 JSG_READONLY_PROTOTYPE_PROPERTY(initiatorType, getInitiatorType);
326 JSG_READONLY_PROTOTYPE_PROPERTY(nextHopProtocol, getNextHopProtocol);
327 JSG_READONLY_PROTOTYPE_PROPERTY(redirectEnd, getRedirectEnd);
328 JSG_READONLY_PROTOTYPE_PROPERTY(redirectStart, getRedirectStart);
329 JSG_READONLY_PROTOTYPE_PROPERTY(requestStart, getRequestStart);
330 JSG_READONLY_PROTOTYPE_PROPERTY(responseEnd, getResponseEnd);
331 JSG_READONLY_PROTOTYPE_PROPERTY(responseStart, getResponseStart);
332 JSG_READONLY_PROTOTYPE_PROPERTY(responseStatus, getResponseStatus);
333 JSG_READONLY_PROTOTYPE_PROPERTY(secureConnectionStart, getSecureConnectionStart);
334 JSG_READONLY_PROTOTYPE_PROPERTY(transferSize, getTransferSize);
335 JSG_READONLY_PROTOTYPE_PROPERTY(workerStart, getWorkerStart);
336 }
337};
338 
339class PerformanceObserverEntryList: public jsg::Object {
340 public:
341 kj::ArrayPtr<jsg::Ref<PerformanceEntry>> getEntries();
342 kj::ArrayPtr<jsg::Ref<PerformanceEntry>> getEntriesByType(kj::String type);
343 kj::ArrayPtr<jsg::Ref<PerformanceEntry>> getEntriesByName(
344 kj::String name, jsg::Optional<kj::String> type);
345 
346 void visitForGc(jsg::GcVisitor& visitor) {
347 // No managed objects to visit currently
348 }
349 
350 JSG_RESOURCE_TYPE(PerformanceObserverEntryList) {
351 JSG_METHOD(getEntries);
352 JSG_METHOD(getEntriesByType);
353 JSG_METHOD(getEntriesByName);
354 }
355};
356 
357// PerformanceObserver provides a way to observe performance timeline entries.
358// This is a minimal implementation for compatibility purposes.
359//
360// Spec: https://w3c.github.io/performance-timeline/#the-performanceobserver-interface
361// MDN: https://developer.mozilla.org/en-US/docs/Web/API/PerformanceObserver
362//
363// Note: In the Workers environment, this observer will not receive most performance
364// entries as we don't track detailed performance metrics within workers. The API
365// is provided mainly for compatibility with code that expects it to exist.
366class PerformanceObserver: public jsg::Object {
367 public:
368 struct CallbackOptions {
369 jsg::Optional<uint32_t> droppedEntriesCount;
370 JSG_STRUCT(droppedEntriesCount);
371 };
372 
373 using Callback = jsg::JsValue;
374 
375 static jsg::Ref<PerformanceObserver> constructor(jsg::Lock& js, Callback callback);
376 
377 PerformanceObserver(jsg::Lock& js, Callback callback): callback(callback.addRef(js)) {}
378 
379 struct ObserveOptions {
380 jsg::Optional<bool> buffered;
381 jsg::Optional<uint32_t> durationThreshold = 104;
382 jsg::Optional<kj::Array<kj::String>> entryTypes;
383 jsg::Optional<kj::String> type;
384 
385 JSG_STRUCT(buffered, durationThreshold, entryTypes, type);
386 };
387 void disconnect();
388 void observe(jsg::Optional<ObserveOptions> options);
389 kj::Array<jsg::Ref<PerformanceEntry>> takeRecords();
390 // Spec: https://w3c.github.io/performance-timeline/#supportedentrytypes-attribute
391 static kj::ArrayPtr<const kj::StringPtr> getSupportedEntryTypes();
392 
393 void visitForGc(jsg::GcVisitor& visitor) {
394 visitor.visit(callback);
395 }
396 
397 JSG_RESOURCE_TYPE(PerformanceObserver) {
398 JSG_METHOD(disconnect);
399 JSG_METHOD(observe);
400 JSG_METHOD(takeRecords);
401 JSG_STATIC_READONLY_PROPERTY_NAMED(supportedEntryTypes, getSupportedEntryTypes);
402 }
403 
404 private:
405 jsg::JsRef<jsg::JsValue> callback;
406 
407 static constexpr kj::FixedArray<kj::StringPtr, 2> supportedEntryTypes = []() consteval {
408 // We have mark and measure as supported because we implement relevant methods.
409 kj::FixedArray<kj::StringPtr, 2> out;
410 out[0] = "measure"_kj;
411 out[1] = "mark"_kj;
412 return kj::mv(out);
413 }();
414};
415 
416// EventCounts provides a read-only map of event counts per event type.
417// This is a minimal implementation for compatibility with the EventCounts API.
418//
419// Spec: https://w3c.github.io/event-timing/#eventcounts
420// MDN: https://developer.mozilla.org/en-US/docs/Web/API/EventCounts
421//
422// The EventCounts interface is a read-only map-like object where:
423// - Keys are event type strings (e.g., "click", "keydown")
424// - Values are the number of events dispatched for that type
425// - It doesn't have clear(), delete(), or set() methods
426class EventCounts: public jsg::Object {
427 public:
428 EventCounts() = default;
429 
430 jsg::Optional<uint32_t> get(kj::String eventType);
431 bool has(kj::String eventType);
432 uint32_t getSize();
433 
434 struct IteratorState {
435 jsg::Ref<EventCounts> parent;
436 size_t index = 0;
437 kj::Vector<kj::Tuple<kj::String, uint32_t>> entries;
438 
439 IteratorState(jsg::Ref<EventCounts> parent): parent(kj::mv(parent)) {
440 // Copy the entries from the map into our vector for stable iteration
441 // Check if the map has any entries before iterating
442 if (this->parent->eventCounts.size() > 0) {
443 for (auto& entry: this->parent->eventCounts) {
444 entries.add(kj::tuple(kj::str(entry.key), entry.value));
445 }
446 }
447 }
448 
449 void visitForGc(jsg::GcVisitor& visitor) {
450 visitor.visit(parent);
451 }
452 };
453 
454 using EntryIteratorType = kj::Array<kj::String>;
455 using KeyIteratorType = kj::String;
456 using ValueIteratorType = uint32_t;
457 
458 JSG_ITERATOR(EntryIterator, entries, EntryIteratorType, IteratorState, entryIteratorNext)
459 JSG_ITERATOR(KeyIterator, keys, KeyIteratorType, IteratorState, keyIteratorNext)
460 JSG_ITERATOR(ValueIterator, values, ValueIteratorType, IteratorState, valueIteratorNext)
461 
462 void forEach(jsg::Lock& js,
463 jsg::Function<void(uint32_t, kj::String, jsg::Ref<EventCounts>)>,
464 jsg::Optional<jsg::JsValue>);
465 
466 void visitForGc(jsg::GcVisitor& visitor) {
467 // No managed objects to visit currently
468 }
469 
470 JSG_RESOURCE_TYPE(EventCounts) {
471 JSG_READONLY_PROTOTYPE_PROPERTY(size, getSize);
472 JSG_METHOD(get);
473 JSG_METHOD(has);
474 JSG_METHOD(entries);
475 JSG_METHOD(keys);
476 JSG_METHOD(values);
477 JSG_METHOD(forEach);
478 JSG_ITERABLE(entries);
479 }
480 
481 private:
482 // Static iterator next methods
483 static kj::Maybe<EntryIteratorType> entryIteratorNext(jsg::Lock& js, IteratorState& state);
484 static kj::Maybe<KeyIteratorType> keyIteratorNext(jsg::Lock& js, IteratorState& state);
485 static kj::Maybe<ValueIteratorType> valueIteratorNext(jsg::Lock& js, IteratorState& state);
486 
487 // For now, we keep this empty as we don't actually track events in the worker context.
488 // This can be extended in the future to store actual event counts.
489 kj::HashMap<kj::String, uint32_t> eventCounts;
490 
491 friend struct IteratorState;
492};
493 
494// Performance provides timing-related functionality and performance metrics.
495// This is a minimal implementation focused on compatibility rather than providing
496// detailed performance insights within the Workers environment.
497//
498// Spec: https://w3c.github.io/hr-time/#the-performance-interface
499// MDN: https://developer.mozilla.org/en-US/docs/Web/API/Performance
500//
501// Key limitations in Workers:
502// - performance.now() returns the same precision as Date.now() for security reasons
503// - Most performance entry types are not supported
504// - Resource timing and navigation timing are not applicable in the Workers context
505// - User timing (marks and measures) have limited implementation
506class Performance: public EventTarget {
507 public:
508 static jsg::Ref<Performance> constructor() = delete;
509 
510 explicit Performance(const IsolateLimitEnforcer& isolateLimitEnforcer)
511 : isolateLimitEnforcer(isolateLimitEnforcer) {}
512 
513 // We always return a time origin of 0, making performance.now() equivalent to Date.now(). There
514 // is no other appropriate time origin to use given that the Worker platform is intended to be
515 // treated like one big computer rather than many individual instances. In particular, if and
516 // when we start snapshotting applications after startup and then starting instances from that
517 // snapshot, what would the right time origin be? The time when the snapshot was created? This
518 // seems to leak implementation details in a weird way.
519 //
520 // Note that the purpose of `timeOrigin` is normally to allow `now()` to return a more-precise
521 // measurement. Measuring against a recent time allows the values returned by `now()` to be
522 // smaller in magnitude, which alzlows them to be more precise due to the nature of floating
523 // point numbers. In our case, though, we don't return precise measurements from this interface
524 // anyway, for Spectre reasons -- it returns the same as Date.now().
525 double getTimeOrigin() {
526 return 0.0;
527 }
528 
529 jsg::Ref<EventCounts> getEventCounts(jsg::Lock& js);
530 
531 double now(jsg::Lock& js);
532 
533 void clearMarks(jsg::Optional<kj::String> name);
534 void clearMeasures(jsg::Optional<kj::String> name);
535 void clearResourceTimings();
536 kj::ArrayPtr<jsg::Ref<PerformanceEntry>> getEntries();
537 kj::Array<jsg::Ref<PerformanceEntry>> getEntriesByName(
538 kj::String name, jsg::Optional<kj::String> type);
539 kj::Array<jsg::Ref<PerformanceEntry>> getEntriesByType(kj::String type);
540 jsg::Ref<PerformanceMark> mark(
541 jsg::Lock& js, kj::String name, jsg::Optional<PerformanceMark::Options> options);
542 
543 // Following signatures are supported:
544 // - measure(measureName)
545 // - measure(measureName, startMark)
546 // - measure(measureName, startMark, endMark)
547 // - measure(measureName, measureOptions)
548 // - measure(measureName, measureOptions, endMark)
549 jsg::Ref<PerformanceMeasure> measure(jsg::Lock& js,
550 kj::String measureName,
551 jsg::Optional<kj::OneOf<PerformanceMeasure::Options, kj::String>> measureOptionsOrStartMark =
552 kj::none,
553 jsg::Optional<kj::String> maybeEndMark = kj::none);
554 
555 void setResourceTimingBufferSize(uint32_t size);
556 
557 jsg::JsObject toJSON(jsg::Lock& js);
558 
559 // Node.js-specific performance extensions.
560 // These are provided as stubs for compatibility with code that expects Node.js APIs.
561 
562 // EventLoopUtilization represents the utilization of the event loop.
563 // In workerd, we return stub values since actual event loop metrics are not available.
564 struct EventLoopUtilization {
565 double idle = 0;
566 double active = 0;
567 double utilization = 0;
568 
569 JSG_STRUCT(idle, active, utilization);
570 };
571 
572 EventLoopUtilization eventLoopUtilization();
573 
574 // Returns the PerformanceNodeTiming object containing Node.js-specific timing metrics.
575 // In workerd, this returns stub values since Node.js startup metrics are not applicable.
576 jsg::Ref<PerformanceNodeTiming> getNodeTiming(jsg::Lock& js);
577 
578 // In the browser, this function is not public. However, it must be used inside fetch
579 // which is a Node.js dependency, not an internal module.
580 // Returns void as a no-op stub since resource timing is not applicable in Workers.
581 void markResourceTiming();
582 jsg::Function<void()> timerify(jsg::Lock& js, jsg::Function<void()> fn);
583 
584 JSG_RESOURCE_TYPE(Performance, CompatibilityFlags::Reader flags) {
585 JSG_READONLY_PROTOTYPE_PROPERTY(timeOrigin, getTimeOrigin);
586 JSG_METHOD(now);
587 
588 // The following are provided as non-ops to ensure availability
589 // of the APIS but we are currently not planning to provide
590 // performance timing feedback within a worker using these
591 // apis.
592 if (flags.getEnableGlobalPerformanceClasses() || flags.getEnableNodeJsPerfHooksModule()) {
593 JSG_INHERIT(EventTarget);
594 JSG_READONLY_PROTOTYPE_PROPERTY(eventCounts, getEventCounts);
595 JSG_METHOD(clearMarks);
596 JSG_METHOD(clearMeasures);
597 JSG_METHOD(clearResourceTimings);
598 JSG_METHOD(getEntries);
599 JSG_METHOD(getEntriesByName);
600 JSG_METHOD(getEntriesByType);
601 JSG_METHOD(mark);
602 JSG_METHOD(measure);
603 JSG_METHOD(setResourceTimingBufferSize);
604 JSG_METHOD(toJSON);
605 }
606 
607 if (flags.getEnableNodeJsPerfHooksModule()) {
608 JSG_READONLY_PROTOTYPE_PROPERTY(nodeTiming, getNodeTiming);
609 JSG_METHOD(eventLoopUtilization);
610 JSG_METHOD(markResourceTiming);
611 JSG_METHOD(timerify);
612 }
613 
614 JSG_TS_OVERRIDE({
615 toJSON(): object;
616 });
617 }
618 
619 private:
620 const IsolateLimitEnforcer& isolateLimitEnforcer;
621 kj::Vector<jsg::Ref<PerformanceEntry>> entries;
622};
623 
624#define EW_PERFORMANCE_ISOLATE_TYPES \
625 api::Performance, api::Performance::EventLoopUtilization, api::PerformanceNodeTiming, \
626 api::UvMetricsInfo, api::PerformanceMark, api::PerformanceMeasure, \
627 api::PerformanceMark::Options, api::PerformanceMeasure::Options, \
628 api::PerformanceMeasure::Entry, api::PerformanceObserverEntryList, api::PerformanceEntry, \
629 api::PerformanceResourceTiming, api::PerformanceObserver, \
630 api::PerformanceObserver::ObserveOptions, api::PerformanceObserver::CallbackOptions, \
631 api::EventCounts, api::EventCounts::EntryIterator, api::EventCounts::EntryIterator::Next, \
632 api::EventCounts::KeyIterator, api::EventCounts::KeyIterator::Next, \
633 api::EventCounts::ValueIterator, api::EventCounts::ValueIterator::Next
634 
635} // namespace workerd::api