mirror of
https://github.com/facebook/react-native.git
synced 2025-11-01 09:14:26 +00:00
Replace DOMHighResTimeStamp alias in ReactCommon with new abstractions (#51512)
Summary: Pull Request resolved: https://github.com/facebook/react-native/pull/51512 Pull Request resolved: https://github.com/facebook/react-native/pull/50585 # Changelog: [Internal] Replaces `DOMHighResTimeStamp` alias completely in `ReactCommon` with `HighResTimeStamp`. `DOMHighResTimeStamp` as a type is now expected to be used only in JavaScript. I didn't update places where we explcitly use `std::chrono::high_resolution_clock`, since it is platform-specific and there is no guarantee that `std::chrono::high_resolution_clock` == `std::chrono::steady_clock`. Also, places that are isolated and not part of the Web Performance APIs, such as Telemetry for Fabric, are not updates as part of this diff. Although these subsystems are also using `std::chrono::steady_clock` as a low-level representation, they are not sharing it with other parts of the React Native core. Reviewed By: rubennorte Differential Revision: D75185613 fbshipit-source-id: 889719368de163e6f529689df6cc16d816fde66c
This commit is contained in:
committed by
Facebook GitHub Bot
parent
aa7202861f
commit
f03268b896
@@ -10,10 +10,8 @@
|
||||
#include "RAMBundleRegistry.h"
|
||||
|
||||
#include <jsinspector-modern/ReactCdp.h>
|
||||
#include <react/timing/primitives.h>
|
||||
|
||||
#include <array>
|
||||
#include <chrono>
|
||||
|
||||
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&
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#include <folly/dynamic.h>
|
||||
#include <jsinspector-modern/InspectorInterfaces.h>
|
||||
#include <jsinspector-modern/ReactCdp.h>
|
||||
#include <react/timing/primitives.h>
|
||||
|
||||
#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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -78,7 +78,7 @@ void NetworkReporter::reportRequestStart(
|
||||
int encodedDataLength,
|
||||
const std::optional<ResponseInfo>& 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
|
||||
{
|
||||
|
||||
@@ -35,11 +35,11 @@ using FrontendChannel = std::function<void(std::string_view messageJson)>;
|
||||
*/
|
||||
struct ResourceTimingData {
|
||||
std::string url;
|
||||
DOMHighResTimeStamp fetchStart;
|
||||
DOMHighResTimeStamp requestStart;
|
||||
std::optional<DOMHighResTimeStamp> connectStart;
|
||||
std::optional<DOMHighResTimeStamp> connectEnd;
|
||||
std::optional<DOMHighResTimeStamp> responseStart;
|
||||
HighResTimeStamp fetchStart;
|
||||
HighResTimeStamp requestStart;
|
||||
std::optional<HighResTimeStamp> connectStart;
|
||||
std::optional<HighResTimeStamp> connectEnd;
|
||||
std::optional<HighResTimeStamp> responseStart;
|
||||
std::optional<int> responseStatus;
|
||||
};
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include "EventLoopReporter.h"
|
||||
|
||||
#if defined(REACT_NATIVE_DEBUGGER_ENABLED)
|
||||
#include <react/timing/primitives.h>
|
||||
#include "PerformanceTracer.h"
|
||||
#endif
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include "Timing.h"
|
||||
|
||||
#include <oscompat/OSCompat.h>
|
||||
#include <react/timing/primitives.h>
|
||||
|
||||
#include <folly/json.h>
|
||||
|
||||
|
||||
@@ -13,6 +13,8 @@
|
||||
|
||||
#include <react/timing/primitives.h>
|
||||
|
||||
#include <react/timing/primitives.h>
|
||||
|
||||
#include <folly/dynamic.h>
|
||||
#include <functional>
|
||||
#include <mutex>
|
||||
|
||||
@@ -784,7 +784,7 @@ TEST_F(BridgingTest, highResTimeStampTest) {
|
||||
bridging::fromJs<HighResTimeStamp>(
|
||||
rt, bridging::toJs(rt, timestamp), invoker));
|
||||
|
||||
HighResDuration duration = HighResDuration::fromNanoseconds(1);
|
||||
auto duration = HighResDuration::fromNanoseconds(1);
|
||||
EXPECT_EQ(
|
||||
duration,
|
||||
bridging::fromJs<HighResDuration>(
|
||||
|
||||
+1
-1
@@ -49,7 +49,7 @@ using NativeIntersectionObserverEntry =
|
||||
// isIntersectingAboveThresholds
|
||||
bool,
|
||||
// time
|
||||
double>;
|
||||
HighResTimeStamp>;
|
||||
|
||||
template <>
|
||||
struct Bridging<NativeIntersectionObserverEntry>
|
||||
|
||||
+12
-10
@@ -116,30 +116,31 @@ std::shared_ptr<PerformanceObserver> tryGetObserver(
|
||||
NativePerformance::NativePerformance(std::shared_ptr<CallInvoker> 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<double> startTime) {
|
||||
std::optional<HighResTimeStamp> startTime) {
|
||||
auto entry =
|
||||
PerformanceEntryReporter::getInstance()->reportMark(name, startTime);
|
||||
return entry.startTime;
|
||||
}
|
||||
|
||||
std::tuple<double, double> NativePerformance::measureWithResult(
|
||||
std::tuple<HighResTimeStamp, HighResDuration>
|
||||
NativePerformance::measureWithResult(
|
||||
jsi::Runtime& runtime,
|
||||
std::string name,
|
||||
double startTime,
|
||||
double endTime,
|
||||
std::optional<double> duration,
|
||||
HighResTimeStamp startTime,
|
||||
HighResTimeStamp endTime,
|
||||
std::optional<HighResDuration> duration,
|
||||
std::optional<std::string> startMark,
|
||||
std::optional<std::string> 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<double, double> 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()) {
|
||||
|
||||
+18
-18
@@ -32,7 +32,7 @@ using NativePerformancePerformanceObserverObserveOptions =
|
||||
// buffered
|
||||
std::optional<bool>,
|
||||
// durationThreshold
|
||||
std::optional<double>>;
|
||||
std::optional<HighResDuration>>;
|
||||
|
||||
template <>
|
||||
struct Bridging<PerformanceEntryType> {
|
||||
@@ -52,21 +52,21 @@ struct Bridging<PerformanceEntryType> {
|
||||
struct NativePerformanceEntry {
|
||||
std::string name;
|
||||
PerformanceEntryType entryType;
|
||||
DOMHighResTimeStamp startTime;
|
||||
DOMHighResTimeStamp duration;
|
||||
HighResTimeStamp startTime;
|
||||
HighResDuration duration;
|
||||
|
||||
// For PerformanceEventTiming only
|
||||
std::optional<DOMHighResTimeStamp> processingStart;
|
||||
std::optional<DOMHighResTimeStamp> processingEnd;
|
||||
std::optional<HighResTimeStamp> processingStart;
|
||||
std::optional<HighResTimeStamp> processingEnd;
|
||||
std::optional<PerformanceEntryInteractionId> interactionId;
|
||||
|
||||
// For PerformanceResourceTiming only
|
||||
std::optional<DOMHighResTimeStamp> fetchStart;
|
||||
std::optional<DOMHighResTimeStamp> requestStart;
|
||||
std::optional<DOMHighResTimeStamp> connectStart;
|
||||
std::optional<DOMHighResTimeStamp> connectEnd;
|
||||
std::optional<DOMHighResTimeStamp> responseStart;
|
||||
std::optional<DOMHighResTimeStamp> responseEnd;
|
||||
std::optional<HighResTimeStamp> fetchStart;
|
||||
std::optional<HighResTimeStamp> requestStart;
|
||||
std::optional<HighResTimeStamp> connectStart;
|
||||
std::optional<HighResTimeStamp> connectEnd;
|
||||
std::optional<HighResTimeStamp> responseStart;
|
||||
std::optional<HighResTimeStamp> responseEnd;
|
||||
std::optional<int> responseStatus;
|
||||
};
|
||||
|
||||
@@ -86,23 +86,23 @@ class NativePerformance : public NativePerformanceCxxSpec<NativePerformance> {
|
||||
#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<double> startTime);
|
||||
std::optional<HighResTimeStamp> startTime);
|
||||
|
||||
// https://w3c.github.io/user-timing/#measure-method
|
||||
std::tuple<double, double> measureWithResult(
|
||||
std::tuple<HighResTimeStamp, HighResDuration> measureWithResult(
|
||||
jsi::Runtime& rt,
|
||||
std::string name,
|
||||
double startTime,
|
||||
double endTime,
|
||||
std::optional<double> duration,
|
||||
HighResTimeStamp startTime,
|
||||
HighResTimeStamp endTime,
|
||||
std::optional<HighResDuration> duration,
|
||||
std::optional<std::string> startMark,
|
||||
std::optional<std::string> endMark);
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <react/timing/primitives.h>
|
||||
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <variant>
|
||||
@@ -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<DOMHighResTimeStamp> connectStart;
|
||||
std::optional<DOMHighResTimeStamp> connectEnd;
|
||||
std::optional<DOMHighResTimeStamp> responseStart;
|
||||
HighResTimeStamp fetchStart;
|
||||
HighResTimeStamp requestStart;
|
||||
std::optional<HighResTimeStamp> connectStart;
|
||||
std::optional<HighResTimeStamp> connectEnd;
|
||||
std::optional<HighResTimeStamp> responseStart;
|
||||
/** Aligns with `duration`. */
|
||||
std::optional<DOMHighResTimeStamp> responseEnd;
|
||||
std::optional<HighResTimeStamp> responseEnd;
|
||||
std::optional<int> responseStatus;
|
||||
};
|
||||
|
||||
|
||||
+2
-2
@@ -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;
|
||||
|
||||
+21
-30
@@ -37,10 +37,6 @@ std::vector<PerformanceEntryType> 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<PerformanceEntryType>
|
||||
@@ -173,7 +169,7 @@ void PerformanceEntryReporter::clearEntries(
|
||||
|
||||
PerformanceMark PerformanceEntryReporter::reportMark(
|
||||
const std::string& name,
|
||||
const std::optional<DOMHighResTimeStamp>& startTime) {
|
||||
const std::optional<HighResTimeStamp>& 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<jsinspector_modern::DevToolsTrackEntryPayload>&
|
||||
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<DOMHighResTimeStamp> PerformanceEntryReporter::getMarkTime(
|
||||
std::optional<HighResTimeStamp> PerformanceEntryReporter::getMarkTime(
|
||||
const std::string& markName) const {
|
||||
std::shared_lock lock(buffersMutex_);
|
||||
|
||||
@@ -231,10 +227,10 @@ std::optional<DOMHighResTimeStamp> 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<DOMHighResTimeStamp> connectStart,
|
||||
std::optional<DOMHighResTimeStamp> connectEnd,
|
||||
DOMHighResTimeStamp responseStart,
|
||||
DOMHighResTimeStamp responseEnd,
|
||||
HighResTimeStamp fetchStart,
|
||||
HighResTimeStamp requestStart,
|
||||
std::optional<HighResTimeStamp> connectStart,
|
||||
std::optional<HighResTimeStamp> connectEnd,
|
||||
HighResTimeStamp responseStart,
|
||||
HighResTimeStamp responseEnd,
|
||||
const std::optional<int>& 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()) {
|
||||
|
||||
+21
-19
@@ -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<DOMHighResTimeStamp()> provider) {
|
||||
void setTimeStampProvider(std::function<HighResTimeStamp()> provider) {
|
||||
timeStampProvider_ = std::move(provider);
|
||||
}
|
||||
|
||||
@@ -80,37 +81,38 @@ class PerformanceEntryReporter {
|
||||
return eventCounts_;
|
||||
}
|
||||
|
||||
std::optional<double> getMarkTime(const std::string& markName) const;
|
||||
std::optional<HighResTimeStamp> getMarkTime(
|
||||
const std::string& markName) const;
|
||||
|
||||
PerformanceMark reportMark(
|
||||
const std::string& name,
|
||||
const std::optional<DOMHighResTimeStamp>& startTime = std::nullopt);
|
||||
const std::optional<HighResTimeStamp>& startTime = std::nullopt);
|
||||
|
||||
PerformanceMeasure reportMeasure(
|
||||
const std::string& name,
|
||||
double startTime,
|
||||
double endTime,
|
||||
HighResTimeStamp startTime,
|
||||
HighResTimeStamp endTime,
|
||||
const std::optional<jsinspector_modern::DevToolsTrackEntryPayload>&
|
||||
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<DOMHighResTimeStamp> connectStart,
|
||||
std::optional<DOMHighResTimeStamp> connectEnd,
|
||||
DOMHighResTimeStamp responseStart,
|
||||
DOMHighResTimeStamp responseEnd,
|
||||
HighResTimeStamp fetchStart,
|
||||
HighResTimeStamp requestStart,
|
||||
std::optional<HighResTimeStamp> connectStart,
|
||||
std::optional<HighResTimeStamp> connectEnd,
|
||||
HighResTimeStamp responseStart,
|
||||
HighResTimeStamp responseEnd,
|
||||
const std::optional<int>& responseStatus);
|
||||
|
||||
private:
|
||||
@@ -126,7 +128,7 @@ class PerformanceEntryReporter {
|
||||
|
||||
std::unordered_map<std::string, uint32_t> eventCounts_;
|
||||
|
||||
std::function<double()> timeStampProvider_ = nullptr;
|
||||
std::function<HighResTimeStamp()> timeStampProvider_ = nullptr;
|
||||
|
||||
const inline PerformanceEntryBuffer& getBuffer(
|
||||
PerformanceEntryType entryType) const {
|
||||
|
||||
@@ -7,12 +7,15 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "PerformanceEntryBuffer.h"
|
||||
#include "PerformanceObserverRegistry.h"
|
||||
|
||||
#include <react/timing/primitives.h>
|
||||
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <unordered_set>
|
||||
#include <vector>
|
||||
#include "PerformanceEntryBuffer.h"
|
||||
#include "PerformanceObserverRegistry.h"
|
||||
|
||||
namespace facebook::react {
|
||||
|
||||
@@ -27,7 +30,7 @@ using PerformanceObserverCallback = std::function<void()>;
|
||||
* 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<PerformanceEntry> buffer_;
|
||||
bool didScheduleFlushBuffer_ = false;
|
||||
bool requiresDroppedEntries_ = false;
|
||||
|
||||
+200
-60
@@ -58,8 +58,10 @@ namespace facebook::react {
|
||||
[&](const auto& entryDetails) -> std::ostream& {
|
||||
os << "{ .name = \"" << entryDetails.name << "\"" << ", .entryType = "
|
||||
<< entryTypeNames[static_cast<int>(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<PerformanceEntry> 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<PerformanceEntry> 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<PerformanceEntry> 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<PerformanceEntry> 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<PerformanceEntry> 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<PerformanceEntry> 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<PerformanceEntry> 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<PerformanceEntry> 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<PerformanceEntry> 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);
|
||||
}
|
||||
|
||||
+237
-43
@@ -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<PerformanceEntry> 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<PerformanceEntry> 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<PerformanceEntry> 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<PerformanceEntry> 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<PerformanceEntry> 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());
|
||||
|
||||
@@ -34,8 +34,7 @@ class EventLogger {
|
||||
virtual EventTag onEventStart(
|
||||
std::string_view name,
|
||||
SharedEventTarget target,
|
||||
std::optional<DOMHighResTimeStamp> eventStartTimeStamp =
|
||||
std::nullopt) = 0;
|
||||
std::optional<HighResTimeStamp> eventStartTimeStamp = std::nullopt) = 0;
|
||||
|
||||
/*
|
||||
* Called when event starts getting dispatched (processed by the handlers, if
|
||||
|
||||
@@ -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<DOMHighResTimeStamp> eventStartTimeStamp = std::nullopt;
|
||||
std::optional<HighResTimeStamp> eventStartTimeStamp = std::nullopt;
|
||||
};
|
||||
|
||||
} // namespace facebook::react
|
||||
|
||||
+1
-1
@@ -25,7 +25,7 @@ class MockEventLogger : public EventLogger {
|
||||
EventTag onEventStart(
|
||||
std::string_view /*name*/,
|
||||
SharedEventTarget /*target*/,
|
||||
std::optional<DOMHighResTimeStamp> /*eventStartTimeStamp*/) override {
|
||||
std::optional<HighResTimeStamp> /*eventStartTimeStamp*/) override {
|
||||
return EMPTY_EVENT_TAG;
|
||||
}
|
||||
void onEventProcessingStart(EventTag /*tag*/) override {}
|
||||
|
||||
+3
-3
@@ -105,7 +105,7 @@ EventPerformanceLogger::EventPerformanceLogger(
|
||||
EventTag EventPerformanceLogger::onEventStart(
|
||||
std::string_view name,
|
||||
SharedEventTarget target,
|
||||
std::optional<DOMHighResTimeStamp> eventStartTimeStamp) {
|
||||
std::optional<HighResTimeStamp> 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;
|
||||
|
||||
+5
-5
@@ -32,7 +32,7 @@ class EventPerformanceLogger : public EventLogger,
|
||||
EventTag onEventStart(
|
||||
std::string_view name,
|
||||
SharedEventTarget target,
|
||||
std::optional<DOMHighResTimeStamp> eventStartTimeStamp =
|
||||
std::optional<HighResTimeStamp> 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<DOMHighResTimeStamp> processingStartTime;
|
||||
std::optional<DOMHighResTimeStamp> processingEndTime;
|
||||
HighResTimeStamp startTime;
|
||||
std::optional<HighResTimeStamp> processingStartTime;
|
||||
std::optional<HighResTimeStamp> processingEndTime;
|
||||
|
||||
bool isWaitingForMount{false};
|
||||
|
||||
|
||||
+4
-4
@@ -104,7 +104,7 @@ static Float getHighestThresholdCrossed(
|
||||
std::optional<IntersectionObserverEntry>
|
||||
IntersectionObserver::updateIntersectionObservation(
|
||||
const RootShadowNode& rootShadowNode,
|
||||
double time) {
|
||||
HighResTimeStamp time) {
|
||||
const auto layoutableRootShadowNode =
|
||||
dynamic_cast<const LayoutableShadowNode*>(&rootShadowNode);
|
||||
|
||||
@@ -169,7 +169,7 @@ IntersectionObserver::updateIntersectionObservation(
|
||||
|
||||
std::optional<IntersectionObserverEntry>
|
||||
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{
|
||||
|
||||
+5
-7
@@ -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<IntersectionObserverEntry> updateIntersectionObservation(
|
||||
const RootShadowNode& rootShadowNode,
|
||||
double time);
|
||||
HighResTimeStamp time);
|
||||
|
||||
std::optional<IntersectionObserverEntry>
|
||||
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<IntersectionObserverEntry> setNotIntersectingState(
|
||||
const Rect& rootBoundingRect,
|
||||
const Rect& targetBoundingRect,
|
||||
const Rect& intersectionRect,
|
||||
double time);
|
||||
HighResTimeStamp time);
|
||||
|
||||
IntersectionObserverObserverId intersectionObserverId_;
|
||||
ShadowNodeFamily::Shared targetShadowNodeFamily_;
|
||||
|
||||
+3
-3
@@ -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<IntersectionObserverEntry> entries;
|
||||
|
||||
+4
-3
@@ -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,
|
||||
|
||||
+4
-6
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+8
-4
@@ -12,6 +12,7 @@
|
||||
#include <react/featureflags/ReactNativeFeatureFlagsDefaults.h>
|
||||
#include <react/performance/timeline/PerformanceEntryReporter.h>
|
||||
#include <react/renderer/runtimescheduler/RuntimeScheduler.h>
|
||||
#include <chrono>
|
||||
#include <memory>
|
||||
#include <semaphore>
|
||||
#include <variant>
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
}
|
||||
|
||||
|
||||
@@ -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<std::chrono::duration<double, std::milli>>(duration)
|
||||
.count();
|
||||
}
|
||||
|
||||
inline DOMHighResTimeStamp chronoToDOMHighResTimeStamp(
|
||||
std::chrono::steady_clock::time_point timePoint) {
|
||||
return chronoToDOMHighResTimeStamp(timePoint.time_since_epoch());
|
||||
}
|
||||
|
||||
class HighResDuration;
|
||||
class HighResTimeStamp;
|
||||
|
||||
|
||||
@@ -11,39 +11,6 @@
|
||||
|
||||
namespace facebook::react {
|
||||
|
||||
using Clock = std::chrono::steady_clock;
|
||||
using TimePoint = std::chrono::time_point<Clock>;
|
||||
|
||||
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);
|
||||
|
||||
+1
-1
@@ -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&) {
|
||||
|
||||
+10
-6
@@ -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<uint64_t>(perfNowTime * 1.e6);
|
||||
uint64_t highResTimeStampToPerfettoTraceTime(HighResTimeStamp timestamp) {
|
||||
auto chronoDurationSinceSteadyClockEpoch =
|
||||
timestamp.toChronoSteadyClockTimePoint().time_since_epoch();
|
||||
auto nanoseconds = std::chrono::duration_cast<std::chrono::nanoseconds>(
|
||||
chronoDurationSinceSteadyClockEpoch);
|
||||
|
||||
return std::chrono::duration_cast<std::chrono::duration<std::uint64_t>>(
|
||||
nanoseconds)
|
||||
.count();
|
||||
}
|
||||
|
||||
} // namespace facebook::react
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#ifdef WITH_PERFETTO
|
||||
|
||||
#include <perfetto.h>
|
||||
#include <react/timing/primitives.h>
|
||||
#include <reactperflogger/ReactPerfettoCategories.h>
|
||||
#include <string>
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
+9
-12
@@ -13,8 +13,6 @@
|
||||
#include <fbsystrace.h>
|
||||
#endif
|
||||
|
||||
#include <chrono>
|
||||
|
||||
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<int64_t>(jsTime * 1.e6) -
|
||||
std::chrono::duration_cast<std::chrono::nanoseconds>(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<std::string_view>& 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<std::string_view>& 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";
|
||||
|
||||
+4
-3
@@ -7,6 +7,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <react/timing/primitives.h>
|
||||
#include <reactperflogger/ReactPerfettoCategories.h>
|
||||
|
||||
#include <optional>
|
||||
@@ -24,13 +25,13 @@ class ReactPerfettoLogger {
|
||||
|
||||
static void mark(
|
||||
const std::string_view& eventName,
|
||||
double startTime,
|
||||
HighResTimeStamp startTime,
|
||||
const std::optional<std::string_view>& trackName);
|
||||
|
||||
static void measure(
|
||||
const std::string_view& eventName,
|
||||
double startTime,
|
||||
double endTime,
|
||||
HighResTimeStamp startTime,
|
||||
HighResTimeStamp endTime,
|
||||
const std::optional<std::string_view>& trackName);
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user