diff --git a/packages/react-native/ReactCommon/cxxreact/JSExecutor.cpp b/packages/react-native/ReactCommon/cxxreact/JSExecutor.cpp index eeca4b3c929..ef6a44c0f12 100644 --- a/packages/react-native/ReactCommon/cxxreact/JSExecutor.cpp +++ b/packages/react-native/ReactCommon/cxxreact/JSExecutor.cpp @@ -10,10 +10,8 @@ #include "RAMBundleRegistry.h" #include -#include #include -#include namespace facebook::react { @@ -29,8 +27,8 @@ std::string JSExecutor::getSyntheticBundlePath( return buffer.data(); } -double JSExecutor::performanceNow() { - return chronoToDOMHighResTimeStamp(std::chrono::steady_clock::now()); +HighResTimeStamp JSExecutor::performanceNow() { + return HighResTimeStamp::now(); } jsinspector_modern::RuntimeTargetDelegate& diff --git a/packages/react-native/ReactCommon/cxxreact/JSExecutor.h b/packages/react-native/ReactCommon/cxxreact/JSExecutor.h index 469f4ca6fd7..775e3971f58 100644 --- a/packages/react-native/ReactCommon/cxxreact/JSExecutor.h +++ b/packages/react-native/ReactCommon/cxxreact/JSExecutor.h @@ -14,6 +14,7 @@ #include #include #include +#include #ifndef RN_EXPORT #define RN_EXPORT __attribute__((visibility("default"))) @@ -138,7 +139,7 @@ class RN_EXPORT JSExecutor { uint32_t bundleId, const std::string& bundlePath); - static double performanceNow(); + static HighResTimeStamp performanceNow(); /** * Get a reference to the \c RuntimeTargetDelegate owned (or implemented) by diff --git a/packages/react-native/ReactCommon/jsiexecutor/jsireact/JSIExecutor.cpp b/packages/react-native/ReactCommon/jsiexecutor/jsireact/JSIExecutor.cpp index 6b226006768..39be0f0f055 100644 --- a/packages/react-native/ReactCommon/jsiexecutor/jsireact/JSIExecutor.cpp +++ b/packages/react-native/ReactCommon/jsiexecutor/jsireact/JSIExecutor.cpp @@ -556,7 +556,9 @@ void bindNativePerformanceNow(Runtime& runtime) { [](jsi::Runtime& runtime, const jsi::Value&, const jsi::Value* args, - size_t count) { return Value(JSExecutor::performanceNow()); })); + size_t /*count*/) { + return JSExecutor::performanceNow().toDOMHighResTimeStamp(); + })); } } // namespace facebook::react diff --git a/packages/react-native/ReactCommon/jsinspector-modern/network/NetworkReporter.cpp b/packages/react-native/ReactCommon/jsinspector-modern/network/NetworkReporter.cpp index 1eb6e19f20f..9f207a0a236 100644 --- a/packages/react-native/ReactCommon/jsinspector-modern/network/NetworkReporter.cpp +++ b/packages/react-native/ReactCommon/jsinspector-modern/network/NetworkReporter.cpp @@ -78,7 +78,7 @@ void NetworkReporter::reportRequestStart( int encodedDataLength, const std::optional& redirectResponse) { if (ReactNativeFeatureFlags::enableResourceTimingAPI()) { - double now = PerformanceEntryReporter::getInstance()->getCurrentTimeStamp(); + auto now = PerformanceEntryReporter::getInstance()->getCurrentTimeStamp(); // All builds: Annotate PerformanceResourceTiming metadata { @@ -127,7 +127,7 @@ void NetworkReporter::reportRequestStart( void NetworkReporter::reportConnectionTiming(const std::string& requestId) { if (ReactNativeFeatureFlags::enableResourceTimingAPI()) { - double now = PerformanceEntryReporter::getInstance()->getCurrentTimeStamp(); + auto now = PerformanceEntryReporter::getInstance()->getCurrentTimeStamp(); // All builds: Annotate PerformanceResourceTiming metadata { @@ -168,7 +168,7 @@ void NetworkReporter::reportResponseStart( const ResponseInfo& responseInfo, int encodedDataLength) { if (ReactNativeFeatureFlags::enableResourceTimingAPI()) { - double now = PerformanceEntryReporter::getInstance()->getCurrentTimeStamp(); + auto now = PerformanceEntryReporter::getInstance()->getCurrentTimeStamp(); // All builds: Annotate PerformanceResourceTiming metadata { @@ -205,7 +205,7 @@ void NetworkReporter::reportResponseStart( void NetworkReporter::reportDataReceived(const std::string& requestId) { if (ReactNativeFeatureFlags::enableResourceTimingAPI()) { - double now = PerformanceEntryReporter::getInstance()->getCurrentTimeStamp(); + auto now = PerformanceEntryReporter::getInstance()->getCurrentTimeStamp(); // All builds: Annotate PerformanceResourceTiming metadata { @@ -233,7 +233,7 @@ void NetworkReporter::reportResponseEnd( const std::string& requestId, int encodedDataLength) { if (ReactNativeFeatureFlags::enableResourceTimingAPI()) { - double now = PerformanceEntryReporter::getInstance()->getCurrentTimeStamp(); + auto now = PerformanceEntryReporter::getInstance()->getCurrentTimeStamp(); // All builds: Report PerformanceResourceTiming event { diff --git a/packages/react-native/ReactCommon/jsinspector-modern/network/NetworkReporter.h b/packages/react-native/ReactCommon/jsinspector-modern/network/NetworkReporter.h index 4227deca3df..90701c412bf 100644 --- a/packages/react-native/ReactCommon/jsinspector-modern/network/NetworkReporter.h +++ b/packages/react-native/ReactCommon/jsinspector-modern/network/NetworkReporter.h @@ -35,11 +35,11 @@ using FrontendChannel = std::function; */ struct ResourceTimingData { std::string url; - DOMHighResTimeStamp fetchStart; - DOMHighResTimeStamp requestStart; - std::optional connectStart; - std::optional connectEnd; - std::optional responseStart; + HighResTimeStamp fetchStart; + HighResTimeStamp requestStart; + std::optional connectStart; + std::optional connectEnd; + std::optional responseStart; std::optional responseStatus; }; diff --git a/packages/react-native/ReactCommon/jsinspector-modern/tracing/EventLoopReporter.cpp b/packages/react-native/ReactCommon/jsinspector-modern/tracing/EventLoopReporter.cpp index 0c9ccba0208..535fe2af5f1 100644 --- a/packages/react-native/ReactCommon/jsinspector-modern/tracing/EventLoopReporter.cpp +++ b/packages/react-native/ReactCommon/jsinspector-modern/tracing/EventLoopReporter.cpp @@ -8,6 +8,7 @@ #include "EventLoopReporter.h" #if defined(REACT_NATIVE_DEBUGGER_ENABLED) +#include #include "PerformanceTracer.h" #endif diff --git a/packages/react-native/ReactCommon/jsinspector-modern/tracing/PerformanceTracer.cpp b/packages/react-native/ReactCommon/jsinspector-modern/tracing/PerformanceTracer.cpp index 0197b82c7f0..837e484efb0 100644 --- a/packages/react-native/ReactCommon/jsinspector-modern/tracing/PerformanceTracer.cpp +++ b/packages/react-native/ReactCommon/jsinspector-modern/tracing/PerformanceTracer.cpp @@ -9,6 +9,7 @@ #include "Timing.h" #include +#include #include diff --git a/packages/react-native/ReactCommon/jsinspector-modern/tracing/PerformanceTracer.h b/packages/react-native/ReactCommon/jsinspector-modern/tracing/PerformanceTracer.h index 9acc978dfc7..c01ff8b63f6 100644 --- a/packages/react-native/ReactCommon/jsinspector-modern/tracing/PerformanceTracer.h +++ b/packages/react-native/ReactCommon/jsinspector-modern/tracing/PerformanceTracer.h @@ -13,6 +13,8 @@ #include +#include + #include #include #include diff --git a/packages/react-native/ReactCommon/react/bridging/tests/BridgingTest.cpp b/packages/react-native/ReactCommon/react/bridging/tests/BridgingTest.cpp index db7287e79d1..804d4a1f3f3 100644 --- a/packages/react-native/ReactCommon/react/bridging/tests/BridgingTest.cpp +++ b/packages/react-native/ReactCommon/react/bridging/tests/BridgingTest.cpp @@ -784,7 +784,7 @@ TEST_F(BridgingTest, highResTimeStampTest) { bridging::fromJs( rt, bridging::toJs(rt, timestamp), invoker)); - HighResDuration duration = HighResDuration::fromNanoseconds(1); + auto duration = HighResDuration::fromNanoseconds(1); EXPECT_EQ( duration, bridging::fromJs( diff --git a/packages/react-native/ReactCommon/react/nativemodule/intersectionobserver/NativeIntersectionObserver.h b/packages/react-native/ReactCommon/react/nativemodule/intersectionobserver/NativeIntersectionObserver.h index 9ea6487b9f7..bc6f9f5a478 100644 --- a/packages/react-native/ReactCommon/react/nativemodule/intersectionobserver/NativeIntersectionObserver.h +++ b/packages/react-native/ReactCommon/react/nativemodule/intersectionobserver/NativeIntersectionObserver.h @@ -49,7 +49,7 @@ using NativeIntersectionObserverEntry = // isIntersectingAboveThresholds bool, // time - double>; + HighResTimeStamp>; template <> struct Bridging diff --git a/packages/react-native/ReactCommon/react/nativemodule/webperformance/NativePerformance.cpp b/packages/react-native/ReactCommon/react/nativemodule/webperformance/NativePerformance.cpp index e8b60299d66..d6ab76d20d8 100644 --- a/packages/react-native/ReactCommon/react/nativemodule/webperformance/NativePerformance.cpp +++ b/packages/react-native/ReactCommon/react/nativemodule/webperformance/NativePerformance.cpp @@ -116,30 +116,31 @@ std::shared_ptr tryGetObserver( NativePerformance::NativePerformance(std::shared_ptr jsInvoker) : NativePerformanceCxxSpec(std::move(jsInvoker)) {} -double NativePerformance::now(jsi::Runtime& /*rt*/) { +HighResTimeStamp NativePerformance::now(jsi::Runtime& /*rt*/) { return JSExecutor::performanceNow(); } -double NativePerformance::markWithResult( +HighResTimeStamp NativePerformance::markWithResult( jsi::Runtime& rt, std::string name, - std::optional startTime) { + std::optional startTime) { auto entry = PerformanceEntryReporter::getInstance()->reportMark(name, startTime); return entry.startTime; } -std::tuple NativePerformance::measureWithResult( +std::tuple +NativePerformance::measureWithResult( jsi::Runtime& runtime, std::string name, - double startTime, - double endTime, - std::optional duration, + HighResTimeStamp startTime, + HighResTimeStamp endTime, + std::optional duration, std::optional startMark, std::optional endMark) { auto reporter = PerformanceEntryReporter::getInstance(); - DOMHighResTimeStamp startTimeValue = startTime; + HighResTimeStamp startTimeValue = startTime; // If the start time mark name is specified, it takes precedence over the // startTime parameter, which can be set to 0 by default from JavaScript. if (startMark) { @@ -151,7 +152,7 @@ std::tuple NativePerformance::measureWithResult( } } - DOMHighResTimeStamp endTimeValue = endTime; + HighResTimeStamp endTimeValue = endTime; // If the end time mark name is specified, it takes precedence over the // startTime parameter, which can be set to 0 by default from JavaScript. if (endMark) { @@ -345,7 +346,8 @@ void NativePerformance::observe( return; } - auto durationThreshold = options.durationThreshold.value_or(0.0); + auto durationThreshold = + options.durationThreshold.value_or(HighResDuration::zero()); // observer of type multiple if (options.entryTypes.has_value()) { diff --git a/packages/react-native/ReactCommon/react/nativemodule/webperformance/NativePerformance.h b/packages/react-native/ReactCommon/react/nativemodule/webperformance/NativePerformance.h index 1a23499f988..d2602b0b78b 100644 --- a/packages/react-native/ReactCommon/react/nativemodule/webperformance/NativePerformance.h +++ b/packages/react-native/ReactCommon/react/nativemodule/webperformance/NativePerformance.h @@ -32,7 +32,7 @@ using NativePerformancePerformanceObserverObserveOptions = // buffered std::optional, // durationThreshold - std::optional>; + std::optional>; template <> struct Bridging { @@ -52,21 +52,21 @@ struct Bridging { struct NativePerformanceEntry { std::string name; PerformanceEntryType entryType; - DOMHighResTimeStamp startTime; - DOMHighResTimeStamp duration; + HighResTimeStamp startTime; + HighResDuration duration; // For PerformanceEventTiming only - std::optional processingStart; - std::optional processingEnd; + std::optional processingStart; + std::optional processingEnd; std::optional interactionId; // For PerformanceResourceTiming only - std::optional fetchStart; - std::optional requestStart; - std::optional connectStart; - std::optional connectEnd; - std::optional responseStart; - std::optional responseEnd; + std::optional fetchStart; + std::optional requestStart; + std::optional connectStart; + std::optional connectEnd; + std::optional responseStart; + std::optional responseEnd; std::optional responseStatus; }; @@ -86,23 +86,23 @@ class NativePerformance : public NativePerformanceCxxSpec { #pragma mark - DOM Performance (High Resolution Time) (https://www.w3.org/TR/hr-time-3/#dom-performance) // https://www.w3.org/TR/hr-time-3/#now-method - double now(jsi::Runtime& rt); + HighResTimeStamp now(jsi::Runtime& rt); #pragma mark - User Timing Level 3 functions (https://w3c.github.io/user-timing/) // https://w3c.github.io/user-timing/#mark-method - double markWithResult( + HighResTimeStamp markWithResult( jsi::Runtime& rt, std::string name, - std::optional startTime); + std::optional startTime); // https://w3c.github.io/user-timing/#measure-method - std::tuple measureWithResult( + std::tuple measureWithResult( jsi::Runtime& rt, std::string name, - double startTime, - double endTime, - std::optional duration, + HighResTimeStamp startTime, + HighResTimeStamp endTime, + std::optional duration, std::optional startMark, std::optional endMark); diff --git a/packages/react-native/ReactCommon/react/performance/timeline/PerformanceEntry.h b/packages/react-native/ReactCommon/react/performance/timeline/PerformanceEntry.h index e794902f85d..887af0d1a07 100644 --- a/packages/react-native/ReactCommon/react/performance/timeline/PerformanceEntry.h +++ b/packages/react-native/ReactCommon/react/performance/timeline/PerformanceEntry.h @@ -8,6 +8,7 @@ #pragma once #include + #include #include #include @@ -28,8 +29,8 @@ enum class PerformanceEntryType { struct AbstractPerformanceEntry { std::string name; - DOMHighResTimeStamp startTime; - DOMHighResTimeStamp duration = 0; + HighResTimeStamp startTime; + HighResDuration duration = HighResDuration::zero(); }; struct PerformanceMark : AbstractPerformanceEntry { @@ -43,8 +44,8 @@ struct PerformanceMeasure : AbstractPerformanceEntry { struct PerformanceEventTiming : AbstractPerformanceEntry { static constexpr PerformanceEntryType entryType = PerformanceEntryType::EVENT; - DOMHighResTimeStamp processingStart; - DOMHighResTimeStamp processingEnd; + HighResTimeStamp processingStart; + HighResTimeStamp processingEnd; PerformanceEntryInteractionId interactionId; }; @@ -57,13 +58,13 @@ struct PerformanceResourceTiming : AbstractPerformanceEntry { static constexpr PerformanceEntryType entryType = PerformanceEntryType::RESOURCE; /** Aligns with `startTime`. */ - DOMHighResTimeStamp fetchStart; - DOMHighResTimeStamp requestStart; - std::optional connectStart; - std::optional connectEnd; - std::optional responseStart; + HighResTimeStamp fetchStart; + HighResTimeStamp requestStart; + std::optional connectStart; + std::optional connectEnd; + std::optional responseStart; /** Aligns with `duration`. */ - std::optional responseEnd; + std::optional responseEnd; std::optional responseStatus; }; diff --git a/packages/react-native/ReactCommon/react/performance/timeline/PerformanceEntryBuffer.h b/packages/react-native/ReactCommon/react/performance/timeline/PerformanceEntryBuffer.h index 96a137ace14..c3ce79d3412 100644 --- a/packages/react-native/ReactCommon/react/performance/timeline/PerformanceEntryBuffer.h +++ b/packages/react-native/ReactCommon/react/performance/timeline/PerformanceEntryBuffer.h @@ -14,7 +14,7 @@ namespace facebook::react { // Default duration threshold for reporting performance entries (0 means "report // all") -constexpr double DEFAULT_DURATION_THRESHOLD = 0.0; +constexpr HighResDuration DEFAULT_DURATION_THRESHOLD = HighResDuration::zero(); /** * Abstract performance entry buffer with reporting flags. @@ -22,7 +22,7 @@ constexpr double DEFAULT_DURATION_THRESHOLD = 0.0; */ class PerformanceEntryBuffer { public: - double durationThreshold{DEFAULT_DURATION_THRESHOLD}; + HighResDuration durationThreshold = DEFAULT_DURATION_THRESHOLD; size_t droppedEntriesCount{0}; explicit PerformanceEntryBuffer() = default; diff --git a/packages/react-native/ReactCommon/react/performance/timeline/PerformanceEntryReporter.cpp b/packages/react-native/ReactCommon/react/performance/timeline/PerformanceEntryReporter.cpp index 441409b8571..01a7591ccef 100644 --- a/packages/react-native/ReactCommon/react/performance/timeline/PerformanceEntryReporter.cpp +++ b/packages/react-native/ReactCommon/react/performance/timeline/PerformanceEntryReporter.cpp @@ -37,10 +37,6 @@ std::vector getSupportedEntryTypesInternal() { return supportedEntryTypes; } -double performanceNow() { - return chronoToDOMHighResTimeStamp(std::chrono::steady_clock::now()); -} - #if defined(__clang__) #define NO_DESTROY [[clang::no_destroy]] #else @@ -83,9 +79,9 @@ PerformanceEntryReporter::PerformanceEntryReporter() #endif } -DOMHighResTimeStamp PerformanceEntryReporter::getCurrentTimeStamp() const { +HighResTimeStamp PerformanceEntryReporter::getCurrentTimeStamp() const { return timeStampProvider_ != nullptr ? timeStampProvider_() - : performanceNow(); + : HighResTimeStamp::now(); } std::vector @@ -173,7 +169,7 @@ void PerformanceEntryReporter::clearEntries( PerformanceMark PerformanceEntryReporter::reportMark( const std::string& name, - const std::optional& startTime) { + const std::optional& startTime) { // Resolve timings auto startTimeVal = startTime ? *startTime : getCurrentTimeStamp(); const auto entry = PerformanceMark{{.name = name, .startTime = startTimeVal}}; @@ -193,11 +189,11 @@ PerformanceMark PerformanceEntryReporter::reportMark( PerformanceMeasure PerformanceEntryReporter::reportMeasure( const std::string& name, - DOMHighResTimeStamp startTime, - DOMHighResTimeStamp endTime, + HighResTimeStamp startTime, + HighResTimeStamp endTime, const std::optional& trackMetadata) { - DOMHighResTimeStamp duration = endTime - startTime; + HighResDuration duration = endTime - startTime; const auto entry = PerformanceMeasure{ {.name = std::string(name), @@ -217,7 +213,7 @@ PerformanceMeasure PerformanceEntryReporter::reportMeasure( return entry; } -std::optional PerformanceEntryReporter::getMarkTime( +std::optional PerformanceEntryReporter::getMarkTime( const std::string& markName) const { std::shared_lock lock(buffersMutex_); @@ -231,10 +227,10 @@ std::optional PerformanceEntryReporter::getMarkTime( void PerformanceEntryReporter::reportEvent( std::string name, - DOMHighResTimeStamp startTime, - DOMHighResTimeStamp duration, - DOMHighResTimeStamp processingStart, - DOMHighResTimeStamp processingEnd, + HighResTimeStamp startTime, + HighResDuration duration, + HighResTimeStamp processingStart, + HighResTimeStamp processingEnd, uint32_t interactionId) { eventCounts_[name]++; @@ -260,8 +256,8 @@ void PerformanceEntryReporter::reportEvent( } void PerformanceEntryReporter::reportLongTask( - DOMHighResTimeStamp startTime, - DOMHighResTimeStamp duration) { + HighResTimeStamp startTime, + HighResDuration duration) { const auto entry = PerformanceLongTaskTiming{ {.name = std::string{"self"}, .startTime = startTime, @@ -277,12 +273,12 @@ void PerformanceEntryReporter::reportLongTask( PerformanceResourceTiming PerformanceEntryReporter::reportResourceTiming( const std::string& url, - DOMHighResTimeStamp fetchStart, - DOMHighResTimeStamp requestStart, - std::optional connectStart, - std::optional connectEnd, - DOMHighResTimeStamp responseStart, - DOMHighResTimeStamp responseEnd, + HighResTimeStamp fetchStart, + HighResTimeStamp requestStart, + std::optional connectStart, + std::optional connectEnd, + HighResTimeStamp responseStart, + HighResTimeStamp responseEnd, const std::optional& responseStatus) { const auto entry = PerformanceResourceTiming{ {.name = url, .startTime = fetchStart}, @@ -313,9 +309,7 @@ void PerformanceEntryReporter::traceMark(const PerformanceMark& entry) const { auto [trackName, eventName] = parseTrackName(entry.name); if (performanceTracer.isTracing()) { - performanceTracer.reportMark( - entry.name, - HighResTimeStamp::fromDOMHighResTimeStamp(entry.startTime)); + performanceTracer.reportMark(entry.name, entry.startTime); } if (ReactPerfettoLogger::isTracing()) { @@ -339,10 +333,7 @@ void PerformanceEntryReporter::traceMeasure( trackMetadata = {.track = trackName.value()}; } performanceTracer.reportMeasure( - eventName, - HighResTimeStamp::fromDOMHighResTimeStamp(entry.startTime), - HighResDuration::fromDOMHighResTimeStamp(entry.duration), - trackMetadata); + eventName, entry.startTime, entry.duration, trackMetadata); } if (ReactPerfettoLogger::isTracing()) { diff --git a/packages/react-native/ReactCommon/react/performance/timeline/PerformanceEntryReporter.h b/packages/react-native/ReactCommon/react/performance/timeline/PerformanceEntryReporter.h index 549fe6f591a..2eb67ceca03 100644 --- a/packages/react-native/ReactCommon/react/performance/timeline/PerformanceEntryReporter.h +++ b/packages/react-native/ReactCommon/react/performance/timeline/PerformanceEntryReporter.h @@ -27,7 +27,8 @@ constexpr size_t EVENT_BUFFER_SIZE = 150; constexpr size_t LONG_TASK_BUFFER_SIZE = 200; constexpr size_t RESOURCE_TIMING_BUFFER_SIZE = 250; -constexpr DOMHighResTimeStamp LONG_TASK_DURATION_THRESHOLD_MS = 50.0; +constexpr HighResDuration LONG_TASK_DURATION_THRESHOLD = + HighResDuration::fromMilliseconds(50); class PerformanceEntryReporter { public: @@ -66,9 +67,9 @@ class PerformanceEntryReporter { PerformanceEntryType entryType, const std::string& entryName); - DOMHighResTimeStamp getCurrentTimeStamp() const; + HighResTimeStamp getCurrentTimeStamp() const; - void setTimeStampProvider(std::function provider) { + void setTimeStampProvider(std::function provider) { timeStampProvider_ = std::move(provider); } @@ -80,37 +81,38 @@ class PerformanceEntryReporter { return eventCounts_; } - std::optional getMarkTime(const std::string& markName) const; + std::optional getMarkTime( + const std::string& markName) const; PerformanceMark reportMark( const std::string& name, - const std::optional& startTime = std::nullopt); + const std::optional& startTime = std::nullopt); PerformanceMeasure reportMeasure( const std::string& name, - double startTime, - double endTime, + HighResTimeStamp startTime, + HighResTimeStamp endTime, const std::optional& trackMetadata = std::nullopt); void reportEvent( std::string name, - double startTime, - double duration, - double processingStart, - double processingEnd, + HighResTimeStamp startTime, + HighResDuration duration, + HighResTimeStamp processingStart, + HighResTimeStamp processingEnd, uint32_t interactionId); - void reportLongTask(double startTime, double duration); + void reportLongTask(HighResTimeStamp startTime, HighResDuration duration); PerformanceResourceTiming reportResourceTiming( const std::string& url, - DOMHighResTimeStamp fetchStart, - DOMHighResTimeStamp requestStart, - std::optional connectStart, - std::optional connectEnd, - DOMHighResTimeStamp responseStart, - DOMHighResTimeStamp responseEnd, + HighResTimeStamp fetchStart, + HighResTimeStamp requestStart, + std::optional connectStart, + std::optional connectEnd, + HighResTimeStamp responseStart, + HighResTimeStamp responseEnd, const std::optional& responseStatus); private: @@ -126,7 +128,7 @@ class PerformanceEntryReporter { std::unordered_map eventCounts_; - std::function timeStampProvider_ = nullptr; + std::function timeStampProvider_ = nullptr; const inline PerformanceEntryBuffer& getBuffer( PerformanceEntryType entryType) const { diff --git a/packages/react-native/ReactCommon/react/performance/timeline/PerformanceObserver.h b/packages/react-native/ReactCommon/react/performance/timeline/PerformanceObserver.h index a79d8d0a99f..8b387ec753c 100644 --- a/packages/react-native/ReactCommon/react/performance/timeline/PerformanceObserver.h +++ b/packages/react-native/ReactCommon/react/performance/timeline/PerformanceObserver.h @@ -7,12 +7,15 @@ #pragma once +#include "PerformanceEntryBuffer.h" +#include "PerformanceObserverRegistry.h" + +#include + #include #include #include #include -#include "PerformanceEntryBuffer.h" -#include "PerformanceObserverRegistry.h" namespace facebook::react { @@ -27,7 +30,7 @@ using PerformanceObserverCallback = std::function; * https://w3c.github.io/performance-timeline/#performanceobserverinit-dictionary */ struct PerformanceObserverObserveMultipleOptions { - double durationThreshold = 0.0; + HighResDuration durationThreshold = DEFAULT_DURATION_THRESHOLD; }; /** @@ -38,7 +41,7 @@ struct PerformanceObserverObserveMultipleOptions { */ struct PerformanceObserverObserveSingleOptions { bool buffered = false; - double durationThreshold = 0.0; + HighResDuration durationThreshold = DEFAULT_DURATION_THRESHOLD; }; /** @@ -124,7 +127,7 @@ class PerformanceObserver PerformanceObserverEntryTypeFilter observedTypes_; /// https://www.w3.org/TR/event-timing/#sec-modifications-perf-timeline - double durationThreshold_{DEFAULT_DURATION_THRESHOLD}; + HighResDuration durationThreshold_ = DEFAULT_DURATION_THRESHOLD; std::vector buffer_; bool didScheduleFlushBuffer_ = false; bool requiresDroppedEntries_ = false; diff --git a/packages/react-native/ReactCommon/react/performance/timeline/tests/PerformanceEntryReporterTest.cpp b/packages/react-native/ReactCommon/react/performance/timeline/tests/PerformanceEntryReporterTest.cpp index 5217debd97d..330eb185f44 100644 --- a/packages/react-native/ReactCommon/react/performance/timeline/tests/PerformanceEntryReporterTest.cpp +++ b/packages/react-native/ReactCommon/react/performance/timeline/tests/PerformanceEntryReporterTest.cpp @@ -58,8 +58,10 @@ namespace facebook::react { [&](const auto& entryDetails) -> std::ostream& { os << "{ .name = \"" << entryDetails.name << "\"" << ", .entryType = " << entryTypeNames[static_cast(entryDetails.entryType) - 1] - << ", .startTime = " << entryDetails.startTime - << ", .duration = " << entryDetails.duration << " }"; + << ", .startTime = " + << entryDetails.startTime.toDOMHighResTimeStamp() + << ", .duration = " << entryDetails.duration.toDOMHighResTimeStamp() + << " }"; return os; }, entry); @@ -77,60 +79,116 @@ std::vector toSorted( TEST(PerformanceEntryReporter, PerformanceEntryReporterTestReportMarks) { auto reporter = PerformanceEntryReporter::getInstance(); + auto timeOrigin = HighResTimeStamp::now(); reporter->clearEntries(); - reporter->reportMark("mark0", 0); - reporter->reportMark("mark1", 1); - reporter->reportMark("mark2", 2); + reporter->reportMark("mark0", timeOrigin); + reporter->reportMark( + "mark1", timeOrigin + HighResDuration::fromMilliseconds(1)); + reporter->reportMark( + "mark2", timeOrigin + HighResDuration::fromMilliseconds(2)); // Report mark0 again - reporter->reportMark("mark0", 3); + reporter->reportMark( + "mark0", timeOrigin + HighResDuration::fromMilliseconds(3)); const auto entries = toSorted(reporter->getEntries()); ASSERT_EQ(4, entries.size()); const std::vector expected = { - PerformanceMark{{.name = "mark0", .startTime = 0, .duration = 0}}, - PerformanceMark{{.name = "mark1", .startTime = 1, .duration = 0}}, - PerformanceMark{{.name = "mark2", .startTime = 2, .duration = 0}}, - PerformanceMark{{.name = "mark0", .startTime = 3, .duration = 0}}}; + PerformanceMark{ + {.name = "mark0", + .startTime = timeOrigin, + .duration = HighResDuration::zero()}}, + PerformanceMark{ + {.name = "mark1", + .startTime = timeOrigin + HighResDuration::fromMilliseconds(1), + .duration = HighResDuration::zero()}}, + PerformanceMark{ + {.name = "mark2", + .startTime = timeOrigin + HighResDuration::fromMilliseconds(2), + .duration = HighResDuration::zero()}}, + PerformanceMark{ + {.name = "mark0", + .startTime = timeOrigin + HighResDuration::fromMilliseconds(3), + .duration = HighResDuration::zero()}}}; ASSERT_EQ(expected, entries); } TEST(PerformanceEntryReporter, PerformanceEntryReporterTestReportMeasures) { auto reporter = PerformanceEntryReporter::getInstance(); + auto timeOrigin = HighResTimeStamp::now(); reporter->clearEntries(); - reporter->reportMark("mark0", 0); - reporter->reportMark("mark1", 1); - reporter->reportMark("mark2", 2); + reporter->reportMark("mark0", timeOrigin); + reporter->reportMark( + "mark1", timeOrigin + HighResDuration::fromMilliseconds(1)); + reporter->reportMark( + "mark2", timeOrigin + HighResDuration::fromMilliseconds(2)); - reporter->reportMeasure("measure0", 0, 2); - reporter->reportMeasure("measure1", 0, 3); + reporter->reportMeasure( + "measure0", + timeOrigin, + timeOrigin + HighResDuration::fromMilliseconds(2)); + reporter->reportMeasure( + "measure1", + timeOrigin, + timeOrigin + HighResDuration::fromMilliseconds(3)); - reporter->reportMark("mark3", 2.5); - reporter->reportMeasure("measure2", 2.0, 2.0); - reporter->reportMark("mark4", 3.0); + reporter->reportMark( + "mark3", timeOrigin + HighResDuration::fromNanoseconds(2.5 * 1e6)); + reporter->reportMeasure( + "measure2", + timeOrigin + HighResDuration::fromMilliseconds(2), + timeOrigin + HighResDuration::fromMilliseconds(2)); + reporter->reportMark( + "mark4", timeOrigin + HighResDuration::fromMilliseconds(3)); const auto entries = toSorted(reporter->getEntries()); const std::vector expected = { - PerformanceMark{{.name = "mark0", .startTime = 0, .duration = 0}}, - PerformanceMeasure{{.name = "measure0", .startTime = 0, .duration = 2}}, - PerformanceMeasure{{.name = "measure1", .startTime = 0, .duration = 3}}, - PerformanceMark{{.name = "mark1", .startTime = 1, .duration = 0}}, - PerformanceMark{{.name = "mark2", .startTime = 2, .duration = 0}}, - PerformanceMeasure{{.name = "measure2", .startTime = 2, .duration = 0}}, - PerformanceMark{{.name = "mark3", .startTime = 2.5, .duration = 0}}, - PerformanceMark{{.name = "mark4", .startTime = 3, .duration = 0}}}; + PerformanceMark{ + {.name = "mark0", + .startTime = timeOrigin, + .duration = HighResDuration::zero()}}, + PerformanceMeasure{ + {.name = "measure0", + .startTime = timeOrigin, + .duration = HighResDuration::fromMilliseconds(2)}}, + PerformanceMeasure{ + {.name = "measure1", + .startTime = timeOrigin, + .duration = HighResDuration::fromMilliseconds(3)}}, + PerformanceMark{ + {.name = "mark1", + .startTime = timeOrigin + HighResDuration::fromMilliseconds(1), + .duration = HighResDuration::zero()}}, + PerformanceMark{ + {.name = "mark2", + .startTime = timeOrigin + HighResDuration::fromMilliseconds(2), + .duration = HighResDuration::zero()}}, + PerformanceMeasure{ + {.name = "measure2", + .startTime = timeOrigin + HighResDuration::fromMilliseconds(2), + .duration = HighResDuration::zero()}}, + PerformanceMark{ + {.name = "mark3", + .startTime = + timeOrigin + HighResDuration::fromNanoseconds(2.5 * 1e6), + .duration = HighResDuration::zero()}}, + PerformanceMark{ + {.name = "mark4", + .startTime = timeOrigin + HighResDuration::fromMilliseconds(3), + .duration = HighResDuration::zero()}}}; ASSERT_EQ(expected, entries); } TEST(PerformanceEntryReporter, PerformanceEntryReporterTestGetEntries) { auto reporter = PerformanceEntryReporter::getInstance(); + auto timeOrigin = HighResTimeStamp::now(); reporter->clearEntries(); { @@ -138,27 +196,61 @@ TEST(PerformanceEntryReporter, PerformanceEntryReporterTestGetEntries) { ASSERT_EQ(0, entries.size()); } - reporter->reportMark("common_name", 0); - reporter->reportMark("mark1", 1); - reporter->reportMark("mark2", 2); + reporter->reportMark("common_name", timeOrigin); + reporter->reportMark( + "mark1", timeOrigin + HighResDuration::fromMilliseconds(1)); + reporter->reportMark( + "mark2", timeOrigin + HighResDuration::fromMilliseconds(2)); - reporter->reportMeasure("common_name", 0, 2); - reporter->reportMeasure("measure1", 0, 3); - reporter->reportMeasure("measure2", 1, 6); - reporter->reportMeasure("measure3", 1.5, 2); + reporter->reportMeasure( + "common_name", + timeOrigin, + timeOrigin + HighResDuration::fromMilliseconds(2)); + reporter->reportMeasure( + "measure1", + timeOrigin, + timeOrigin + HighResDuration::fromMilliseconds(3)); + reporter->reportMeasure( + "measure2", + timeOrigin + HighResDuration::fromMilliseconds(1), + timeOrigin + HighResDuration::fromMilliseconds(6)); + reporter->reportMeasure( + "measure3", + timeOrigin + HighResDuration::fromNanoseconds(1.5 * 1e6), + timeOrigin + HighResDuration::fromMilliseconds(2)); { const auto allEntries = toSorted(reporter->getEntries()); const std::vector expected = { - PerformanceMark{{.name = "common_name", .startTime = 0, .duration = 0}}, + PerformanceMark{ + {.name = "common_name", + .startTime = timeOrigin, + .duration = HighResDuration::zero()}}, PerformanceMeasure{ - {.name = "common_name", .startTime = 0, .duration = 2}}, - PerformanceMeasure{{.name = "measure1", .startTime = 0, .duration = 3}}, - PerformanceMark{{.name = "mark1", .startTime = 1, .duration = 0}}, - PerformanceMeasure{{.name = "measure2", .startTime = 1, .duration = 5}}, + {.name = "common_name", + .startTime = timeOrigin, + .duration = HighResDuration::fromMilliseconds(2)}}, PerformanceMeasure{ - {.name = "measure3", .startTime = 1.5, .duration = 0.5}}, - PerformanceMark{{.name = "mark2", .startTime = 2, .duration = 0}}}; + {.name = "measure1", + .startTime = timeOrigin, + .duration = HighResDuration::fromMilliseconds(3)}}, + PerformanceMark{ + {.name = "mark1", + .startTime = timeOrigin + HighResDuration::fromMilliseconds(1), + .duration = HighResDuration::zero()}}, + PerformanceMeasure{ + {.name = "measure2", + .startTime = timeOrigin + HighResDuration::fromMilliseconds(1), + .duration = HighResDuration::fromMilliseconds(5)}}, + PerformanceMeasure{ + {.name = "measure3", + .startTime = + timeOrigin + HighResDuration::fromNanoseconds(1.5 * 1e6), + .duration = HighResDuration::fromNanoseconds(0.5 * 1e6)}}, + PerformanceMark{ + {.name = "mark2", + .startTime = timeOrigin + HighResDuration::fromMilliseconds(2), + .duration = HighResDuration::zero()}}}; ASSERT_EQ(expected, allEntries); } @@ -166,9 +258,18 @@ TEST(PerformanceEntryReporter, PerformanceEntryReporterTestGetEntries) { const auto marks = toSorted(reporter->getEntries(PerformanceEntryType::MARK)); const std::vector expected = { - PerformanceMark{{.name = "common_name", .startTime = 0, .duration = 0}}, - PerformanceMark{{.name = "mark1", .startTime = 1, .duration = 0}}, - PerformanceMark{{.name = "mark2", .startTime = 2, .duration = 0}}}; + PerformanceMark{ + {.name = "common_name", + .startTime = timeOrigin, + .duration = HighResDuration::zero()}}, + PerformanceMark{ + {.name = "mark1", + .startTime = timeOrigin + HighResDuration::fromMilliseconds(1), + .duration = HighResDuration::zero()}}, + PerformanceMark{ + {.name = "mark2", + .startTime = timeOrigin + HighResDuration::fromMilliseconds(2), + .duration = HighResDuration::zero()}}}; ASSERT_EQ(expected, marks); } @@ -177,17 +278,28 @@ TEST(PerformanceEntryReporter, PerformanceEntryReporterTestGetEntries) { toSorted(reporter->getEntries(PerformanceEntryType::MEASURE)); const std::vector expected = { PerformanceMeasure{ - {.name = "common_name", .startTime = 0, .duration = 2}}, - PerformanceMeasure{{.name = "measure1", .startTime = 0, .duration = 3}}, - PerformanceMeasure{{.name = "measure2", .startTime = 1, .duration = 5}}, + {.name = "common_name", + .startTime = timeOrigin, + .duration = HighResDuration::fromMilliseconds(2)}}, PerformanceMeasure{ - {.name = "measure3", .startTime = 1.5, .duration = 0.5}}}; + {.name = "measure1", + .startTime = timeOrigin, + .duration = HighResDuration::fromMilliseconds(3)}}, + PerformanceMeasure{ + {.name = "measure2", + .startTime = timeOrigin + HighResDuration::fromMilliseconds(1), + .duration = HighResDuration::fromMilliseconds(5)}}, + PerformanceMeasure{ + {.name = "measure3", + .startTime = + timeOrigin + HighResDuration::fromNanoseconds(1.5 * 1e6), + .duration = HighResDuration::fromNanoseconds(0.5 * 1e6)}}}; ASSERT_EQ(expected, measures); } { const std::vector expected = { - PerformanceMark{{.name = "common_name", .startTime = 0}}}; + PerformanceMark{{.name = "common_name", .startTime = timeOrigin}}}; const auto commonName = reporter->getEntries(PerformanceEntryType::MARK, "common_name"); ASSERT_EQ(expected, commonName); @@ -195,7 +307,9 @@ TEST(PerformanceEntryReporter, PerformanceEntryReporterTestGetEntries) { { const std::vector expected = {PerformanceMeasure{ - {.name = "common_name", .startTime = 0, .duration = 2}}}; + {.name = "common_name", + .startTime = timeOrigin, + .duration = HighResDuration::fromMilliseconds(2)}}}; const auto commonName = reporter->getEntries(PerformanceEntryType::MEASURE, "common_name"); ASSERT_EQ(expected, commonName); @@ -204,26 +318,52 @@ TEST(PerformanceEntryReporter, PerformanceEntryReporterTestGetEntries) { TEST(PerformanceEntryReporter, PerformanceEntryReporterTestClearMarks) { auto reporter = PerformanceEntryReporter::getInstance(); + auto timeOrigin = HighResTimeStamp::now(); reporter->clearEntries(); - reporter->reportMark("common_name", 0); - reporter->reportMark("mark1", 1); - reporter->reportMark("mark1", 2.1); - reporter->reportMark("mark2", 2); + reporter->reportMark("common_name", timeOrigin); + reporter->reportMark( + "mark1", timeOrigin + HighResDuration::fromMilliseconds(1)); + reporter->reportMark( + "mark1", timeOrigin + HighResDuration::fromNanoseconds(2.1 * 1e6)); + reporter->reportMark( + "mark2", timeOrigin + HighResDuration::fromMilliseconds(2)); - reporter->reportMeasure("common_name", 0, 2); - reporter->reportMeasure("measure1", 0, 3); - reporter->reportMeasure("measure2", 1, 6); - reporter->reportMeasure("measure3", 1.5, 2); + reporter->reportMeasure( + "common_name", + timeOrigin, + timeOrigin + HighResDuration::fromMilliseconds(2)); + reporter->reportMeasure( + "measure1", + timeOrigin, + timeOrigin + HighResDuration::fromMilliseconds(3)); + reporter->reportMeasure( + "measure2", + timeOrigin + HighResDuration::fromMilliseconds(1), + timeOrigin + HighResDuration::fromMilliseconds(6)); + reporter->reportMeasure( + "measure3", + timeOrigin + HighResDuration::fromNanoseconds(1.5 * 1e6), + timeOrigin + HighResDuration::fromMilliseconds(2)); reporter->clearEntries(PerformanceEntryType::MARK, "common_name"); { auto entries = toSorted(reporter->getEntries(PerformanceEntryType::MARK)); std::vector expected = { - PerformanceMark{{.name = "mark1", .startTime = 1, .duration = 0}}, - PerformanceMark{{.name = "mark2", .startTime = 2, .duration = 0}}, - PerformanceMark{{.name = "mark1", .startTime = 2.1, .duration = 0}}, + PerformanceMark{ + {.name = "mark1", + .startTime = timeOrigin + HighResDuration::fromMilliseconds(1), + .duration = HighResDuration::zero()}}, + PerformanceMark{ + {.name = "mark2", + .startTime = timeOrigin + HighResDuration::fromMilliseconds(2), + .duration = HighResDuration::zero()}}, + PerformanceMark{ + {.name = "mark1", + .startTime = + timeOrigin + HighResDuration::fromNanoseconds(2.1 * 1e6), + .duration = HighResDuration::zero()}}, }; ASSERT_EQ(expected, entries); } diff --git a/packages/react-native/ReactCommon/react/performance/timeline/tests/PerformanceObserverTest.cpp b/packages/react-native/ReactCommon/react/performance/timeline/tests/PerformanceObserverTest.cpp index 06cf2c3e09b..0a954958288 100644 --- a/packages/react-native/ReactCommon/react/performance/timeline/tests/PerformanceObserverTest.cpp +++ b/packages/react-native/ReactCommon/react/performance/timeline/tests/PerformanceObserverTest.cpp @@ -49,12 +49,14 @@ TEST(PerformanceObserver, PerformanceObserverTestObserveFlushes) { bool callbackCalled = false; auto observer = PerformanceObserver::create( reporter->getObserverRegistry(), [&]() { callbackCalled = true; }); + auto timeOrigin = HighResTimeStamp::now(); observer->observe(PerformanceEntryType::MARK); // buffer is empty ASSERT_FALSE(callbackCalled); - reporter->reportMark("test", 10); + reporter->reportMark( + "test", timeOrigin + HighResDuration::fromMilliseconds(10)); ASSERT_TRUE(callbackCalled); observer->disconnect(); @@ -64,10 +66,12 @@ TEST(PerformanceObserver, PerformanceObserverTestFilteredSingle) { auto reporter = PerformanceEntryReporter::getInstance(); reporter->clearEntries(); + auto timeOrigin = HighResTimeStamp::now(); auto observer = PerformanceObserver::create(reporter->getObserverRegistry(), [&]() {}); observer->observe(PerformanceEntryType::MEASURE); - reporter->reportMark("test", 10); + reporter->reportMark( + "test", timeOrigin + HighResDuration::fromMilliseconds(10)); // wrong type ASSERT_EQ(observer->takeRecords().size(), 0); @@ -79,15 +83,34 @@ TEST(PerformanceObserver, PerformanceObserverTestFilterMulti) { auto reporter = PerformanceEntryReporter::getInstance(); reporter->clearEntries(); + auto timeOrigin = HighResTimeStamp::now(); auto callbackCalled = false; auto observer = PerformanceObserver::create( reporter->getObserverRegistry(), [&]() { callbackCalled = true; }); observer->observe( {PerformanceEntryType::MEASURE, PerformanceEntryType::MARK}); - reporter->reportEvent("test1", 10, 10, 0, 0, 0); - reporter->reportEvent("test2", 10, 10, 0, 0, 0); - reporter->reportEvent("test3", 10, 10, 0, 0, 0); + reporter->reportEvent( + "test1", + timeOrigin + HighResDuration::fromMilliseconds(10), + HighResDuration::fromMilliseconds(10), + timeOrigin, + timeOrigin, + 0); + reporter->reportEvent( + "test2", + timeOrigin + HighResDuration::fromMilliseconds(10), + HighResDuration::fromMilliseconds(10), + timeOrigin, + timeOrigin, + 0); + reporter->reportEvent( + "test3", + timeOrigin + HighResDuration::fromMilliseconds(10), + HighResDuration::fromMilliseconds(10), + timeOrigin, + timeOrigin, + 0); ASSERT_EQ(observer->takeRecords().size(), 0); ASSERT_FALSE(callbackCalled); @@ -101,11 +124,14 @@ TEST( auto reporter = PerformanceEntryReporter::getInstance(); reporter->clearEntries(); + auto timeOrigin = HighResTimeStamp::now(); auto callbackCalled = false; auto observer = PerformanceObserver::create( reporter->getObserverRegistry(), [&]() { callbackCalled = true; }); observer->observe(PerformanceEntryType::MEASURE); - reporter->reportMark("test", 10); + + reporter->reportMark( + "test", timeOrigin + HighResDuration::fromMilliseconds(10)); ASSERT_FALSE(callbackCalled); @@ -116,14 +142,34 @@ TEST(PerformanceObserver, PerformanceObserverTestFilterMultiCallbackNotCalled) { auto reporter = PerformanceEntryReporter::getInstance(); reporter->clearEntries(); + auto timeOrigin = HighResTimeStamp::now(); auto callbackCalled = false; auto observer = PerformanceObserver::create( reporter->getObserverRegistry(), [&]() { callbackCalled = true; }); observer->observe( {PerformanceEntryType::MEASURE, PerformanceEntryType::MARK}); - reporter->reportEvent("test1", 10, 10, 0, 0, 0); - reporter->reportEvent("test2", 10, 10, 0, 0, 0); - reporter->reportEvent("off3", 10, 10, 0, 0, 0); + + reporter->reportEvent( + "test1", + timeOrigin + HighResDuration::fromMilliseconds(10), + HighResDuration::fromMilliseconds(10), + timeOrigin, + timeOrigin, + 0); + reporter->reportEvent( + "test2", + timeOrigin + HighResDuration::fromMilliseconds(10), + HighResDuration::fromMilliseconds(10), + timeOrigin, + timeOrigin, + 0); + reporter->reportEvent( + "off3", + timeOrigin + HighResDuration::fromMilliseconds(10), + HighResDuration::fromMilliseconds(10), + timeOrigin, + timeOrigin, + 0); ASSERT_FALSE(callbackCalled); @@ -134,18 +180,32 @@ TEST(PerformanceObserver, PerformanceObserverTestObserveTakeRecords) { auto reporter = PerformanceEntryReporter::getInstance(); reporter->clearEntries(); + auto timeOrigin = HighResTimeStamp::now(); auto observer = PerformanceObserver::create(reporter->getObserverRegistry(), [&]() {}); observer->observe(PerformanceEntryType::MARK); - reporter->reportMark("test1", 10); - reporter->reportMeasure("off", 10, 20); - reporter->reportMark("test2", 20); - reporter->reportMark("test3", 30); + + reporter->reportMark( + "test1", timeOrigin + HighResDuration::fromMilliseconds(10)); + reporter->reportMeasure( + "off", + timeOrigin + HighResDuration::fromMilliseconds(10), + timeOrigin + HighResDuration::fromMilliseconds(20)); + reporter->reportMark( + "test2", timeOrigin + HighResDuration::fromMilliseconds(20)); + reporter->reportMark( + "test3", timeOrigin + HighResDuration::fromMilliseconds(30)); const std::vector expected = { - PerformanceMark{{.name = "test1", .startTime = 10}}, - PerformanceMark{{.name = "test2", .startTime = 20}}, - PerformanceMark{{.name = "test3", .startTime = 30}}, + PerformanceMark{ + {.name = "test1", + .startTime = timeOrigin + HighResDuration::fromMilliseconds(10)}}, + PerformanceMark{ + {.name = "test2", + .startTime = timeOrigin + HighResDuration::fromMilliseconds(20)}}, + PerformanceMark{ + {.name = "test3", + .startTime = timeOrigin + HighResDuration::fromMilliseconds(30)}}, }; ASSERT_EQ(expected, observer->takeRecords()); @@ -157,19 +217,66 @@ TEST(PerformanceObserver, PerformanceObserverTestObserveDurationThreshold) { auto reporter = PerformanceEntryReporter::getInstance(); reporter->clearEntries(); + auto timeOrigin = HighResTimeStamp::now(); auto observer = PerformanceObserver::create(reporter->getObserverRegistry(), [&]() {}); - observer->observe(PerformanceEntryType::EVENT, {.durationThreshold = 50}); - reporter->reportEvent("test1", 0, 50, 0, 0, 0); - reporter->reportEvent("test2", 0, 100, 0, 0, 0); - reporter->reportEvent("off1", 0, 40, 0, 0, 0); - reporter->reportMark("off2", 100); - reporter->reportEvent("test3", 0, 60, 0, 0, 0); + observer->observe( + PerformanceEntryType::EVENT, + {.durationThreshold = HighResDuration::fromMilliseconds(50)}); + + reporter->reportEvent( + "test1", + timeOrigin, + HighResDuration::fromMilliseconds(50), + timeOrigin, + timeOrigin, + 0); + reporter->reportEvent( + "test2", + timeOrigin, + HighResDuration::fromMilliseconds(100), + timeOrigin, + timeOrigin, + 0); + reporter->reportEvent( + "off1", + timeOrigin, + HighResDuration::fromMilliseconds(40), + timeOrigin, + timeOrigin, + 0); + reporter->reportMark( + "off2", timeOrigin + HighResDuration::fromMilliseconds(100)); + reporter->reportEvent( + "test3", + timeOrigin, + HighResDuration::fromMilliseconds(60), + timeOrigin, + timeOrigin, + 0); const std::vector expected = { - PerformanceEventTiming{{.name = "test1", .duration = 50}, 0, 0, 0}, - PerformanceEventTiming{{.name = "test2", .duration = 100}, 0, 0, 0}, - PerformanceEventTiming{{.name = "test3", .duration = 60}, 0, 0, 0}, + PerformanceEventTiming{ + {.name = "test1", + .startTime = timeOrigin, + .duration = HighResDuration::fromMilliseconds(50)}, + timeOrigin, + timeOrigin, + 0}, + PerformanceEventTiming{ + {.name = "test2", + .startTime = timeOrigin, + .duration = HighResDuration::fromMilliseconds(100)}, + timeOrigin, + timeOrigin, + 0}, + PerformanceEventTiming{ + {.name = "test3", + .startTime = timeOrigin, + .duration = HighResDuration::fromMilliseconds(60)}, + timeOrigin, + timeOrigin, + 0}, }; ASSERT_EQ(expected, observer->takeRecords()); @@ -181,23 +288,65 @@ TEST(PerformanceObserver, PerformanceObserverTestObserveBuffered) { auto reporter = PerformanceEntryReporter::getInstance(); reporter->clearEntries(); - reporter->reportEvent("test1", 0, 50, 0, 0, 0); - reporter->reportEvent("test2", 0, 100, 0, 0, 0); - reporter->reportEvent("test3", 0, 40, 0, 0, 0); - reporter->reportEvent("test4", 0, 100, 0, 0, 0); + auto timeOrigin = HighResTimeStamp::now(); + reporter->reportEvent( + "test1", + timeOrigin, + HighResDuration::fromMilliseconds(50), + timeOrigin, + timeOrigin, + 0); + reporter->reportEvent( + "test2", + timeOrigin, + HighResDuration::fromMilliseconds(100), + timeOrigin, + timeOrigin, + 0); + reporter->reportEvent( + "test3", + timeOrigin, + HighResDuration::fromMilliseconds(40), + timeOrigin, + timeOrigin, + 0); + reporter->reportEvent( + "test4", + timeOrigin, + HighResDuration::fromMilliseconds(100), + timeOrigin, + timeOrigin, + 0); auto observer = PerformanceObserver::create(reporter->getObserverRegistry(), [&]() {}); observer->observe( - PerformanceEntryType::EVENT, {.buffered = true, .durationThreshold = 50}); + PerformanceEntryType::EVENT, + {.buffered = true, + .durationThreshold = HighResDuration::fromMilliseconds(50)}); const std::vector expected = { PerformanceEventTiming{ - {.name = "test1", .startTime = 0, .duration = 50}, 0, 0, 0}, + {.name = "test1", + .startTime = timeOrigin, + .duration = HighResDuration::fromMilliseconds(50)}, + timeOrigin, + timeOrigin, + 0}, PerformanceEventTiming{ - {.name = "test2", .startTime = 0, .duration = 100}, 0, 0, 0}, + {.name = "test2", + .startTime = timeOrigin, + .duration = HighResDuration::fromMilliseconds(100)}, + timeOrigin, + timeOrigin, + 0}, PerformanceEventTiming{ - {.name = "test4", .startTime = 0, .duration = 100}, 0, 0, 0}, + {.name = "test4", + .startTime = timeOrigin, + .duration = HighResDuration::fromMilliseconds(100)}, + timeOrigin, + timeOrigin, + 0}, }; ASSERT_EQ(expected, observer->takeRecords()); @@ -209,26 +358,71 @@ TEST(PerformanceObserver, PerformanceObserverTestMultiple) { auto reporter = PerformanceEntryReporter::getInstance(); reporter->clearEntries(); + auto timeOrigin = HighResTimeStamp::now(); auto observer1 = PerformanceObserver::create(reporter->getObserverRegistry(), [&]() {}); auto observer2 = PerformanceObserver::create(reporter->getObserverRegistry(), [&]() {}); - observer1->observe(PerformanceEntryType::EVENT, {.durationThreshold = 50}); - observer2->observe(PerformanceEntryType::EVENT, {.durationThreshold = 80}); + observer1->observe( + PerformanceEntryType::EVENT, + {.durationThreshold = HighResDuration::fromMilliseconds(50)}); + observer2->observe( + PerformanceEntryType::EVENT, + {.durationThreshold = HighResDuration::fromMilliseconds(80)}); - reporter->reportMeasure("measure", 0, 50); - reporter->reportEvent("event1", 0, 100, 0, 0, 0); - reporter->reportEvent("event2", 0, 40, 0, 0, 0); - reporter->reportMark("mark1", 100); - reporter->reportEvent("event3", 0, 60, 0, 0, 0); + reporter->reportMeasure( + "measure", + timeOrigin, + timeOrigin + HighResDuration::fromMilliseconds(50)); + reporter->reportEvent( + "event1", + timeOrigin, + HighResDuration::fromMilliseconds(100), + timeOrigin, + timeOrigin, + 0); + reporter->reportEvent( + "event2", + timeOrigin, + HighResDuration::fromMilliseconds(40), + timeOrigin, + timeOrigin, + 0); + reporter->reportMark( + "mark1", timeOrigin + HighResDuration::fromMilliseconds(100)); + reporter->reportEvent( + "event3", + timeOrigin, + HighResDuration::fromMilliseconds(60), + timeOrigin, + timeOrigin, + 0); const std::vector expected1 = { - PerformanceEventTiming{{.name = "event1", .duration = 100}, 0, 0, 0}, - PerformanceEventTiming{{.name = "event3", .duration = 60}, 0, 0, 0}, + PerformanceEventTiming{ + {.name = "event1", + .startTime = timeOrigin, + .duration = HighResDuration::fromMilliseconds(100)}, + timeOrigin, + timeOrigin, + 0}, + PerformanceEventTiming{ + {.name = "event3", + .startTime = timeOrigin, + .duration = HighResDuration::fromMilliseconds(60)}, + timeOrigin, + timeOrigin, + 0}, }; const std::vector expected2 = { - PerformanceEventTiming{{.name = "event1", .duration = 100}, 0, 0, 0}, + PerformanceEventTiming{ + {.name = "event1", + .startTime = timeOrigin, + .duration = HighResDuration::fromMilliseconds(100)}, + timeOrigin, + timeOrigin, + 0}, }; ASSERT_EQ(expected1, observer1->takeRecords()); diff --git a/packages/react-native/ReactCommon/react/renderer/core/EventLogger.h b/packages/react-native/ReactCommon/react/renderer/core/EventLogger.h index 4e5d211e463..1d7526ec471 100644 --- a/packages/react-native/ReactCommon/react/renderer/core/EventLogger.h +++ b/packages/react-native/ReactCommon/react/renderer/core/EventLogger.h @@ -34,8 +34,7 @@ class EventLogger { virtual EventTag onEventStart( std::string_view name, SharedEventTarget target, - std::optional eventStartTimeStamp = - std::nullopt) = 0; + std::optional eventStartTimeStamp = std::nullopt) = 0; /* * Called when event starts getting dispatched (processed by the handlers, if diff --git a/packages/react-native/ReactCommon/react/renderer/core/RawEvent.h b/packages/react-native/ReactCommon/react/renderer/core/RawEvent.h index 817512e5c75..d78cbd11860 100644 --- a/packages/react-native/ReactCommon/react/renderer/core/RawEvent.h +++ b/packages/react-native/ReactCommon/react/renderer/core/RawEvent.h @@ -87,7 +87,7 @@ struct RawEvent { // The client may specify a platform-specific timestamp for the event start // time, for example when MotionEvent was triggered on the Android native // side. - std::optional eventStartTimeStamp = std::nullopt; + std::optional eventStartTimeStamp = std::nullopt; }; } // namespace facebook::react diff --git a/packages/react-native/ReactCommon/react/renderer/core/tests/EventQueueProcessorTest.cpp b/packages/react-native/ReactCommon/react/renderer/core/tests/EventQueueProcessorTest.cpp index 467689efddb..b6ebd6f4905 100644 --- a/packages/react-native/ReactCommon/react/renderer/core/tests/EventQueueProcessorTest.cpp +++ b/packages/react-native/ReactCommon/react/renderer/core/tests/EventQueueProcessorTest.cpp @@ -25,7 +25,7 @@ class MockEventLogger : public EventLogger { EventTag onEventStart( std::string_view /*name*/, SharedEventTarget /*target*/, - std::optional /*eventStartTimeStamp*/) override { + std::optional /*eventStartTimeStamp*/) override { return EMPTY_EVENT_TAG; } void onEventProcessingStart(EventTag /*tag*/) override {} diff --git a/packages/react-native/ReactCommon/react/renderer/observers/events/EventPerformanceLogger.cpp b/packages/react-native/ReactCommon/react/renderer/observers/events/EventPerformanceLogger.cpp index 6dc9680b232..f3665ddddaf 100644 --- a/packages/react-native/ReactCommon/react/renderer/observers/events/EventPerformanceLogger.cpp +++ b/packages/react-native/ReactCommon/react/renderer/observers/events/EventPerformanceLogger.cpp @@ -105,7 +105,7 @@ EventPerformanceLogger::EventPerformanceLogger( EventTag EventPerformanceLogger::onEventStart( std::string_view name, SharedEventTarget target, - std::optional eventStartTimeStamp) { + std::optional eventStartTimeStamp) { auto performanceEntryReporter = performanceEntryReporter_.lock(); if (performanceEntryReporter == nullptr) { return EMPTY_EVENT_TAG; @@ -123,7 +123,7 @@ EventTag EventPerformanceLogger::onEventStart( // The event start timestamp may be provided by the caller in order to // specify the platform specific event start time. - DOMHighResTimeStamp timeStamp = eventStartTimeStamp + HighResTimeStamp timeStamp = eventStartTimeStamp ? *eventStartTimeStamp : performanceEntryReporter->getCurrentTimeStamp(); { @@ -213,7 +213,7 @@ void EventPerformanceLogger::dispatchPendingEventTimingEntries( void EventPerformanceLogger::shadowTreeDidMount( const RootShadowNode::Shared& rootShadowNode, - double mountTime) noexcept { + HighResTimeStamp mountTime) noexcept { auto performanceEntryReporter = performanceEntryReporter_.lock(); if (performanceEntryReporter == nullptr) { return; diff --git a/packages/react-native/ReactCommon/react/renderer/observers/events/EventPerformanceLogger.h b/packages/react-native/ReactCommon/react/renderer/observers/events/EventPerformanceLogger.h index ffa1d01fb79..2addb87f1d6 100644 --- a/packages/react-native/ReactCommon/react/renderer/observers/events/EventPerformanceLogger.h +++ b/packages/react-native/ReactCommon/react/renderer/observers/events/EventPerformanceLogger.h @@ -32,7 +32,7 @@ class EventPerformanceLogger : public EventLogger, EventTag onEventStart( std::string_view name, SharedEventTarget target, - std::optional eventStartTimeStamp = + std::optional eventStartTimeStamp = std::nullopt) override; void onEventProcessingStart(EventTag tag) override; void onEventProcessingEnd(EventTag tag) override; @@ -47,15 +47,15 @@ class EventPerformanceLogger : public EventLogger, void shadowTreeDidMount( const RootShadowNode::Shared& rootShadowNode, - double mountTime) noexcept override; + HighResTimeStamp mountTime) noexcept override; private: struct EventEntry { std::string_view name; SharedEventTarget target{nullptr}; - DOMHighResTimeStamp startTime; - std::optional processingStartTime; - std::optional processingEndTime; + HighResTimeStamp startTime; + std::optional processingStartTime; + std::optional processingEndTime; bool isWaitingForMount{false}; diff --git a/packages/react-native/ReactCommon/react/renderer/observers/intersection/IntersectionObserver.cpp b/packages/react-native/ReactCommon/react/renderer/observers/intersection/IntersectionObserver.cpp index bc8d0c875a5..f7cc94f2a32 100644 --- a/packages/react-native/ReactCommon/react/renderer/observers/intersection/IntersectionObserver.cpp +++ b/packages/react-native/ReactCommon/react/renderer/observers/intersection/IntersectionObserver.cpp @@ -104,7 +104,7 @@ static Float getHighestThresholdCrossed( std::optional IntersectionObserver::updateIntersectionObservation( const RootShadowNode& rootShadowNode, - double time) { + HighResTimeStamp time) { const auto layoutableRootShadowNode = dynamic_cast(&rootShadowNode); @@ -169,7 +169,7 @@ IntersectionObserver::updateIntersectionObservation( std::optional IntersectionObserver::updateIntersectionObservationForSurfaceUnmount( - double time) { + HighResTimeStamp time) { return setNotIntersectingState(Rect{}, Rect{}, Rect{}, time); } @@ -180,7 +180,7 @@ IntersectionObserver::setIntersectingState( const Rect& intersectionRect, Float threshold, Float rootThreshold, - double time) { + HighResTimeStamp time) { auto newState = IntersectionObserverState::Intersecting(threshold, rootThreshold); @@ -206,7 +206,7 @@ IntersectionObserver::setNotIntersectingState( const Rect& rootBoundingRect, const Rect& targetBoundingRect, const Rect& intersectionRect, - double time) { + HighResTimeStamp time) { if (state_ != IntersectionObserverState::NotIntersecting()) { state_ = IntersectionObserverState::NotIntersecting(); IntersectionObserverEntry entry{ diff --git a/packages/react-native/ReactCommon/react/renderer/observers/intersection/IntersectionObserver.h b/packages/react-native/ReactCommon/react/renderer/observers/intersection/IntersectionObserver.h index d5dd24174af..9248c84132e 100644 --- a/packages/react-native/ReactCommon/react/renderer/observers/intersection/IntersectionObserver.h +++ b/packages/react-native/ReactCommon/react/renderer/observers/intersection/IntersectionObserver.h @@ -25,9 +25,7 @@ struct IntersectionObserverEntry { Rect rootRect; Rect intersectionRect; bool isIntersectingAboveThresholds; - // TODO(T156529385) Define `DOMHighResTimeStamp` as an alias for `double` and - // use it here. - double time; + HighResTimeStamp time; bool sameShadowNodeFamily( const ShadowNodeFamily& otherShadowNodeFamily) const { @@ -48,10 +46,10 @@ class IntersectionObserver { // https://w3c.github.io/IntersectionObserver/#update-intersection-observations-algo std::optional updateIntersectionObservation( const RootShadowNode& rootShadowNode, - double time); + HighResTimeStamp time); std::optional - updateIntersectionObservationForSurfaceUnmount(double time); + updateIntersectionObservationForSurfaceUnmount(HighResTimeStamp time); IntersectionObserverObserverId getIntersectionObserverId() const { return intersectionObserverId_; @@ -72,13 +70,13 @@ class IntersectionObserver { const Rect& intersectionRect, Float threshold, Float rootThreshold, - double time); + HighResTimeStamp time); std::optional setNotIntersectingState( const Rect& rootBoundingRect, const Rect& targetBoundingRect, const Rect& intersectionRect, - double time); + HighResTimeStamp time); IntersectionObserverObserverId intersectionObserverId_; ShadowNodeFamily::Shared targetShadowNodeFamily_; diff --git a/packages/react-native/ReactCommon/react/renderer/observers/intersection/IntersectionObserverManager.cpp b/packages/react-native/ReactCommon/react/renderer/observers/intersection/IntersectionObserverManager.cpp index 4725628b898..57ada48e712 100644 --- a/packages/react-native/ReactCommon/react/renderer/observers/intersection/IntersectionObserverManager.cpp +++ b/packages/react-native/ReactCommon/react/renderer/observers/intersection/IntersectionObserverManager.cpp @@ -280,14 +280,14 @@ void IntersectionObserverManager::updateIntersectionObservations( void IntersectionObserverManager::shadowTreeDidMount( const RootShadowNode::Shared& rootShadowNode, - double time) noexcept { + HighResTimeStamp time) noexcept { updateIntersectionObservations( rootShadowNode->getSurfaceId(), rootShadowNode.get(), time); } void IntersectionObserverManager::shadowTreeDidUnmount( SurfaceId surfaceId, - double time) noexcept { + HighResTimeStamp time) noexcept { updateIntersectionObservations(surfaceId, nullptr, time); } @@ -296,7 +296,7 @@ void IntersectionObserverManager::shadowTreeDidUnmount( void IntersectionObserverManager::updateIntersectionObservations( SurfaceId surfaceId, const RootShadowNode* rootShadowNode, - double time) { + HighResTimeStamp time) { TraceSection s("IntersectionObserverManager::updateIntersectionObservations"); std::vector entries; diff --git a/packages/react-native/ReactCommon/react/renderer/observers/intersection/IntersectionObserverManager.h b/packages/react-native/ReactCommon/react/renderer/observers/intersection/IntersectionObserverManager.h index 9331bcfef67..64317bd2d6e 100644 --- a/packages/react-native/ReactCommon/react/renderer/observers/intersection/IntersectionObserverManager.h +++ b/packages/react-native/ReactCommon/react/renderer/observers/intersection/IntersectionObserverManager.h @@ -55,9 +55,10 @@ class IntersectionObserverManager final void shadowTreeDidMount( const RootShadowNode::Shared& rootShadowNode, - double time) noexcept override; + HighResTimeStamp time) noexcept override; - void shadowTreeDidUnmount(SurfaceId surfaceId, double time) noexcept override; + void shadowTreeDidUnmount(SurfaceId surfaceId, HighResTimeStamp time) noexcept + override; private: mutable std::unordered_map< @@ -92,7 +93,7 @@ class IntersectionObserverManager final void updateIntersectionObservations( SurfaceId surfaceId, const RootShadowNode* rootShadowNode, - double time); + HighResTimeStamp time); const IntersectionObserver& getRegisteredIntersectionObserver( SurfaceId surfaceId, diff --git a/packages/react-native/ReactCommon/react/renderer/runtimescheduler/RuntimeScheduler_Modern.cpp b/packages/react-native/ReactCommon/react/renderer/runtimescheduler/RuntimeScheduler_Modern.cpp index 10fef3e9831..fcdb9565edb 100644 --- a/packages/react-native/ReactCommon/react/renderer/runtimescheduler/RuntimeScheduler_Modern.cpp +++ b/packages/react-native/ReactCommon/react/renderer/runtimescheduler/RuntimeScheduler_Modern.cpp @@ -460,12 +460,10 @@ void RuntimeScheduler_Modern::reportLongTasks( return; } - auto checkedDurationMs = - longestPeriodWithoutYieldingOpportunity_.toDOMHighResTimeStamp(); - if (checkedDurationMs >= LONG_TASK_DURATION_THRESHOLD_MS) { - auto durationMs = (endTime - startTime).toDOMHighResTimeStamp(); - auto startTimeMs = startTime.toDOMHighResTimeStamp(); - reporter->reportLongTask(startTimeMs, durationMs); + if (longestPeriodWithoutYieldingOpportunity_ >= + LONG_TASK_DURATION_THRESHOLD) { + auto duration = endTime - startTime; + reporter->reportLongTask(startTime, duration); } } diff --git a/packages/react-native/ReactCommon/react/renderer/runtimescheduler/tests/RuntimeSchedulerTest.cpp b/packages/react-native/ReactCommon/react/renderer/runtimescheduler/tests/RuntimeSchedulerTest.cpp index 0fdff1b072f..6251b5a552b 100644 --- a/packages/react-native/ReactCommon/react/renderer/runtimescheduler/tests/RuntimeSchedulerTest.cpp +++ b/packages/react-native/ReactCommon/react/renderer/runtimescheduler/tests/RuntimeSchedulerTest.cpp @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -1257,8 +1258,9 @@ TEST_P(RuntimeSchedulerTest, reportsLongTasks) { [startTime](const auto& entryDetails) { EXPECT_EQ(entryDetails.entryType, PerformanceEntryType::LONGTASK); EXPECT_EQ( - entryDetails.startTime, startTime.toDOMHighResTimeStamp() + 100); - EXPECT_EQ(entryDetails.duration, 50); + entryDetails.startTime.toDOMHighResTimeStamp(), + startTime.toDOMHighResTimeStamp() + 100); + EXPECT_EQ(entryDetails.duration, HighResDuration::fromMilliseconds(50)); }, entry); } @@ -1344,8 +1346,10 @@ TEST_P(RuntimeSchedulerTest, reportsLongTasksWithYielding) { [startTime](const auto& entryDetails) { EXPECT_EQ(entryDetails.entryType, PerformanceEntryType::LONGTASK); EXPECT_EQ( - entryDetails.startTime, startTime.toDOMHighResTimeStamp() + 100); - EXPECT_EQ(entryDetails.duration, 120); + entryDetails.startTime.toDOMHighResTimeStamp(), + startTime.toDOMHighResTimeStamp() + 100); + EXPECT_EQ( + entryDetails.duration, HighResDuration::fromMilliseconds(120)); }, entry); } diff --git a/packages/react-native/ReactCommon/react/renderer/uimanager/UIManagerMountHook.h b/packages/react-native/ReactCommon/react/renderer/uimanager/UIManagerMountHook.h index 3e5627b53eb..1a014411d85 100644 --- a/packages/react-native/ReactCommon/react/renderer/uimanager/UIManagerMountHook.h +++ b/packages/react-native/ReactCommon/react/renderer/uimanager/UIManagerMountHook.h @@ -26,11 +26,11 @@ class UIManagerMountHook { */ virtual void shadowTreeDidMount( const RootShadowNode::Shared& rootShadowNode, - double mountTime) noexcept = 0; + HighResTimeStamp mountTime) noexcept = 0; virtual void shadowTreeDidUnmount( SurfaceId /*surfaceId*/, - double /*unmountTime*/) noexcept { + HighResTimeStamp /*unmountTime*/) noexcept { // Default no-op implementation for backwards compatibility. } diff --git a/packages/react-native/ReactCommon/react/timing/primitives.h b/packages/react-native/ReactCommon/react/timing/primitives.h index 91e5c33ed57..9c3be8990b8 100644 --- a/packages/react-native/ReactCommon/react/timing/primitives.h +++ b/packages/react-native/ReactCommon/react/timing/primitives.h @@ -11,23 +11,6 @@ namespace facebook::react { -// `DOMHighResTimeStamp` represents a time value in milliseconds (time point or -// duration), with sub-millisecond precision. -// On the Web, the precision can be reduced for security purposes, but that is -// not necessary in React Native. -using DOMHighResTimeStamp = double; - -inline DOMHighResTimeStamp chronoToDOMHighResTimeStamp( - std::chrono::steady_clock::duration duration) { - return static_cast>(duration) - .count(); -} - -inline DOMHighResTimeStamp chronoToDOMHighResTimeStamp( - std::chrono::steady_clock::time_point timePoint) { - return chronoToDOMHighResTimeStamp(timePoint.time_since_epoch()); -} - class HighResDuration; class HighResTimeStamp; diff --git a/packages/react-native/ReactCommon/react/timing/tests/PrimitivesTest.cpp b/packages/react-native/ReactCommon/react/timing/tests/PrimitivesTest.cpp index be1751c2bff..f94a379c036 100644 --- a/packages/react-native/ReactCommon/react/timing/tests/PrimitivesTest.cpp +++ b/packages/react-native/ReactCommon/react/timing/tests/PrimitivesTest.cpp @@ -11,39 +11,6 @@ namespace facebook::react { -using Clock = std::chrono::steady_clock; -using TimePoint = std::chrono::time_point; - -TEST(chronoToDOMHighResTimeStamp, withDurations) { - EXPECT_EQ(chronoToDOMHighResTimeStamp(std::chrono::nanoseconds(10)), 0.00001); - EXPECT_EQ(chronoToDOMHighResTimeStamp(std::chrono::microseconds(10)), 0.01); - EXPECT_EQ(chronoToDOMHighResTimeStamp(std::chrono::milliseconds(10)), 10.0); - EXPECT_EQ(chronoToDOMHighResTimeStamp(std::chrono::seconds(10)), 10000.0); - EXPECT_EQ( - chronoToDOMHighResTimeStamp( - std::chrono::seconds(1) + std::chrono::nanoseconds(20)), - 1000.000020); -} - -TEST(chronoToDOMHighResTimeStamp, withTimePoints) { - EXPECT_EQ( - chronoToDOMHighResTimeStamp(TimePoint(std::chrono::nanoseconds(10))), - 0.00001); - EXPECT_EQ( - chronoToDOMHighResTimeStamp(TimePoint(std::chrono::microseconds(10))), - 0.01); - EXPECT_EQ( - chronoToDOMHighResTimeStamp(TimePoint(std::chrono::milliseconds(10))), - 10.0); - EXPECT_EQ( - chronoToDOMHighResTimeStamp(TimePoint(std::chrono::seconds(10))), - 10000.0); - EXPECT_EQ( - chronoToDOMHighResTimeStamp( - TimePoint(std::chrono::seconds(1) + std::chrono::nanoseconds(20))), - 1000.000020); -} - TEST(HighResDuration, CorrectlyConvertsToDOMHighResTimeStamp) { EXPECT_EQ( HighResDuration::fromNanoseconds(10).toDOMHighResTimeStamp(), 0.00001); diff --git a/packages/react-native/ReactCommon/reactperflogger/reactperflogger/HermesPerfettoDataSource.cpp b/packages/react-native/ReactCommon/reactperflogger/reactperflogger/HermesPerfettoDataSource.cpp index c51d6a7a778..1ae283d7f50 100644 --- a/packages/react-native/ReactCommon/reactperflogger/reactperflogger/HermesPerfettoDataSource.cpp +++ b/packages/react-native/ReactCommon/reactperflogger/reactperflogger/HermesPerfettoDataSource.cpp @@ -113,7 +113,7 @@ void HermesPerfettoDataSource::OnStart(const StartArgs&) { "react-native", perfetto::DynamicString{"Profiling Started"}, getPerfettoWebPerfTrackSync("JS Sampling"), - performanceNowToPerfettoTraceTime(0)); + perfetto::TrackEvent::GetTraceTimeNs()); } void HermesPerfettoDataSource::OnFlush(const FlushArgs&) { diff --git a/packages/react-native/ReactCommon/reactperflogger/reactperflogger/ReactPerfetto.cpp b/packages/react-native/ReactCommon/reactperflogger/reactperflogger/ReactPerfetto.cpp index a0786d4c649..c280ad4ca08 100644 --- a/packages/react-native/ReactCommon/reactperflogger/reactperflogger/ReactPerfetto.cpp +++ b/packages/react-native/ReactCommon/reactperflogger/reactperflogger/ReactPerfetto.cpp @@ -80,13 +80,17 @@ perfetto::Track getPerfettoWebPerfTrackAsync(const std::string& trackName) { } // Perfetto's monotonic clock seems to match the std::chrono::steady_clock we -// use in JSExecutor::performanceNow on Android platforms, but if that +// use in HighResTimeStamp on Android platforms, but if that // assumption is incorrect we may need to manually offset perfetto timestamps. -uint64_t performanceNowToPerfettoTraceTime(double perfNowTime) { - if (perfNowTime == 0) { - return perfetto::TrackEvent::GetTraceTimeNs(); - } - return static_cast(perfNowTime * 1.e6); +uint64_t highResTimeStampToPerfettoTraceTime(HighResTimeStamp timestamp) { + auto chronoDurationSinceSteadyClockEpoch = + timestamp.toChronoSteadyClockTimePoint().time_since_epoch(); + auto nanoseconds = std::chrono::duration_cast( + chronoDurationSinceSteadyClockEpoch); + + return std::chrono::duration_cast>( + nanoseconds) + .count(); } } // namespace facebook::react diff --git a/packages/react-native/ReactCommon/reactperflogger/reactperflogger/ReactPerfetto.h b/packages/react-native/ReactCommon/reactperflogger/reactperflogger/ReactPerfetto.h index c01ac604c89..c46ff051c53 100644 --- a/packages/react-native/ReactCommon/reactperflogger/reactperflogger/ReactPerfetto.h +++ b/packages/react-native/ReactCommon/reactperflogger/reactperflogger/ReactPerfetto.h @@ -10,6 +10,7 @@ #ifdef WITH_PERFETTO #include +#include #include #include @@ -20,7 +21,7 @@ void initializePerfetto(); perfetto::Track getPerfettoWebPerfTrackSync(const std::string& trackName); perfetto::Track getPerfettoWebPerfTrackAsync(const std::string& trackName); -uint64_t performanceNowToPerfettoTraceTime(double perfNowTime); +uint64_t highResTimeStampToPerfettoTraceTime(HighResTimeStamp timestamp); } // namespace facebook::react diff --git a/packages/react-native/ReactCommon/reactperflogger/reactperflogger/ReactPerfettoLogger.cpp b/packages/react-native/ReactCommon/reactperflogger/reactperflogger/ReactPerfettoLogger.cpp index c895334b7c5..d021a912d49 100644 --- a/packages/react-native/ReactCommon/reactperflogger/reactperflogger/ReactPerfettoLogger.cpp +++ b/packages/react-native/ReactCommon/reactperflogger/reactperflogger/ReactPerfettoLogger.cpp @@ -13,8 +13,6 @@ #include #endif -#include - namespace facebook::react { namespace { @@ -30,10 +28,9 @@ std::string toPerfettoTrackName( : PERFETTO_DEFAULT_TRACK_NAME; } #elif defined(WITH_FBSYSTRACE) -int64_t getDeltaNanos(double jsTime) { - auto now = std::chrono::steady_clock::now().time_since_epoch(); - return static_cast(jsTime * 1.e6) - - std::chrono::duration_cast(now).count(); +int64_t getDeltaNanos(HighResTimeStamp jsTime) { + auto now = HighResTimeStamp::now(); + return (jsTime - now).toNanoseconds(); } #endif @@ -51,8 +48,8 @@ int64_t getDeltaNanos(double jsTime) { /* static */ void ReactPerfettoLogger::measure( const std::string_view& eventName, - double startTime, - double endTime, + HighResTimeStamp startTime, + HighResTimeStamp endTime, const std::optional& trackName) { #if defined(WITH_PERFETTO) if (TRACE_EVENT_CATEGORY_ENABLED("react-native")) { @@ -61,9 +58,9 @@ int64_t getDeltaNanos(double jsTime) { "react-native", perfetto::DynamicString(eventName.data(), eventName.size()), track, - performanceNowToPerfettoTraceTime(startTime)); + highResTimeStampToPerfettoTraceTime(startTime)); TRACE_EVENT_END( - "react-native", track, performanceNowToPerfettoTraceTime(endTime)); + "react-native", track, highResTimeStampToPerfettoTraceTime(endTime)); } #elif defined(WITH_FBSYSTRACE) static int cookie = 0; @@ -77,7 +74,7 @@ int64_t getDeltaNanos(double jsTime) { /* static */ void ReactPerfettoLogger::mark( const std::string_view& eventName, - double startTime, + HighResTimeStamp startTime, const std::optional& trackName) { #if defined(WITH_PERFETTO) if (TRACE_EVENT_CATEGORY_ENABLED("react-native")) { @@ -85,7 +82,7 @@ int64_t getDeltaNanos(double jsTime) { "react-native", perfetto::DynamicString(eventName.data(), eventName.size()), getPerfettoWebPerfTrackSync(toPerfettoTrackName(trackName)), - performanceNowToPerfettoTraceTime(startTime)); + highResTimeStampToPerfettoTraceTime(startTime)); } #elif defined(WITH_FBSYSTRACE) static const char* kTrackName = "# Web Performance: Markers"; diff --git a/packages/react-native/ReactCommon/reactperflogger/reactperflogger/ReactPerfettoLogger.h b/packages/react-native/ReactCommon/reactperflogger/reactperflogger/ReactPerfettoLogger.h index a85d06a5b39..7206d679fab 100644 --- a/packages/react-native/ReactCommon/reactperflogger/reactperflogger/ReactPerfettoLogger.h +++ b/packages/react-native/ReactCommon/reactperflogger/reactperflogger/ReactPerfettoLogger.h @@ -7,6 +7,7 @@ #pragma once +#include #include #include @@ -24,13 +25,13 @@ class ReactPerfettoLogger { static void mark( const std::string_view& eventName, - double startTime, + HighResTimeStamp startTime, const std::optional& trackName); static void measure( const std::string_view& eventName, - double startTime, - double endTime, + HighResTimeStamp startTime, + HighResTimeStamp endTime, const std::optional& trackName); };