Revert D72649815: Replace DOMHighResTimeStamp alias in ReactCommon with new abstractions

Differential Revision:
D72649815

Original commit changeset: 96bcfaf909d4

Original Phabricator Diff: D72649815

fbshipit-source-id: 491579e20fed41f0f31639f51d6051022ae9de55
This commit is contained in:
Jiawei Lü
2025-05-21 14:12:16 -07:00
committed by Facebook GitHub Bot
parent cbfa2ecc9a
commit 65ef8fe6b8
38 changed files with 329 additions and 620 deletions
@@ -10,8 +10,10 @@
#include "RAMBundleRegistry.h"
#include <jsinspector-modern/ReactCdp.h>
#include <react/timing/primitives.h>
#include <array>
#include <chrono>
namespace facebook::react {
@@ -27,8 +29,8 @@ std::string JSExecutor::getSyntheticBundlePath(
return buffer.data();
}
HighResTimeStamp JSExecutor::performanceNow() {
return HighResTimeStamp::now();
double JSExecutor::performanceNow() {
return chronoToDOMHighResTimeStamp(std::chrono::steady_clock::now());
}
jsinspector_modern::RuntimeTargetDelegate&
@@ -14,7 +14,6 @@
#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")))
@@ -139,7 +138,7 @@ class RN_EXPORT JSExecutor {
uint32_t bundleId,
const std::string& bundlePath);
static HighResTimeStamp performanceNow();
static double performanceNow();
/**
* Get a reference to the \c RuntimeTargetDelegate owned (or implemented) by
@@ -556,9 +556,7 @@ void bindNativePerformanceNow(Runtime& runtime) {
[](jsi::Runtime& runtime,
const jsi::Value&,
const jsi::Value* args,
size_t /*count*/) {
return JSExecutor::performanceNow().toDOMHighResTimeStamp();
}));
size_t count) { return Value(JSExecutor::performanceNow()); }));
}
} // namespace facebook::react
@@ -78,7 +78,7 @@ void NetworkReporter::reportRequestStart(
int encodedDataLength,
const std::optional<ResponseInfo>& redirectResponse) {
if (ReactNativeFeatureFlags::enableResourceTimingAPI()) {
auto now = PerformanceEntryReporter::getInstance()->getCurrentTimeStamp();
double 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()) {
auto now = PerformanceEntryReporter::getInstance()->getCurrentTimeStamp();
double now = PerformanceEntryReporter::getInstance()->getCurrentTimeStamp();
// All builds: Annotate PerformanceResourceTiming metadata
{
@@ -168,7 +168,7 @@ void NetworkReporter::reportResponseStart(
const ResponseInfo& responseInfo,
int encodedDataLength) {
if (ReactNativeFeatureFlags::enableResourceTimingAPI()) {
auto now = PerformanceEntryReporter::getInstance()->getCurrentTimeStamp();
double 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()) {
auto now = PerformanceEntryReporter::getInstance()->getCurrentTimeStamp();
double 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()) {
auto now = PerformanceEntryReporter::getInstance()->getCurrentTimeStamp();
double 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;
HighResTimeStamp fetchStart;
HighResTimeStamp requestStart;
std::optional<HighResTimeStamp> connectStart;
std::optional<HighResTimeStamp> connectEnd;
std::optional<HighResTimeStamp> responseStart;
DOMHighResTimeStamp fetchStart;
DOMHighResTimeStamp requestStart;
std::optional<DOMHighResTimeStamp> connectStart;
std::optional<DOMHighResTimeStamp> connectEnd;
std::optional<DOMHighResTimeStamp> responseStart;
std::optional<int> responseStatus;
};
@@ -8,7 +8,6 @@
#include "EventLoopReporter.h"
#if defined(REACT_NATIVE_DEBUGGER_ENABLED)
#include <react/timing/primitives.h>
#include "PerformanceTracer.h"
#endif
@@ -9,7 +9,6 @@
#include "Timing.h"
#include <oscompat/OSCompat.h>
#include <react/timing/primitives.h>
#include <folly/json.h>
@@ -13,8 +13,6 @@
#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));
auto duration = HighResDuration::fromNanoseconds(1);
HighResDuration duration = HighResDuration::fromNanoseconds(1);
EXPECT_EQ(
duration,
bridging::fromJs<HighResDuration>(
@@ -51,7 +51,7 @@ using NativeIntersectionObserverEntry =
// isIntersectingAboveThresholds
bool,
// time
HighResTimeStamp>;
double>;
template <>
struct Bridging<NativeIntersectionObserverEntry>
@@ -116,31 +116,30 @@ std::shared_ptr<PerformanceObserver> tryGetObserver(
NativePerformance::NativePerformance(std::shared_ptr<CallInvoker> jsInvoker)
: NativePerformanceCxxSpec(std::move(jsInvoker)) {}
HighResTimeStamp NativePerformance::now(jsi::Runtime& /*rt*/) {
double NativePerformance::now(jsi::Runtime& /*rt*/) {
return JSExecutor::performanceNow();
}
HighResTimeStamp NativePerformance::markWithResult(
double NativePerformance::markWithResult(
jsi::Runtime& rt,
std::string name,
std::optional<HighResTimeStamp> startTime) {
std::optional<double> startTime) {
auto entry =
PerformanceEntryReporter::getInstance()->reportMark(name, startTime);
return entry.startTime;
}
std::tuple<HighResTimeStamp, HighResDuration>
NativePerformance::measureWithResult(
std::tuple<double, double> NativePerformance::measureWithResult(
jsi::Runtime& runtime,
std::string name,
HighResTimeStamp startTime,
HighResTimeStamp endTime,
std::optional<HighResDuration> duration,
double startTime,
double endTime,
std::optional<double> duration,
std::optional<std::string> startMark,
std::optional<std::string> endMark) {
auto reporter = PerformanceEntryReporter::getInstance();
HighResTimeStamp startTimeValue = startTime;
DOMHighResTimeStamp 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) {
@@ -152,7 +151,7 @@ NativePerformance::measureWithResult(
}
}
HighResTimeStamp endTimeValue = endTime;
DOMHighResTimeStamp 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) {
@@ -346,8 +345,7 @@ void NativePerformance::observe(
return;
}
auto durationThreshold =
options.durationThreshold.value_or(HighResDuration::zero());
auto durationThreshold = options.durationThreshold.value_or(0.0);
// observer of type multiple
if (options.entryTypes.has_value()) {
@@ -32,7 +32,7 @@ using NativePerformancePerformanceObserverObserveOptions =
// buffered
std::optional<bool>,
// durationThreshold
std::optional<HighResDuration>>;
std::optional<double>>;
template <>
struct Bridging<PerformanceEntryType> {
@@ -52,21 +52,21 @@ struct Bridging<PerformanceEntryType> {
struct NativePerformanceEntry {
std::string name;
PerformanceEntryType entryType;
HighResTimeStamp startTime;
HighResDuration duration;
DOMHighResTimeStamp startTime;
DOMHighResTimeStamp duration;
// For PerformanceEventTiming only
std::optional<HighResTimeStamp> processingStart;
std::optional<HighResTimeStamp> processingEnd;
std::optional<DOMHighResTimeStamp> processingStart;
std::optional<DOMHighResTimeStamp> processingEnd;
std::optional<PerformanceEntryInteractionId> interactionId;
// For PerformanceResourceTiming only
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<DOMHighResTimeStamp> fetchStart;
std::optional<DOMHighResTimeStamp> requestStart;
std::optional<DOMHighResTimeStamp> connectStart;
std::optional<DOMHighResTimeStamp> connectEnd;
std::optional<DOMHighResTimeStamp> responseStart;
std::optional<DOMHighResTimeStamp> 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
HighResTimeStamp now(jsi::Runtime& rt);
double 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
HighResTimeStamp markWithResult(
double markWithResult(
jsi::Runtime& rt,
std::string name,
std::optional<HighResTimeStamp> startTime);
std::optional<double> startTime);
// https://w3c.github.io/user-timing/#measure-method
std::tuple<HighResTimeStamp, HighResDuration> measureWithResult(
std::tuple<double, double> measureWithResult(
jsi::Runtime& rt,
std::string name,
HighResTimeStamp startTime,
HighResTimeStamp endTime,
std::optional<HighResDuration> duration,
double startTime,
double endTime,
std::optional<double> duration,
std::optional<std::string> startMark,
std::optional<std::string> endMark);
@@ -8,7 +8,6 @@
#pragma once
#include <react/timing/primitives.h>
#include <optional>
#include <string>
#include <variant>
@@ -29,8 +28,8 @@ enum class PerformanceEntryType {
struct AbstractPerformanceEntry {
std::string name;
HighResTimeStamp startTime;
HighResDuration duration = HighResDuration::zero();
DOMHighResTimeStamp startTime;
DOMHighResTimeStamp duration = 0;
};
struct PerformanceMark : AbstractPerformanceEntry {
@@ -44,8 +43,8 @@ struct PerformanceMeasure : AbstractPerformanceEntry {
struct PerformanceEventTiming : AbstractPerformanceEntry {
static constexpr PerformanceEntryType entryType = PerformanceEntryType::EVENT;
HighResTimeStamp processingStart;
HighResTimeStamp processingEnd;
DOMHighResTimeStamp processingStart;
DOMHighResTimeStamp processingEnd;
PerformanceEntryInteractionId interactionId;
};
@@ -58,13 +57,13 @@ struct PerformanceResourceTiming : AbstractPerformanceEntry {
static constexpr PerformanceEntryType entryType =
PerformanceEntryType::RESOURCE;
/** Aligns with `startTime`. */
HighResTimeStamp fetchStart;
HighResTimeStamp requestStart;
std::optional<HighResTimeStamp> connectStart;
std::optional<HighResTimeStamp> connectEnd;
std::optional<HighResTimeStamp> responseStart;
DOMHighResTimeStamp fetchStart;
DOMHighResTimeStamp requestStart;
std::optional<DOMHighResTimeStamp> connectStart;
std::optional<DOMHighResTimeStamp> connectEnd;
std::optional<DOMHighResTimeStamp> responseStart;
/** Aligns with `duration`. */
std::optional<HighResTimeStamp> responseEnd;
std::optional<DOMHighResTimeStamp> responseEnd;
std::optional<int> responseStatus;
};
@@ -14,7 +14,7 @@ namespace facebook::react {
// Default duration threshold for reporting performance entries (0 means "report
// all")
constexpr HighResDuration DEFAULT_DURATION_THRESHOLD = HighResDuration::zero();
constexpr double DEFAULT_DURATION_THRESHOLD = 0.0;
/**
* Abstract performance entry buffer with reporting flags.
@@ -22,7 +22,7 @@ constexpr HighResDuration DEFAULT_DURATION_THRESHOLD = HighResDuration::zero();
*/
class PerformanceEntryBuffer {
public:
HighResDuration durationThreshold = DEFAULT_DURATION_THRESHOLD;
double durationThreshold{DEFAULT_DURATION_THRESHOLD};
size_t droppedEntriesCount{0};
explicit PerformanceEntryBuffer() = default;
@@ -37,6 +37,10 @@ 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
@@ -79,9 +83,9 @@ PerformanceEntryReporter::PerformanceEntryReporter()
#endif
}
HighResTimeStamp PerformanceEntryReporter::getCurrentTimeStamp() const {
DOMHighResTimeStamp PerformanceEntryReporter::getCurrentTimeStamp() const {
return timeStampProvider_ != nullptr ? timeStampProvider_()
: HighResTimeStamp::now();
: performanceNow();
}
std::vector<PerformanceEntryType>
@@ -169,7 +173,7 @@ void PerformanceEntryReporter::clearEntries(
PerformanceMark PerformanceEntryReporter::reportMark(
const std::string& name,
const std::optional<HighResTimeStamp>& startTime) {
const std::optional<DOMHighResTimeStamp>& startTime) {
// Resolve timings
auto startTimeVal = startTime ? *startTime : getCurrentTimeStamp();
const auto entry = PerformanceMark{{.name = name, .startTime = startTimeVal}};
@@ -189,11 +193,11 @@ PerformanceMark PerformanceEntryReporter::reportMark(
PerformanceMeasure PerformanceEntryReporter::reportMeasure(
const std::string& name,
HighResTimeStamp startTime,
HighResTimeStamp endTime,
DOMHighResTimeStamp startTime,
DOMHighResTimeStamp endTime,
const std::optional<jsinspector_modern::DevToolsTrackEntryPayload>&
trackMetadata) {
HighResDuration duration = endTime - startTime;
DOMHighResTimeStamp duration = endTime - startTime;
const auto entry = PerformanceMeasure{
{.name = std::string(name),
@@ -213,7 +217,7 @@ PerformanceMeasure PerformanceEntryReporter::reportMeasure(
return entry;
}
std::optional<HighResTimeStamp> PerformanceEntryReporter::getMarkTime(
std::optional<DOMHighResTimeStamp> PerformanceEntryReporter::getMarkTime(
const std::string& markName) const {
std::shared_lock lock(buffersMutex_);
@@ -227,10 +231,10 @@ std::optional<HighResTimeStamp> PerformanceEntryReporter::getMarkTime(
void PerformanceEntryReporter::reportEvent(
std::string name,
HighResTimeStamp startTime,
HighResDuration duration,
HighResTimeStamp processingStart,
HighResTimeStamp processingEnd,
DOMHighResTimeStamp startTime,
DOMHighResTimeStamp duration,
DOMHighResTimeStamp processingStart,
DOMHighResTimeStamp processingEnd,
uint32_t interactionId) {
eventCounts_[name]++;
@@ -256,8 +260,8 @@ void PerformanceEntryReporter::reportEvent(
}
void PerformanceEntryReporter::reportLongTask(
HighResTimeStamp startTime,
HighResDuration duration) {
DOMHighResTimeStamp startTime,
DOMHighResTimeStamp duration) {
const auto entry = PerformanceLongTaskTiming{
{.name = std::string{"self"},
.startTime = startTime,
@@ -273,12 +277,12 @@ void PerformanceEntryReporter::reportLongTask(
PerformanceResourceTiming PerformanceEntryReporter::reportResourceTiming(
const std::string& url,
HighResTimeStamp fetchStart,
HighResTimeStamp requestStart,
std::optional<HighResTimeStamp> connectStart,
std::optional<HighResTimeStamp> connectEnd,
HighResTimeStamp responseStart,
HighResTimeStamp responseEnd,
DOMHighResTimeStamp fetchStart,
DOMHighResTimeStamp requestStart,
std::optional<DOMHighResTimeStamp> connectStart,
std::optional<DOMHighResTimeStamp> connectEnd,
DOMHighResTimeStamp responseStart,
DOMHighResTimeStamp responseEnd,
const std::optional<int>& responseStatus) {
const auto entry = PerformanceResourceTiming{
{.name = url, .startTime = fetchStart},
@@ -309,7 +313,9 @@ void PerformanceEntryReporter::traceMark(const PerformanceMark& entry) const {
auto [trackName, eventName] = parseTrackName(entry.name);
if (performanceTracer.isTracing()) {
performanceTracer.reportMark(entry.name, entry.startTime);
performanceTracer.reportMark(
entry.name,
HighResTimeStamp::fromDOMHighResTimeStamp(entry.startTime));
}
if (ReactPerfettoLogger::isTracing()) {
@@ -333,7 +339,10 @@ void PerformanceEntryReporter::traceMeasure(
trackMetadata = {.track = trackName.value()};
}
performanceTracer.reportMeasure(
eventName, entry.startTime, entry.duration, trackMetadata);
eventName,
HighResTimeStamp::fromDOMHighResTimeStamp(entry.startTime),
HighResDuration::fromDOMHighResTimeStamp(entry.duration),
trackMetadata);
}
if (ReactPerfettoLogger::isTracing()) {
@@ -27,8 +27,7 @@ constexpr size_t EVENT_BUFFER_SIZE = 150;
constexpr size_t LONG_TASK_BUFFER_SIZE = 200;
constexpr size_t RESOURCE_TIMING_BUFFER_SIZE = 250;
constexpr HighResDuration LONG_TASK_DURATION_THRESHOLD =
HighResDuration::fromMilliseconds(50);
constexpr DOMHighResTimeStamp LONG_TASK_DURATION_THRESHOLD_MS = 50.0;
class PerformanceEntryReporter {
public:
@@ -67,9 +66,9 @@ class PerformanceEntryReporter {
PerformanceEntryType entryType,
const std::string& entryName);
HighResTimeStamp getCurrentTimeStamp() const;
DOMHighResTimeStamp getCurrentTimeStamp() const;
void setTimeStampProvider(std::function<HighResTimeStamp()> provider) {
void setTimeStampProvider(std::function<DOMHighResTimeStamp()> provider) {
timeStampProvider_ = std::move(provider);
}
@@ -81,38 +80,37 @@ class PerformanceEntryReporter {
return eventCounts_;
}
std::optional<HighResTimeStamp> getMarkTime(
const std::string& markName) const;
std::optional<double> getMarkTime(const std::string& markName) const;
PerformanceMark reportMark(
const std::string& name,
const std::optional<HighResTimeStamp>& startTime = std::nullopt);
const std::optional<DOMHighResTimeStamp>& startTime = std::nullopt);
PerformanceMeasure reportMeasure(
const std::string& name,
HighResTimeStamp startTime,
HighResTimeStamp endTime,
double startTime,
double endTime,
const std::optional<jsinspector_modern::DevToolsTrackEntryPayload>&
trackMetadata = std::nullopt);
void reportEvent(
std::string name,
HighResTimeStamp startTime,
HighResDuration duration,
HighResTimeStamp processingStart,
HighResTimeStamp processingEnd,
double startTime,
double duration,
double processingStart,
double processingEnd,
uint32_t interactionId);
void reportLongTask(HighResTimeStamp startTime, HighResDuration duration);
void reportLongTask(double startTime, double duration);
PerformanceResourceTiming reportResourceTiming(
const std::string& url,
HighResTimeStamp fetchStart,
HighResTimeStamp requestStart,
std::optional<HighResTimeStamp> connectStart,
std::optional<HighResTimeStamp> connectEnd,
HighResTimeStamp responseStart,
HighResTimeStamp responseEnd,
DOMHighResTimeStamp fetchStart,
DOMHighResTimeStamp requestStart,
std::optional<DOMHighResTimeStamp> connectStart,
std::optional<DOMHighResTimeStamp> connectEnd,
DOMHighResTimeStamp responseStart,
DOMHighResTimeStamp responseEnd,
const std::optional<int>& responseStatus);
private:
@@ -128,7 +126,7 @@ class PerformanceEntryReporter {
std::unordered_map<std::string, uint32_t> eventCounts_;
std::function<HighResTimeStamp()> timeStampProvider_ = nullptr;
std::function<double()> timeStampProvider_ = nullptr;
const inline PerformanceEntryBuffer& getBuffer(
PerformanceEntryType entryType) const {
@@ -7,15 +7,12 @@
#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 {
@@ -30,7 +27,7 @@ using PerformanceObserverCallback = std::function<void()>;
* https://w3c.github.io/performance-timeline/#performanceobserverinit-dictionary
*/
struct PerformanceObserverObserveMultipleOptions {
HighResDuration durationThreshold = DEFAULT_DURATION_THRESHOLD;
double durationThreshold = 0.0;
};
/**
@@ -41,7 +38,7 @@ struct PerformanceObserverObserveMultipleOptions {
*/
struct PerformanceObserverObserveSingleOptions {
bool buffered = false;
HighResDuration durationThreshold = DEFAULT_DURATION_THRESHOLD;
double durationThreshold = 0.0;
};
/**
@@ -127,7 +124,7 @@ class PerformanceObserver
PerformanceObserverEntryTypeFilter observedTypes_;
/// https://www.w3.org/TR/event-timing/#sec-modifications-perf-timeline
HighResDuration durationThreshold_ = DEFAULT_DURATION_THRESHOLD;
double durationThreshold_{DEFAULT_DURATION_THRESHOLD};
std::vector<PerformanceEntry> buffer_;
bool didScheduleFlushBuffer_ = false;
bool requiresDroppedEntries_ = false;
@@ -58,10 +58,8 @@ namespace facebook::react {
[&](const auto& entryDetails) -> std::ostream& {
os << "{ .name = \"" << entryDetails.name << "\"" << ", .entryType = "
<< entryTypeNames[static_cast<int>(entryDetails.entryType) - 1]
<< ", .startTime = "
<< entryDetails.startTime.toDOMHighResTimeStamp()
<< ", .duration = " << entryDetails.duration.toDOMHighResTimeStamp()
<< " }";
<< ", .startTime = " << entryDetails.startTime
<< ", .duration = " << entryDetails.duration << " }";
return os;
},
entry);
@@ -79,116 +77,60 @@ std::vector<PerformanceEntry> toSorted(
TEST(PerformanceEntryReporter, PerformanceEntryReporterTestReportMarks) {
auto reporter = PerformanceEntryReporter::getInstance();
auto timeOrigin = HighResTimeStamp::now();
reporter->clearEntries();
reporter->reportMark("mark0", timeOrigin);
reporter->reportMark(
"mark1", timeOrigin + HighResDuration::fromMilliseconds(1));
reporter->reportMark(
"mark2", timeOrigin + HighResDuration::fromMilliseconds(2));
reporter->reportMark("mark0", 0);
reporter->reportMark("mark1", 1);
reporter->reportMark("mark2", 2);
// Report mark0 again
reporter->reportMark(
"mark0", timeOrigin + HighResDuration::fromMilliseconds(3));
reporter->reportMark("mark0", 3);
const auto entries = toSorted(reporter->getEntries());
ASSERT_EQ(4, entries.size());
const std::vector<PerformanceEntry> expected = {
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()}}};
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}}};
ASSERT_EQ(expected, entries);
}
TEST(PerformanceEntryReporter, PerformanceEntryReporterTestReportMeasures) {
auto reporter = PerformanceEntryReporter::getInstance();
auto timeOrigin = HighResTimeStamp::now();
reporter->clearEntries();
reporter->reportMark("mark0", timeOrigin);
reporter->reportMark(
"mark1", timeOrigin + HighResDuration::fromMilliseconds(1));
reporter->reportMark(
"mark2", timeOrigin + HighResDuration::fromMilliseconds(2));
reporter->reportMark("mark0", 0);
reporter->reportMark("mark1", 1);
reporter->reportMark("mark2", 2);
reporter->reportMeasure(
"measure0",
timeOrigin,
timeOrigin + HighResDuration::fromMilliseconds(2));
reporter->reportMeasure(
"measure1",
timeOrigin,
timeOrigin + HighResDuration::fromMilliseconds(3));
reporter->reportMeasure("measure0", 0, 2);
reporter->reportMeasure("measure1", 0, 3);
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));
reporter->reportMark("mark3", 2.5);
reporter->reportMeasure("measure2", 2.0, 2.0);
reporter->reportMark("mark4", 3.0);
const auto entries = toSorted(reporter->getEntries());
const std::vector<PerformanceEntry> expected = {
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()}}};
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}}};
ASSERT_EQ(expected, entries);
}
TEST(PerformanceEntryReporter, PerformanceEntryReporterTestGetEntries) {
auto reporter = PerformanceEntryReporter::getInstance();
auto timeOrigin = HighResTimeStamp::now();
reporter->clearEntries();
{
@@ -196,61 +138,27 @@ TEST(PerformanceEntryReporter, PerformanceEntryReporterTestGetEntries) {
ASSERT_EQ(0, entries.size());
}
reporter->reportMark("common_name", timeOrigin);
reporter->reportMark(
"mark1", timeOrigin + HighResDuration::fromMilliseconds(1));
reporter->reportMark(
"mark2", timeOrigin + HighResDuration::fromMilliseconds(2));
reporter->reportMark("common_name", 0);
reporter->reportMark("mark1", 1);
reporter->reportMark("mark2", 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->reportMeasure("common_name", 0, 2);
reporter->reportMeasure("measure1", 0, 3);
reporter->reportMeasure("measure2", 1, 6);
reporter->reportMeasure("measure3", 1.5, 2);
{
const auto allEntries = toSorted(reporter->getEntries());
const std::vector<PerformanceEntry> expected = {
PerformanceMark{
{.name = "common_name",
.startTime = timeOrigin,
.duration = HighResDuration::zero()}},
PerformanceMark{{.name = "common_name", .startTime = 0, .duration = 0}},
PerformanceMeasure{
{.name = "common_name",
.startTime = timeOrigin,
.duration = HighResDuration::fromMilliseconds(2)}},
{.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}},
PerformanceMeasure{
{.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()}}};
{.name = "measure3", .startTime = 1.5, .duration = 0.5}},
PerformanceMark{{.name = "mark2", .startTime = 2, .duration = 0}}};
ASSERT_EQ(expected, allEntries);
}
@@ -258,18 +166,9 @@ TEST(PerformanceEntryReporter, PerformanceEntryReporterTestGetEntries) {
const auto marks =
toSorted(reporter->getEntries(PerformanceEntryType::MARK));
const std::vector<PerformanceEntry> expected = {
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()}}};
PerformanceMark{{.name = "common_name", .startTime = 0, .duration = 0}},
PerformanceMark{{.name = "mark1", .startTime = 1, .duration = 0}},
PerformanceMark{{.name = "mark2", .startTime = 2, .duration = 0}}};
ASSERT_EQ(expected, marks);
}
@@ -278,28 +177,17 @@ TEST(PerformanceEntryReporter, PerformanceEntryReporterTestGetEntries) {
toSorted(reporter->getEntries(PerformanceEntryType::MEASURE));
const std::vector<PerformanceEntry> expected = {
PerformanceMeasure{
{.name = "common_name",
.startTime = timeOrigin,
.duration = HighResDuration::fromMilliseconds(2)}},
{.name = "common_name", .startTime = 0, .duration = 2}},
PerformanceMeasure{{.name = "measure1", .startTime = 0, .duration = 3}},
PerformanceMeasure{{.name = "measure2", .startTime = 1, .duration = 5}},
PerformanceMeasure{
{.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)}}};
{.name = "measure3", .startTime = 1.5, .duration = 0.5}}};
ASSERT_EQ(expected, measures);
}
{
const std::vector<PerformanceEntry> expected = {
PerformanceMark{{.name = "common_name", .startTime = timeOrigin}}};
PerformanceMark{{.name = "common_name", .startTime = 0}}};
const auto commonName =
reporter->getEntries(PerformanceEntryType::MARK, "common_name");
ASSERT_EQ(expected, commonName);
@@ -307,9 +195,7 @@ TEST(PerformanceEntryReporter, PerformanceEntryReporterTestGetEntries) {
{
const std::vector<PerformanceEntry> expected = {PerformanceMeasure{
{.name = "common_name",
.startTime = timeOrigin,
.duration = HighResDuration::fromMilliseconds(2)}}};
{.name = "common_name", .startTime = 0, .duration = 2}}};
const auto commonName =
reporter->getEntries(PerformanceEntryType::MEASURE, "common_name");
ASSERT_EQ(expected, commonName);
@@ -318,52 +204,26 @@ TEST(PerformanceEntryReporter, PerformanceEntryReporterTestGetEntries) {
TEST(PerformanceEntryReporter, PerformanceEntryReporterTestClearMarks) {
auto reporter = PerformanceEntryReporter::getInstance();
auto timeOrigin = HighResTimeStamp::now();
reporter->clearEntries();
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->reportMark("common_name", 0);
reporter->reportMark("mark1", 1);
reporter->reportMark("mark1", 2.1);
reporter->reportMark("mark2", 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->reportMeasure("common_name", 0, 2);
reporter->reportMeasure("measure1", 0, 3);
reporter->reportMeasure("measure2", 1, 6);
reporter->reportMeasure("measure3", 1.5, 2);
reporter->clearEntries(PerformanceEntryType::MARK, "common_name");
{
auto entries = toSorted(reporter->getEntries(PerformanceEntryType::MARK));
std::vector<PerformanceEntry> expected = {
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()}},
PerformanceMark{{.name = "mark1", .startTime = 1, .duration = 0}},
PerformanceMark{{.name = "mark2", .startTime = 2, .duration = 0}},
PerformanceMark{{.name = "mark1", .startTime = 2.1, .duration = 0}},
};
ASSERT_EQ(expected, entries);
}
@@ -49,14 +49,12 @@ 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", timeOrigin + HighResDuration::fromMilliseconds(10));
reporter->reportMark("test", 10);
ASSERT_TRUE(callbackCalled);
observer->disconnect();
@@ -66,12 +64,10 @@ 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", timeOrigin + HighResDuration::fromMilliseconds(10));
reporter->reportMark("test", 10);
// wrong type
ASSERT_EQ(observer->takeRecords().size(), 0);
@@ -83,34 +79,15 @@ 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",
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);
reporter->reportEvent("test1", 10, 10, 0, 0, 0);
reporter->reportEvent("test2", 10, 10, 0, 0, 0);
reporter->reportEvent("test3", 10, 10, 0, 0, 0);
ASSERT_EQ(observer->takeRecords().size(), 0);
ASSERT_FALSE(callbackCalled);
@@ -124,14 +101,11 @@ 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", timeOrigin + HighResDuration::fromMilliseconds(10));
reporter->reportMark("test", 10);
ASSERT_FALSE(callbackCalled);
@@ -142,34 +116,14 @@ 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",
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);
reporter->reportEvent("test1", 10, 10, 0, 0, 0);
reporter->reportEvent("test2", 10, 10, 0, 0, 0);
reporter->reportEvent("off3", 10, 10, 0, 0, 0);
ASSERT_FALSE(callbackCalled);
@@ -180,32 +134,18 @@ 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", 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));
reporter->reportMark("test1", 10);
reporter->reportMeasure("off", 10, 20);
reporter->reportMark("test2", 20);
reporter->reportMark("test3", 30);
const std::vector<PerformanceEntry> expected = {
PerformanceMark{
{.name = "test1",
.startTime = timeOrigin + HighResDuration::fromMilliseconds(10)}},
PerformanceMark{
{.name = "test2",
.startTime = timeOrigin + HighResDuration::fromMilliseconds(20)}},
PerformanceMark{
{.name = "test3",
.startTime = timeOrigin + HighResDuration::fromMilliseconds(30)}},
PerformanceMark{{.name = "test1", .startTime = 10}},
PerformanceMark{{.name = "test2", .startTime = 20}},
PerformanceMark{{.name = "test3", .startTime = 30}},
};
ASSERT_EQ(expected, observer->takeRecords());
@@ -217,66 +157,19 @@ TEST(PerformanceObserver, PerformanceObserverTestObserveDurationThreshold) {
auto reporter = PerformanceEntryReporter::getInstance();
reporter->clearEntries();
auto timeOrigin = HighResTimeStamp::now();
auto observer =
PerformanceObserver::create(reporter->getObserverRegistry(), [&]() {});
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);
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);
const std::vector<PerformanceEntry> expected = {
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},
PerformanceEventTiming{{.name = "test1", .duration = 50}, 0, 0, 0},
PerformanceEventTiming{{.name = "test2", .duration = 100}, 0, 0, 0},
PerformanceEventTiming{{.name = "test3", .duration = 60}, 0, 0, 0},
};
ASSERT_EQ(expected, observer->takeRecords());
@@ -288,65 +181,23 @@ TEST(PerformanceObserver, PerformanceObserverTestObserveBuffered) {
auto reporter = PerformanceEntryReporter::getInstance();
reporter->clearEntries();
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);
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 observer =
PerformanceObserver::create(reporter->getObserverRegistry(), [&]() {});
observer->observe(
PerformanceEntryType::EVENT,
{.buffered = true,
.durationThreshold = HighResDuration::fromMilliseconds(50)});
PerformanceEntryType::EVENT, {.buffered = true, .durationThreshold = 50});
const std::vector<PerformanceEntry> expected = {
PerformanceEventTiming{
{.name = "test1",
.startTime = timeOrigin,
.duration = HighResDuration::fromMilliseconds(50)},
timeOrigin,
timeOrigin,
0},
{.name = "test1", .startTime = 0, .duration = 50}, 0, 0, 0},
PerformanceEventTiming{
{.name = "test2",
.startTime = timeOrigin,
.duration = HighResDuration::fromMilliseconds(100)},
timeOrigin,
timeOrigin,
0},
{.name = "test2", .startTime = 0, .duration = 100}, 0, 0, 0},
PerformanceEventTiming{
{.name = "test4",
.startTime = timeOrigin,
.duration = HighResDuration::fromMilliseconds(100)},
timeOrigin,
timeOrigin,
0},
{.name = "test4", .startTime = 0, .duration = 100}, 0, 0, 0},
};
ASSERT_EQ(expected, observer->takeRecords());
@@ -358,71 +209,26 @@ 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 = HighResDuration::fromMilliseconds(50)});
observer2->observe(
PerformanceEntryType::EVENT,
{.durationThreshold = HighResDuration::fromMilliseconds(80)});
observer1->observe(PerformanceEntryType::EVENT, {.durationThreshold = 50});
observer2->observe(PerformanceEntryType::EVENT, {.durationThreshold = 80});
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);
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);
const std::vector<PerformanceEntry> expected1 = {
PerformanceEventTiming{
{.name = "event1",
.startTime = timeOrigin,
.duration = HighResDuration::fromMilliseconds(100)},
timeOrigin,
timeOrigin,
0},
PerformanceEventTiming{
{.name = "event3",
.startTime = timeOrigin,
.duration = HighResDuration::fromMilliseconds(60)},
timeOrigin,
timeOrigin,
0},
PerformanceEventTiming{{.name = "event1", .duration = 100}, 0, 0, 0},
PerformanceEventTiming{{.name = "event3", .duration = 60}, 0, 0, 0},
};
const std::vector<PerformanceEntry> expected2 = {
PerformanceEventTiming{
{.name = "event1",
.startTime = timeOrigin,
.duration = HighResDuration::fromMilliseconds(100)},
timeOrigin,
timeOrigin,
0},
PerformanceEventTiming{{.name = "event1", .duration = 100}, 0, 0, 0},
};
ASSERT_EQ(expected1, observer1->takeRecords());
@@ -34,7 +34,8 @@ class EventLogger {
virtual EventTag onEventStart(
std::string_view name,
SharedEventTarget target,
std::optional<HighResTimeStamp> eventStartTimeStamp = std::nullopt) = 0;
std::optional<DOMHighResTimeStamp> 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<HighResTimeStamp> eventStartTimeStamp = std::nullopt;
std::optional<DOMHighResTimeStamp> eventStartTimeStamp = std::nullopt;
};
} // namespace facebook::react
@@ -25,7 +25,7 @@ class MockEventLogger : public EventLogger {
EventTag onEventStart(
std::string_view /*name*/,
SharedEventTarget /*target*/,
std::optional<HighResTimeStamp> /*eventStartTimeStamp*/) override {
std::optional<DOMHighResTimeStamp> /*eventStartTimeStamp*/) override {
return EMPTY_EVENT_TAG;
}
void onEventProcessingStart(EventTag /*tag*/) override {}
@@ -105,7 +105,7 @@ EventPerformanceLogger::EventPerformanceLogger(
EventTag EventPerformanceLogger::onEventStart(
std::string_view name,
SharedEventTarget target,
std::optional<HighResTimeStamp> eventStartTimeStamp) {
std::optional<DOMHighResTimeStamp> 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.
HighResTimeStamp timeStamp = eventStartTimeStamp
DOMHighResTimeStamp timeStamp = eventStartTimeStamp
? *eventStartTimeStamp
: performanceEntryReporter->getCurrentTimeStamp();
{
@@ -213,7 +213,7 @@ void EventPerformanceLogger::dispatchPendingEventTimingEntries(
void EventPerformanceLogger::shadowTreeDidMount(
const RootShadowNode::Shared& rootShadowNode,
HighResTimeStamp mountTime) noexcept {
double mountTime) noexcept {
auto performanceEntryReporter = performanceEntryReporter_.lock();
if (performanceEntryReporter == nullptr) {
return;
@@ -32,7 +32,7 @@ class EventPerformanceLogger : public EventLogger,
EventTag onEventStart(
std::string_view name,
SharedEventTarget target,
std::optional<HighResTimeStamp> eventStartTimeStamp =
std::optional<DOMHighResTimeStamp> 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,
HighResTimeStamp mountTime) noexcept override;
double mountTime) noexcept override;
private:
struct EventEntry {
std::string_view name;
SharedEventTarget target{nullptr};
HighResTimeStamp startTime;
std::optional<HighResTimeStamp> processingStartTime;
std::optional<HighResTimeStamp> processingEndTime;
DOMHighResTimeStamp startTime;
std::optional<DOMHighResTimeStamp> processingStartTime;
std::optional<DOMHighResTimeStamp> processingEndTime;
bool isWaitingForMount{false};
@@ -132,7 +132,7 @@ static Float getHighestThresholdCrossed(
std::optional<IntersectionObserverEntry>
IntersectionObserver::updateIntersectionObservation(
const RootShadowNode& rootShadowNode,
HighResTimeStamp time) {
double time) {
bool hasCustomRoot = observationRootShadowNodeFamily_.has_value();
auto rootAncestors = hasCustomRoot
@@ -208,7 +208,7 @@ IntersectionObserver::updateIntersectionObservation(
std::optional<IntersectionObserverEntry>
IntersectionObserver::updateIntersectionObservationForSurfaceUnmount(
HighResTimeStamp time) {
double time) {
return setNotIntersectingState(Rect{}, Rect{}, Rect{}, time);
}
@@ -219,7 +219,7 @@ IntersectionObserver::setIntersectingState(
const Rect& intersectionRect,
Float threshold,
Float rootThreshold,
HighResTimeStamp time) {
double time) {
auto newState =
IntersectionObserverState::Intersecting(threshold, rootThreshold);
@@ -245,7 +245,7 @@ IntersectionObserver::setNotIntersectingState(
const Rect& rootBoundingRect,
const Rect& targetBoundingRect,
const Rect& intersectionRect,
HighResTimeStamp time) {
double time) {
if (state_ != IntersectionObserverState::NotIntersecting()) {
state_ = IntersectionObserverState::NotIntersecting();
IntersectionObserverEntry entry{
@@ -25,7 +25,9 @@ struct IntersectionObserverEntry {
Rect rootRect;
Rect intersectionRect;
bool isIntersectingAboveThresholds;
HighResTimeStamp time;
// TODO(T156529385) Define `DOMHighResTimeStamp` as an alias for `double` and
// use it here.
double time;
bool sameShadowNodeFamily(
const ShadowNodeFamily& otherShadowNodeFamily) const {
@@ -47,10 +49,10 @@ class IntersectionObserver {
// https://w3c.github.io/IntersectionObserver/#update-intersection-observations-algo
std::optional<IntersectionObserverEntry> updateIntersectionObservation(
const RootShadowNode& rootShadowNode,
HighResTimeStamp time);
double time);
std::optional<IntersectionObserverEntry>
updateIntersectionObservationForSurfaceUnmount(HighResTimeStamp time);
updateIntersectionObservationForSurfaceUnmount(double time);
IntersectionObserverObserverId getIntersectionObserverId() const {
return intersectionObserverId_;
@@ -71,13 +73,13 @@ class IntersectionObserver {
const Rect& intersectionRect,
Float threshold,
Float rootThreshold,
HighResTimeStamp time);
double time);
std::optional<IntersectionObserverEntry> setNotIntersectingState(
const Rect& rootBoundingRect,
const Rect& targetBoundingRect,
const Rect& intersectionRect,
HighResTimeStamp time);
double time);
IntersectionObserverObserverId intersectionObserverId_;
std::optional<ShadowNodeFamily::Shared> observationRootShadowNodeFamily_;
@@ -283,14 +283,14 @@ void IntersectionObserverManager::updateIntersectionObservations(
void IntersectionObserverManager::shadowTreeDidMount(
const RootShadowNode::Shared& rootShadowNode,
HighResTimeStamp time) noexcept {
double time) noexcept {
updateIntersectionObservations(
rootShadowNode->getSurfaceId(), rootShadowNode.get(), time);
}
void IntersectionObserverManager::shadowTreeDidUnmount(
SurfaceId surfaceId,
HighResTimeStamp time) noexcept {
double time) noexcept {
updateIntersectionObservations(surfaceId, nullptr, time);
}
@@ -299,7 +299,7 @@ void IntersectionObserverManager::shadowTreeDidUnmount(
void IntersectionObserverManager::updateIntersectionObservations(
SurfaceId surfaceId,
const RootShadowNode* rootShadowNode,
HighResTimeStamp time) {
double time) {
TraceSection s("IntersectionObserverManager::updateIntersectionObservations");
std::vector<IntersectionObserverEntry> entries;
@@ -56,10 +56,9 @@ class IntersectionObserverManager final
void shadowTreeDidMount(
const RootShadowNode::Shared& rootShadowNode,
HighResTimeStamp time) noexcept override;
double time) noexcept override;
void shadowTreeDidUnmount(SurfaceId surfaceId, HighResTimeStamp time) noexcept
override;
void shadowTreeDidUnmount(SurfaceId surfaceId, double time) noexcept override;
private:
mutable std::unordered_map<
@@ -94,7 +93,7 @@ class IntersectionObserverManager final
void updateIntersectionObservations(
SurfaceId surfaceId,
const RootShadowNode* rootShadowNode,
HighResTimeStamp time);
double time);
const IntersectionObserver& getRegisteredIntersectionObserver(
SurfaceId surfaceId,
@@ -460,10 +460,12 @@ void RuntimeScheduler_Modern::reportLongTasks(
return;
}
if (longestPeriodWithoutYieldingOpportunity_ >=
LONG_TASK_DURATION_THRESHOLD) {
auto duration = endTime - startTime;
reporter->reportLongTask(startTime, duration);
auto checkedDurationMs =
longestPeriodWithoutYieldingOpportunity_.toDOMHighResTimeStamp();
if (checkedDurationMs >= LONG_TASK_DURATION_THRESHOLD_MS) {
auto durationMs = (endTime - startTime).toDOMHighResTimeStamp();
auto startTimeMs = startTime.toDOMHighResTimeStamp();
reporter->reportLongTask(startTimeMs, durationMs);
}
}
@@ -12,7 +12,6 @@
#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>
@@ -1258,9 +1257,8 @@ TEST_P(RuntimeSchedulerTest, reportsLongTasks) {
[startTime](const auto& entryDetails) {
EXPECT_EQ(entryDetails.entryType, PerformanceEntryType::LONGTASK);
EXPECT_EQ(
entryDetails.startTime.toDOMHighResTimeStamp(),
startTime.toDOMHighResTimeStamp() + 100);
EXPECT_EQ(entryDetails.duration, HighResDuration::fromMilliseconds(50));
entryDetails.startTime, startTime.toDOMHighResTimeStamp() + 100);
EXPECT_EQ(entryDetails.duration, 50);
},
entry);
}
@@ -1346,10 +1344,8 @@ TEST_P(RuntimeSchedulerTest, reportsLongTasksWithYielding) {
[startTime](const auto& entryDetails) {
EXPECT_EQ(entryDetails.entryType, PerformanceEntryType::LONGTASK);
EXPECT_EQ(
entryDetails.startTime.toDOMHighResTimeStamp(),
startTime.toDOMHighResTimeStamp() + 100);
EXPECT_EQ(
entryDetails.duration, HighResDuration::fromMilliseconds(120));
entryDetails.startTime, startTime.toDOMHighResTimeStamp() + 100);
EXPECT_EQ(entryDetails.duration, 120);
},
entry);
}
@@ -26,11 +26,11 @@ class UIManagerMountHook {
*/
virtual void shadowTreeDidMount(
const RootShadowNode::Shared& rootShadowNode,
HighResTimeStamp mountTime) noexcept = 0;
double mountTime) noexcept = 0;
virtual void shadowTreeDidUnmount(
SurfaceId /*surfaceId*/,
HighResTimeStamp /*unmountTime*/) noexcept {
double /*unmountTime*/) noexcept {
// Default no-op implementation for backwards compatibility.
}
@@ -11,6 +11,23 @@
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,6 +11,39 @@
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);
@@ -113,7 +113,7 @@ void HermesPerfettoDataSource::OnStart(const StartArgs&) {
"react-native",
perfetto::DynamicString{"Profiling Started"},
getPerfettoWebPerfTrackSync("JS Sampling"),
perfetto::TrackEvent::GetTraceTimeNs());
performanceNowToPerfettoTraceTime(0));
}
void HermesPerfettoDataSource::OnFlush(const FlushArgs&) {
@@ -80,17 +80,13 @@ perfetto::Track getPerfettoWebPerfTrackAsync(const std::string& trackName) {
}
// Perfetto's monotonic clock seems to match the std::chrono::steady_clock we
// use in HighResTimeStamp on Android platforms, but if that
// use in JSExecutor::performanceNow on Android platforms, but if that
// assumption is incorrect we may need to manually offset perfetto timestamps.
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();
uint64_t performanceNowToPerfettoTraceTime(double perfNowTime) {
if (perfNowTime == 0) {
return perfetto::TrackEvent::GetTraceTimeNs();
}
return static_cast<uint64_t>(perfNowTime * 1.e6);
}
} // namespace facebook::react
@@ -10,7 +10,6 @@
#ifdef WITH_PERFETTO
#include <perfetto.h>
#include <react/timing/primitives.h>
#include <reactperflogger/ReactPerfettoCategories.h>
#include <string>
@@ -21,7 +20,7 @@ void initializePerfetto();
perfetto::Track getPerfettoWebPerfTrackSync(const std::string& trackName);
perfetto::Track getPerfettoWebPerfTrackAsync(const std::string& trackName);
uint64_t highResTimeStampToPerfettoTraceTime(HighResTimeStamp timestamp);
uint64_t performanceNowToPerfettoTraceTime(double perfNowTime);
} // namespace facebook::react
@@ -13,6 +13,8 @@
#include <fbsystrace.h>
#endif
#include <chrono>
namespace facebook::react {
namespace {
@@ -28,9 +30,10 @@ std::string toPerfettoTrackName(
: PERFETTO_DEFAULT_TRACK_NAME;
}
#elif defined(WITH_FBSYSTRACE)
int64_t getDeltaNanos(HighResTimeStamp jsTime) {
auto now = HighResTimeStamp::now();
return (jsTime - now).toNanoseconds();
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();
}
#endif
@@ -48,8 +51,8 @@ int64_t getDeltaNanos(HighResTimeStamp jsTime) {
/* static */ void ReactPerfettoLogger::measure(
const std::string_view& eventName,
HighResTimeStamp startTime,
HighResTimeStamp endTime,
double startTime,
double endTime,
const std::optional<std::string_view>& trackName) {
#if defined(WITH_PERFETTO)
if (TRACE_EVENT_CATEGORY_ENABLED("react-native")) {
@@ -58,9 +61,9 @@ int64_t getDeltaNanos(HighResTimeStamp jsTime) {
"react-native",
perfetto::DynamicString(eventName.data(), eventName.size()),
track,
highResTimeStampToPerfettoTraceTime(startTime));
performanceNowToPerfettoTraceTime(startTime));
TRACE_EVENT_END(
"react-native", track, highResTimeStampToPerfettoTraceTime(endTime));
"react-native", track, performanceNowToPerfettoTraceTime(endTime));
}
#elif defined(WITH_FBSYSTRACE)
static int cookie = 0;
@@ -74,7 +77,7 @@ int64_t getDeltaNanos(HighResTimeStamp jsTime) {
/* static */ void ReactPerfettoLogger::mark(
const std::string_view& eventName,
HighResTimeStamp startTime,
double startTime,
const std::optional<std::string_view>& trackName) {
#if defined(WITH_PERFETTO)
if (TRACE_EVENT_CATEGORY_ENABLED("react-native")) {
@@ -82,7 +85,7 @@ int64_t getDeltaNanos(HighResTimeStamp jsTime) {
"react-native",
perfetto::DynamicString(eventName.data(), eventName.size()),
getPerfettoWebPerfTrackSync(toPerfettoTrackName(trackName)),
highResTimeStampToPerfettoTraceTime(startTime));
performanceNowToPerfettoTraceTime(startTime));
}
#elif defined(WITH_FBSYSTRACE)
static const char* kTrackName = "# Web Performance: Markers";
@@ -7,7 +7,6 @@
#pragma once
#include <react/timing/primitives.h>
#include <reactperflogger/ReactPerfettoCategories.h>
#include <optional>
@@ -25,13 +24,13 @@ class ReactPerfettoLogger {
static void mark(
const std::string_view& eventName,
HighResTimeStamp startTime,
double startTime,
const std::optional<std::string_view>& trackName);
static void measure(
const std::string_view& eventName,
HighResTimeStamp startTime,
HighResTimeStamp endTime,
double startTime,
double endTime,
const std::optional<std::string_view>& trackName);
};