mirror of
https://github.com/facebook/react-native.git
synced 2025-11-01 09:14:26 +00:00
Decouple PerformanceEntryReporter from NativePerformanceObserver (#43849)
Summary: Pull Request resolved: https://github.com/facebook/react-native/pull/43849 Changelog: [internal] ## Context This is part of a refactor to decouple the performance entry reporter from the rendering infra and from the native module that uses it. ## Changes This refactors `PerformanceEntryReporter` to make the class not depend on the native module that uses it. Instead of using the `RawPerformanceEntry` type from the native module, we define `PerformanceEntry` in `PerformanceEntryReporter` and use it as the source of truth in the native module instead. Thanks to the bridging template sytem we have, we can convert the raw objects passed from JS to the C++ structs, defining how the enums are converted from and to JS. Reviewed By: sammy-SC Differential Revision: D55646394 fbshipit-source-id: 9cf5a7db6ecb221ca08320d0aaae7e7bc8d91804
This commit is contained in:
committed by
Facebook GitHub Bot
parent
0f43f86035
commit
f5c9ed1ff4
+32
-38
@@ -36,14 +36,12 @@ NativePerformanceObserver::~NativePerformanceObserver() {
|
||||
|
||||
void NativePerformanceObserver::startReporting(
|
||||
jsi::Runtime& rt,
|
||||
int32_t entryType) {
|
||||
PerformanceEntryType entryType) {
|
||||
PerformanceEntryReporter& reporter = PerformanceEntryReporter::getInstance();
|
||||
|
||||
PerformanceEntryType entryTypeEnum =
|
||||
static_cast<PerformanceEntryType>(entryType);
|
||||
reporter.startReporting(entryTypeEnum);
|
||||
reporter.startReporting(entryType);
|
||||
|
||||
if (entryTypeEnum == PerformanceEntryType::EVENT &&
|
||||
if (entryType == PerformanceEntryType::EVENT &&
|
||||
CoreFeatures::enableReportEventPaintTime) {
|
||||
UIManagerBinding::getBinding(rt)->getUIManager().registerMountHook(
|
||||
reporter);
|
||||
@@ -52,14 +50,12 @@ void NativePerformanceObserver::startReporting(
|
||||
|
||||
void NativePerformanceObserver::stopReporting(
|
||||
jsi::Runtime& rt,
|
||||
int32_t entryType) {
|
||||
PerformanceEntryType entryType) {
|
||||
PerformanceEntryReporter& reporter = PerformanceEntryReporter::getInstance();
|
||||
|
||||
PerformanceEntryType entryTypeEnum =
|
||||
static_cast<PerformanceEntryType>(entryType);
|
||||
reporter.stopReporting(entryTypeEnum);
|
||||
reporter.stopReporting(entryType);
|
||||
|
||||
if (entryTypeEnum == PerformanceEntryType::EVENT &&
|
||||
if (entryType == PerformanceEntryType::EVENT &&
|
||||
CoreFeatures::enableReportEventPaintTime) {
|
||||
UIManagerBinding::getBinding(rt)->getUIManager().unregisterMountHook(
|
||||
reporter);
|
||||
@@ -67,34 +63,34 @@ void NativePerformanceObserver::stopReporting(
|
||||
}
|
||||
|
||||
void NativePerformanceObserver::setIsBuffered(
|
||||
jsi::Runtime& rt,
|
||||
std::vector<int32_t> entryTypes,
|
||||
jsi::Runtime& /*rt*/,
|
||||
const std::vector<PerformanceEntryType> entryTypes,
|
||||
bool isBuffered) {
|
||||
for (const int32_t entryType : entryTypes) {
|
||||
for (const PerformanceEntryType entryType : entryTypes) {
|
||||
PerformanceEntryReporter::getInstance().setAlwaysLogged(
|
||||
static_cast<PerformanceEntryType>(entryType), isBuffered);
|
||||
entryType, isBuffered);
|
||||
}
|
||||
}
|
||||
|
||||
GetPendingEntriesResult NativePerformanceObserver::popPendingEntries(
|
||||
jsi::Runtime& rt) {
|
||||
PerformanceEntryReporter::PopPendingEntriesResult
|
||||
NativePerformanceObserver::popPendingEntries(jsi::Runtime& /*rt*/) {
|
||||
return PerformanceEntryReporter::getInstance().popPendingEntries();
|
||||
}
|
||||
|
||||
void NativePerformanceObserver::setOnPerformanceEntryCallback(
|
||||
jsi::Runtime& rt,
|
||||
jsi::Runtime& /*rt*/,
|
||||
std::optional<AsyncCallback<>> callback) {
|
||||
PerformanceEntryReporter::getInstance().setReportingCallback(callback);
|
||||
}
|
||||
|
||||
void NativePerformanceObserver::logRawEntry(
|
||||
jsi::Runtime& rt,
|
||||
RawPerformanceEntry entry) {
|
||||
jsi::Runtime& /*rt*/,
|
||||
const PerformanceEntry entry) {
|
||||
PerformanceEntryReporter::getInstance().logEntry(entry);
|
||||
}
|
||||
|
||||
std::vector<std::pair<std::string, uint32_t>>
|
||||
NativePerformanceObserver::getEventCounts(jsi::Runtime& rt) {
|
||||
NativePerformanceObserver::getEventCounts(jsi::Runtime& /*rt*/) {
|
||||
const auto& eventCounts =
|
||||
PerformanceEntryReporter::getInstance().getEventCounts();
|
||||
return std::vector<std::pair<std::string, uint32_t>>(
|
||||
@@ -102,38 +98,36 @@ NativePerformanceObserver::getEventCounts(jsi::Runtime& rt) {
|
||||
}
|
||||
|
||||
void NativePerformanceObserver::setDurationThreshold(
|
||||
jsi::Runtime& rt,
|
||||
int32_t entryType,
|
||||
jsi::Runtime& /*rt*/,
|
||||
PerformanceEntryType entryType,
|
||||
double durationThreshold) {
|
||||
PerformanceEntryReporter::getInstance().setDurationThreshold(
|
||||
static_cast<PerformanceEntryType>(entryType), durationThreshold);
|
||||
entryType, durationThreshold);
|
||||
}
|
||||
|
||||
void NativePerformanceObserver::clearEntries(
|
||||
jsi::Runtime& rt,
|
||||
int32_t entryType,
|
||||
jsi::Runtime& /*rt*/,
|
||||
PerformanceEntryType entryType,
|
||||
std::optional<std::string> entryName) {
|
||||
PerformanceEntryReporter::getInstance().clearEntries(
|
||||
static_cast<PerformanceEntryType>(entryType),
|
||||
entryName ? entryName->c_str() : nullptr);
|
||||
entryType, entryName ? entryName->c_str() : std::string_view{});
|
||||
}
|
||||
|
||||
std::vector<RawPerformanceEntry> NativePerformanceObserver::getEntries(
|
||||
jsi::Runtime& rt,
|
||||
std::optional<int32_t> entryType,
|
||||
std::vector<PerformanceEntry> NativePerformanceObserver::getEntries(
|
||||
jsi::Runtime& /*rt*/,
|
||||
std::optional<PerformanceEntryType> entryType,
|
||||
std::optional<std::string> entryName) {
|
||||
return PerformanceEntryReporter::getInstance().getEntries(
|
||||
entryType ? std::optional{static_cast<PerformanceEntryType>(*entryType)}
|
||||
: std::nullopt,
|
||||
entryName ? entryName->c_str() : nullptr);
|
||||
entryType, entryName ? entryName->c_str() : std::string_view{});
|
||||
}
|
||||
|
||||
std::vector<RawPerformanceEntryType>
|
||||
NativePerformanceObserver::getSupportedPerformanceEntryTypes(jsi::Runtime& rt) {
|
||||
std::vector<PerformanceEntryType>
|
||||
NativePerformanceObserver::getSupportedPerformanceEntryTypes(
|
||||
jsi::Runtime& /*rt*/) {
|
||||
return {
|
||||
static_cast<RawPerformanceEntryType>(PerformanceEntryType::MARK),
|
||||
static_cast<RawPerformanceEntryType>(PerformanceEntryType::MEASURE),
|
||||
static_cast<RawPerformanceEntryType>(PerformanceEntryType::EVENT),
|
||||
PerformanceEntryType::MARK,
|
||||
PerformanceEntryType::MEASURE,
|
||||
PerformanceEntryType::EVENT,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
+30
-34
@@ -8,43 +8,40 @@
|
||||
#pragma once
|
||||
|
||||
#include <FBReactNativeSpec/FBReactNativeSpecJSI.h>
|
||||
#include <react/nativemodule/webperformance/PerformanceEntryReporter.h>
|
||||
#include <functional>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace facebook::react {
|
||||
class PerformanceEntryReporter;
|
||||
|
||||
#pragma mark - Structs
|
||||
|
||||
using RawPerformanceEntryType = int32_t;
|
||||
template <>
|
||||
struct Bridging<PerformanceEntryType> {
|
||||
static PerformanceEntryType fromJs(
|
||||
jsi::Runtime& /*rt*/,
|
||||
const jsi::Value& value) {
|
||||
return static_cast<PerformanceEntryType>(value.asNumber());
|
||||
}
|
||||
|
||||
using RawPerformanceEntry = NativePerformanceObserverCxxRawPerformanceEntry<
|
||||
/* name */ std::string,
|
||||
/* type */ RawPerformanceEntryType,
|
||||
/* startTime */ double,
|
||||
/* duration */ double,
|
||||
|
||||
// For "event" entries only:
|
||||
/* processingStart */ std::optional<double>,
|
||||
/* processingEnd */ std::optional<double>,
|
||||
/* interactionId */ std::optional<uint32_t>>;
|
||||
static jsi::Value toJs(
|
||||
jsi::Runtime& /*rt*/,
|
||||
const PerformanceEntryType& value) {
|
||||
return {static_cast<int>(value)};
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Bridging<RawPerformanceEntry>
|
||||
struct Bridging<PerformanceEntry>
|
||||
: NativePerformanceObserverCxxRawPerformanceEntryBridging<
|
||||
RawPerformanceEntry> {};
|
||||
|
||||
using GetPendingEntriesResult =
|
||||
NativePerformanceObserverCxxGetPendingEntriesResult<
|
||||
std::vector<RawPerformanceEntry>,
|
||||
uint32_t>;
|
||||
PerformanceEntry> {};
|
||||
|
||||
template <>
|
||||
struct Bridging<GetPendingEntriesResult>
|
||||
struct Bridging<PerformanceEntryReporter::PopPendingEntriesResult>
|
||||
: NativePerformanceObserverCxxGetPendingEntriesResultBridging<
|
||||
GetPendingEntriesResult> {};
|
||||
PerformanceEntryReporter::PopPendingEntriesResult> {};
|
||||
|
||||
#pragma mark - implementation
|
||||
|
||||
@@ -54,45 +51,44 @@ class NativePerformanceObserver
|
||||
NativePerformanceObserver(std::shared_ptr<CallInvoker> jsInvoker);
|
||||
~NativePerformanceObserver();
|
||||
|
||||
void startReporting(jsi::Runtime& rt, int32_t entryType);
|
||||
void startReporting(jsi::Runtime& rt, PerformanceEntryType entryType);
|
||||
|
||||
void stopReporting(jsi::Runtime& rt, int32_t entryType);
|
||||
void stopReporting(jsi::Runtime& rt, PerformanceEntryType entryType);
|
||||
|
||||
void setIsBuffered(
|
||||
jsi::Runtime& rt,
|
||||
std::vector<int32_t> entryTypes,
|
||||
const std::vector<PerformanceEntryType> entryTypes,
|
||||
bool isBuffered);
|
||||
|
||||
GetPendingEntriesResult popPendingEntries(jsi::Runtime& rt);
|
||||
PerformanceEntryReporter::PopPendingEntriesResult popPendingEntries(
|
||||
jsi::Runtime& rt);
|
||||
|
||||
void setOnPerformanceEntryCallback(
|
||||
jsi::Runtime& rt,
|
||||
std::optional<AsyncCallback<>> callback);
|
||||
|
||||
void logRawEntry(jsi::Runtime& rt, RawPerformanceEntry entry);
|
||||
void logRawEntry(jsi::Runtime& rt, const PerformanceEntry entry);
|
||||
|
||||
std::vector<std::pair<std::string, uint32_t>> getEventCounts(
|
||||
jsi::Runtime& rt);
|
||||
|
||||
void setDurationThreshold(
|
||||
jsi::Runtime& rt,
|
||||
int32_t entryType,
|
||||
double durationThreshold);
|
||||
PerformanceEntryType entryType,
|
||||
DOMHighResTimeStamp durationThreshold);
|
||||
|
||||
void clearEntries(
|
||||
jsi::Runtime& rt,
|
||||
int32_t entryType,
|
||||
PerformanceEntryType entryType,
|
||||
std::optional<std::string> entryName);
|
||||
|
||||
std::vector<RawPerformanceEntry> getEntries(
|
||||
std::vector<PerformanceEntry> getEntries(
|
||||
jsi::Runtime& rt,
|
||||
std::optional<int32_t> entryType,
|
||||
std::optional<PerformanceEntryType> entryType,
|
||||
std::optional<std::string> entryName);
|
||||
|
||||
std::vector<RawPerformanceEntryType> getSupportedPerformanceEntryTypes(
|
||||
std::vector<PerformanceEntryType> getSupportedPerformanceEntryTypes(
|
||||
jsi::Runtime& rt);
|
||||
|
||||
private:
|
||||
};
|
||||
|
||||
} // namespace facebook::react
|
||||
|
||||
+40
-39
@@ -9,7 +9,6 @@
|
||||
#include <cxxreact/JSExecutor.h>
|
||||
#include <react/renderer/core/EventLogger.h>
|
||||
#include <react/utils/CoreFeatures.h>
|
||||
#include "NativePerformanceObserver.h"
|
||||
|
||||
#include <functional>
|
||||
#include <unordered_map>
|
||||
@@ -35,7 +34,7 @@ void PerformanceEntryReporter::setReportingCallback(
|
||||
callback_ = callback;
|
||||
}
|
||||
|
||||
double PerformanceEntryReporter::getCurrentTimeStamp() const {
|
||||
DOMHighResTimeStamp PerformanceEntryReporter::getCurrentTimeStamp() const {
|
||||
return timeStampProvider_ != nullptr ? timeStampProvider_()
|
||||
: JSExecutor::performanceNow();
|
||||
}
|
||||
@@ -55,7 +54,7 @@ void PerformanceEntryReporter::setAlwaysLogged(
|
||||
|
||||
void PerformanceEntryReporter::setDurationThreshold(
|
||||
PerformanceEntryType entryType,
|
||||
double durationThreshold) {
|
||||
DOMHighResTimeStamp durationThreshold) {
|
||||
getBuffer(entryType).durationThreshold = durationThreshold;
|
||||
}
|
||||
|
||||
@@ -69,10 +68,12 @@ void PerformanceEntryReporter::stopReporting() {
|
||||
}
|
||||
}
|
||||
|
||||
GetPendingEntriesResult PerformanceEntryReporter::popPendingEntries() {
|
||||
PerformanceEntryReporter::PopPendingEntriesResult
|
||||
PerformanceEntryReporter::popPendingEntries() {
|
||||
std::lock_guard lock(entriesMutex_);
|
||||
GetPendingEntriesResult res = {
|
||||
std::vector<RawPerformanceEntry>(), droppedEntryCount_};
|
||||
PopPendingEntriesResult res = {
|
||||
.entries = std::vector<PerformanceEntry>(),
|
||||
.droppedEntriesCount = droppedEntriesCount_};
|
||||
for (auto& buffer : buffers_) {
|
||||
buffer.entries.consume(res.entries);
|
||||
}
|
||||
@@ -81,7 +82,7 @@ GetPendingEntriesResult PerformanceEntryReporter::popPendingEntries() {
|
||||
std::stable_sort(
|
||||
res.entries.begin(),
|
||||
res.entries.end(),
|
||||
[](const RawPerformanceEntry& lhs, const RawPerformanceEntry& rhs) {
|
||||
[](const PerformanceEntry& lhs, const PerformanceEntry& rhs) {
|
||||
if (lhs.startTime != rhs.startTime) {
|
||||
return lhs.startTime < rhs.startTime;
|
||||
} else {
|
||||
@@ -89,23 +90,22 @@ GetPendingEntriesResult PerformanceEntryReporter::popPendingEntries() {
|
||||
}
|
||||
});
|
||||
|
||||
droppedEntryCount_ = 0;
|
||||
droppedEntriesCount_ = 0;
|
||||
return res;
|
||||
}
|
||||
|
||||
void PerformanceEntryReporter::logEntry(const RawPerformanceEntry& entry) {
|
||||
const auto entryType = static_cast<PerformanceEntryType>(entry.entryType);
|
||||
if (entryType == PerformanceEntryType::EVENT) {
|
||||
void PerformanceEntryReporter::logEntry(const PerformanceEntry& entry) {
|
||||
if (entry.entryType == PerformanceEntryType::EVENT) {
|
||||
eventCounts_[entry.name]++;
|
||||
}
|
||||
|
||||
if (!isReporting(entryType) && !isAlwaysLogged(entryType)) {
|
||||
if (!isReporting(entry.entryType) && !isAlwaysLogged(entry.entryType)) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::lock_guard lock(entriesMutex_);
|
||||
|
||||
auto& buffer = getBuffer(entryType);
|
||||
auto& buffer = getBuffer(entry.entryType);
|
||||
|
||||
if (entry.duration < buffer.durationThreshold) {
|
||||
// The entries duration is lower than the desired reporting threshold, skip
|
||||
@@ -127,11 +127,11 @@ void PerformanceEntryReporter::logEntry(const RawPerformanceEntry& entry) {
|
||||
|
||||
auto pushResult = buffer.entries.add(std::move(entry));
|
||||
if (pushResult ==
|
||||
BoundedConsumableBuffer<RawPerformanceEntry>::PushStatus::DROP) {
|
||||
BoundedConsumableBuffer<PerformanceEntry>::PushStatus::DROP) {
|
||||
// Start dropping entries once reached maximum buffer size.
|
||||
// The number of dropped entries will be reported back to the corresponding
|
||||
// PerformanceObserver callback.
|
||||
droppedEntryCount_ += 1;
|
||||
droppedEntriesCount_ += 1;
|
||||
}
|
||||
|
||||
if (buffer.hasNameLookup) {
|
||||
@@ -153,10 +153,10 @@ void PerformanceEntryReporter::logEntry(const RawPerformanceEntry& entry) {
|
||||
|
||||
void PerformanceEntryReporter::mark(
|
||||
const std::string& name,
|
||||
const std::optional<double>& startTime) {
|
||||
logEntry(RawPerformanceEntry{
|
||||
const std::optional<DOMHighResTimeStamp>& startTime) {
|
||||
logEntry(PerformanceEntry{
|
||||
.name = name,
|
||||
.entryType = static_cast<int>(PerformanceEntryType::MARK),
|
||||
.entryType = PerformanceEntryType::MARK,
|
||||
.startTime = startTime ? *startTime : getCurrentTimeStamp()});
|
||||
}
|
||||
|
||||
@@ -177,7 +177,7 @@ void PerformanceEntryReporter::clearEntries(
|
||||
}
|
||||
|
||||
std::lock_guard lock(entriesMutex_);
|
||||
buffer.entries.clear([entryName](const RawPerformanceEntry& entry) {
|
||||
buffer.entries.clear([entryName](const PerformanceEntry& entry) {
|
||||
return entry.name == entryName;
|
||||
});
|
||||
|
||||
@@ -207,22 +207,22 @@ void PerformanceEntryReporter::clearEntries(
|
||||
void PerformanceEntryReporter::getEntries(
|
||||
PerformanceEntryType entryType,
|
||||
std::string_view entryName,
|
||||
std::vector<RawPerformanceEntry>& res) const {
|
||||
std::vector<PerformanceEntry>& res) const {
|
||||
std::lock_guard lock(entriesMutex_);
|
||||
const auto& entries = getBuffer(entryType).entries;
|
||||
if (entryName.empty()) {
|
||||
entries.getEntries(res);
|
||||
} else {
|
||||
entries.getEntries(res, [entryName](const RawPerformanceEntry& entry) {
|
||||
entries.getEntries(res, [entryName](const PerformanceEntry& entry) {
|
||||
return entry.name == entryName;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<RawPerformanceEntry> PerformanceEntryReporter::getEntries(
|
||||
std::vector<PerformanceEntry> PerformanceEntryReporter::getEntries(
|
||||
std::optional<PerformanceEntryType> entryType,
|
||||
std::string_view entryName) const {
|
||||
std::vector<RawPerformanceEntry> res;
|
||||
std::vector<PerformanceEntry> res;
|
||||
if (!entryType) {
|
||||
// Collect all entry types
|
||||
for (int i = 1; i < NUM_PERFORMANCE_ENTRY_TYPES; i++) {
|
||||
@@ -236,13 +236,14 @@ std::vector<RawPerformanceEntry> PerformanceEntryReporter::getEntries(
|
||||
|
||||
void PerformanceEntryReporter::measure(
|
||||
const std::string& name,
|
||||
double startTime,
|
||||
double endTime,
|
||||
const std::optional<double>& duration,
|
||||
DOMHighResTimeStamp startTime,
|
||||
DOMHighResTimeStamp endTime,
|
||||
const std::optional<DOMHighResTimeStamp>& duration,
|
||||
const std::optional<std::string>& startMark,
|
||||
const std::optional<std::string>& endMark) {
|
||||
double startTimeVal = startMark ? getMarkTime(*startMark) : startTime;
|
||||
double endTimeVal = endMark ? getMarkTime(*endMark) : endTime;
|
||||
DOMHighResTimeStamp startTimeVal =
|
||||
startMark ? getMarkTime(*startMark) : startTime;
|
||||
DOMHighResTimeStamp endTimeVal = endMark ? getMarkTime(*endMark) : endTime;
|
||||
|
||||
if (!endMark && endTime < startTimeVal) {
|
||||
// The end time is not specified, take the current time, according to the
|
||||
@@ -250,20 +251,20 @@ void PerformanceEntryReporter::measure(
|
||||
endTimeVal = getCurrentTimeStamp();
|
||||
}
|
||||
|
||||
double durationVal = duration ? *duration : endTimeVal - startTimeVal;
|
||||
DOMHighResTimeStamp durationVal =
|
||||
duration ? *duration : endTimeVal - startTimeVal;
|
||||
|
||||
logEntry(
|
||||
{.name = name,
|
||||
.entryType = static_cast<int>(PerformanceEntryType::MEASURE),
|
||||
.entryType = PerformanceEntryType::MEASURE,
|
||||
.startTime = startTimeVal,
|
||||
.duration = durationVal});
|
||||
}
|
||||
|
||||
double PerformanceEntryReporter::getMarkTime(
|
||||
DOMHighResTimeStamp PerformanceEntryReporter::getMarkTime(
|
||||
const std::string& markName) const {
|
||||
RawPerformanceEntry mark{
|
||||
.name = markName,
|
||||
.entryType = static_cast<int>(PerformanceEntryType::MARK)};
|
||||
PerformanceEntry mark{
|
||||
.name = markName, .entryType = PerformanceEntryType::MARK};
|
||||
|
||||
std::lock_guard lock(nameLookupMutex_);
|
||||
const auto& marksBuffer = getBuffer(PerformanceEntryType::MARK);
|
||||
@@ -277,14 +278,14 @@ double PerformanceEntryReporter::getMarkTime(
|
||||
|
||||
void PerformanceEntryReporter::logEventEntry(
|
||||
std::string name,
|
||||
double startTime,
|
||||
double duration,
|
||||
double processingStart,
|
||||
double processingEnd,
|
||||
DOMHighResTimeStamp startTime,
|
||||
DOMHighResTimeStamp duration,
|
||||
DOMHighResTimeStamp processingStart,
|
||||
DOMHighResTimeStamp processingEnd,
|
||||
uint32_t interactionId) {
|
||||
logEntry(
|
||||
{.name = std::move(name),
|
||||
.entryType = static_cast<int>(PerformanceEntryType::EVENT),
|
||||
.entryType = PerformanceEntryType::EVENT,
|
||||
.startTime = startTime,
|
||||
.duration = duration,
|
||||
.processingStart = processingStart,
|
||||
|
||||
+41
-22
@@ -17,28 +17,50 @@
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include "BoundedConsumableBuffer.h"
|
||||
#include "NativePerformanceObserver.h"
|
||||
|
||||
#include <react/renderer/uimanager/UIManagerMountHook.h>
|
||||
|
||||
namespace facebook::react {
|
||||
|
||||
using DOMHighResTimeStamp = double;
|
||||
|
||||
using PerformanceEntryInteractionId = uint32_t;
|
||||
|
||||
enum class PerformanceEntryType {
|
||||
// We need to preserve these values for backwards compatibility.
|
||||
MARK = 1,
|
||||
MEASURE = 2,
|
||||
EVENT = 3,
|
||||
_NEXT = 4,
|
||||
};
|
||||
|
||||
struct PerformanceEntry {
|
||||
std::string name;
|
||||
PerformanceEntryType entryType;
|
||||
DOMHighResTimeStamp startTime;
|
||||
DOMHighResTimeStamp duration = 0;
|
||||
|
||||
// For "event" entries only:
|
||||
std::optional<DOMHighResTimeStamp> processingStart;
|
||||
std::optional<DOMHighResTimeStamp> processingEnd;
|
||||
std::optional<PerformanceEntryInteractionId> interactionId;
|
||||
};
|
||||
|
||||
struct PerformanceEntryHash {
|
||||
size_t operator()(const RawPerformanceEntry* entry) const {
|
||||
size_t operator()(const PerformanceEntry* entry) const {
|
||||
return std::hash<std::string>()(entry->name);
|
||||
}
|
||||
};
|
||||
|
||||
struct PerformanceEntryEqual {
|
||||
bool operator()(
|
||||
const RawPerformanceEntry* lhs,
|
||||
const RawPerformanceEntry* rhs) const {
|
||||
bool operator()(const PerformanceEntry* lhs, const PerformanceEntry* rhs)
|
||||
const {
|
||||
return lhs->name == rhs->name;
|
||||
}
|
||||
};
|
||||
|
||||
using PerformanceEntryRegistryType = std::unordered_set<
|
||||
const RawPerformanceEntry*,
|
||||
const PerformanceEntry*,
|
||||
PerformanceEntryHash,
|
||||
PerformanceEntryEqual>;
|
||||
|
||||
@@ -50,7 +72,7 @@ constexpr double DEFAULT_DURATION_THRESHOLD = 0.0;
|
||||
constexpr size_t DEFAULT_MAX_BUFFER_SIZE = 1024;
|
||||
|
||||
struct PerformanceEntryBuffer {
|
||||
BoundedConsumableBuffer<RawPerformanceEntry> entries{DEFAULT_MAX_BUFFER_SIZE};
|
||||
BoundedConsumableBuffer<PerformanceEntry> entries{DEFAULT_MAX_BUFFER_SIZE};
|
||||
bool isReporting{false};
|
||||
bool isAlwaysLogged{false};
|
||||
double durationThreshold{DEFAULT_DURATION_THRESHOLD};
|
||||
@@ -58,14 +80,6 @@ struct PerformanceEntryBuffer {
|
||||
PerformanceEntryRegistryType nameLookup;
|
||||
};
|
||||
|
||||
enum class PerformanceEntryType {
|
||||
// We need to preserve these values for backwards compatibility.
|
||||
MARK = 1,
|
||||
MEASURE = 2,
|
||||
EVENT = 3,
|
||||
_NEXT = 4,
|
||||
};
|
||||
|
||||
constexpr size_t NUM_PERFORMANCE_ENTRY_TYPES =
|
||||
(size_t)PerformanceEntryType::_NEXT - 1; // Valid types start from 1.
|
||||
|
||||
@@ -80,6 +94,11 @@ class PerformanceEntryReporter : public EventLogger, public UIManagerMountHook {
|
||||
// creation time instead of having the singleton.
|
||||
static PerformanceEntryReporter& getInstance();
|
||||
|
||||
struct PopPendingEntriesResult {
|
||||
std::vector<PerformanceEntry> entries;
|
||||
uint32_t droppedEntriesCount;
|
||||
};
|
||||
|
||||
void setReportingCallback(std::optional<AsyncCallback<>> callback);
|
||||
void startReporting(PerformanceEntryType entryType);
|
||||
void stopReporting(PerformanceEntryType entryType);
|
||||
@@ -89,9 +108,9 @@ class PerformanceEntryReporter : public EventLogger, public UIManagerMountHook {
|
||||
PerformanceEntryType entryType,
|
||||
double durationThreshold);
|
||||
|
||||
GetPendingEntriesResult popPendingEntries();
|
||||
PopPendingEntriesResult popPendingEntries();
|
||||
|
||||
void logEntry(const RawPerformanceEntry& entry);
|
||||
void logEntry(const PerformanceEntry& entry);
|
||||
|
||||
PerformanceEntryBuffer& getBuffer(PerformanceEntryType entryType) {
|
||||
return buffers_[static_cast<int>(entryType) - 1];
|
||||
@@ -110,8 +129,8 @@ class PerformanceEntryReporter : public EventLogger, public UIManagerMountHook {
|
||||
return getBuffer(entryType).isAlwaysLogged;
|
||||
}
|
||||
|
||||
uint32_t getDroppedEntryCount() const {
|
||||
return droppedEntryCount_;
|
||||
uint32_t getDroppedEntriesCount() const {
|
||||
return droppedEntriesCount_;
|
||||
}
|
||||
|
||||
void mark(
|
||||
@@ -130,7 +149,7 @@ class PerformanceEntryReporter : public EventLogger, public UIManagerMountHook {
|
||||
std::optional<PerformanceEntryType> entryType = std::nullopt,
|
||||
std::string_view entryName = {});
|
||||
|
||||
std::vector<RawPerformanceEntry> getEntries(
|
||||
std::vector<PerformanceEntry> getEntries(
|
||||
std::optional<PerformanceEntryType> entryType = std::nullopt,
|
||||
std::string_view entryName = {}) const;
|
||||
|
||||
@@ -165,7 +184,7 @@ class PerformanceEntryReporter : public EventLogger, public UIManagerMountHook {
|
||||
std::array<PerformanceEntryBuffer, NUM_PERFORMANCE_ENTRY_TYPES> buffers_;
|
||||
std::unordered_map<std::string, uint32_t> eventCounts_;
|
||||
|
||||
uint32_t droppedEntryCount_{0};
|
||||
uint32_t droppedEntriesCount_{0};
|
||||
|
||||
struct EventEntry {
|
||||
std::string_view name;
|
||||
@@ -199,7 +218,7 @@ class PerformanceEntryReporter : public EventLogger, public UIManagerMountHook {
|
||||
void getEntries(
|
||||
PerformanceEntryType entryType,
|
||||
std::string_view entryName,
|
||||
std::vector<RawPerformanceEntry>& res) const;
|
||||
std::vector<PerformanceEntry>& res) const;
|
||||
|
||||
double getCurrentTimeStamp() const;
|
||||
};
|
||||
|
||||
+67
-33
@@ -13,9 +13,19 @@
|
||||
|
||||
namespace facebook::react {
|
||||
|
||||
static std::ostream& operator<<(
|
||||
[[maybe_unused]] static bool operator==(
|
||||
const PerformanceEntry& lhs,
|
||||
const PerformanceEntry& rhs) {
|
||||
return lhs.name == rhs.name && lhs.entryType == rhs.entryType &&
|
||||
lhs.startTime == rhs.startTime && lhs.duration == rhs.duration &&
|
||||
lhs.processingStart == rhs.processingStart &&
|
||||
lhs.processingEnd == rhs.processingEnd &&
|
||||
lhs.interactionId == rhs.interactionId;
|
||||
}
|
||||
|
||||
[[maybe_unused]] static std::ostream& operator<<(
|
||||
std::ostream& os,
|
||||
const RawPerformanceEntry& entry) {
|
||||
const PerformanceEntry& entry) {
|
||||
static constexpr const char* entryTypeNames[] = {
|
||||
"UNDEFINED",
|
||||
"MARK",
|
||||
@@ -23,7 +33,7 @@ static std::ostream& operator<<(
|
||||
"EVENT",
|
||||
};
|
||||
return os << "{ name: " << entry.name
|
||||
<< ", type: " << entryTypeNames[entry.entryType]
|
||||
<< ", type: " << entryTypeNames[static_cast<int>(entry.entryType)]
|
||||
<< ", startTime: " << entry.startTime
|
||||
<< ", duration: " << entry.duration << " }";
|
||||
}
|
||||
@@ -103,18 +113,18 @@ TEST(PerformanceEntryReporter, PerformanceEntryReporterTestReportMarks) {
|
||||
ASSERT_EQ(0, res.droppedEntriesCount);
|
||||
ASSERT_EQ(4, entries.size());
|
||||
|
||||
const std::vector<RawPerformanceEntry> expected = {
|
||||
const std::vector<PerformanceEntry> expected = {
|
||||
{.name = "mark0",
|
||||
.entryType = static_cast<int>(PerformanceEntryType::MARK),
|
||||
.entryType = PerformanceEntryType::MARK,
|
||||
.startTime = 0.0},
|
||||
{.name = "mark1",
|
||||
.entryType = static_cast<int>(PerformanceEntryType::MARK),
|
||||
.entryType = PerformanceEntryType::MARK,
|
||||
.startTime = 1.0},
|
||||
{.name = "mark2",
|
||||
.entryType = static_cast<int>(PerformanceEntryType::MARK),
|
||||
.entryType = PerformanceEntryType::MARK,
|
||||
.startTime = 2.0},
|
||||
{.name = "mark0",
|
||||
.entryType = static_cast<int>(PerformanceEntryType::MARK),
|
||||
.entryType = PerformanceEntryType::MARK,
|
||||
.startTime = 3.0},
|
||||
};
|
||||
|
||||
@@ -155,80 +165,80 @@ TEST(PerformanceEntryReporter, PerformanceEntryReporterTestReportMeasures) {
|
||||
|
||||
ASSERT_EQ(0, res.droppedEntriesCount);
|
||||
|
||||
const std::vector<RawPerformanceEntry> expected = {
|
||||
const std::vector<PerformanceEntry> expected = {
|
||||
{.name = "mark0",
|
||||
.entryType = static_cast<int>(PerformanceEntryType::MARK),
|
||||
.entryType = PerformanceEntryType::MARK,
|
||||
.startTime = 0.0},
|
||||
{.name = "measure0",
|
||||
.entryType = static_cast<int>(PerformanceEntryType::MEASURE),
|
||||
.entryType = PerformanceEntryType::MEASURE,
|
||||
.startTime = 0.0,
|
||||
.duration = 2.0},
|
||||
{.name = "measure1",
|
||||
.entryType = static_cast<int>(PerformanceEntryType::MEASURE),
|
||||
.entryType = PerformanceEntryType::MEASURE,
|
||||
.startTime = 0.0,
|
||||
.duration = 4.0},
|
||||
{.name = "mark1",
|
||||
.entryType = static_cast<int>(PerformanceEntryType::MARK),
|
||||
.entryType = PerformanceEntryType::MARK,
|
||||
.startTime = 1.0},
|
||||
{.name = "measure2",
|
||||
.entryType = static_cast<int>(PerformanceEntryType::MEASURE),
|
||||
.entryType = PerformanceEntryType::MEASURE,
|
||||
.startTime = 1.0,
|
||||
.duration = 1.0},
|
||||
{.name = "measure7",
|
||||
.entryType = static_cast<int>(PerformanceEntryType::MEASURE),
|
||||
.entryType = PerformanceEntryType::MEASURE,
|
||||
.startTime = 1.0,
|
||||
.duration = 2.0},
|
||||
{.name = "measure3",
|
||||
.entryType = static_cast<int>(PerformanceEntryType::MEASURE),
|
||||
.entryType = PerformanceEntryType::MEASURE,
|
||||
.startTime = 1.0,
|
||||
.duration = 5.0},
|
||||
{.name = "measure4",
|
||||
.entryType = static_cast<int>(PerformanceEntryType::MEASURE),
|
||||
.entryType = PerformanceEntryType::MEASURE,
|
||||
.startTime = 1.5,
|
||||
.duration = 0.5},
|
||||
{.name = "mark2",
|
||||
.entryType = static_cast<int>(PerformanceEntryType::MARK),
|
||||
.entryType = PerformanceEntryType::MARK,
|
||||
.startTime = 2.0},
|
||||
{.name = "mark3",
|
||||
.entryType = static_cast<int>(PerformanceEntryType::MARK),
|
||||
.entryType = PerformanceEntryType::MARK,
|
||||
.startTime = 2.0},
|
||||
{.name = "mark4",
|
||||
.entryType = static_cast<int>(PerformanceEntryType::MARK),
|
||||
.entryType = PerformanceEntryType::MARK,
|
||||
.startTime = 2.0},
|
||||
{.name = "measure6",
|
||||
.entryType = static_cast<int>(PerformanceEntryType::MEASURE),
|
||||
.entryType = PerformanceEntryType::MEASURE,
|
||||
.startTime = 2.0,
|
||||
.duration = 0.0},
|
||||
{.name = "measure5",
|
||||
.entryType = static_cast<int>(PerformanceEntryType::MEASURE),
|
||||
.entryType = PerformanceEntryType::MEASURE,
|
||||
.startTime = 2.0,
|
||||
.duration = 1.5},
|
||||
{.name = "mark4",
|
||||
.entryType = static_cast<int>(PerformanceEntryType::MARK),
|
||||
.entryType = PerformanceEntryType::MARK,
|
||||
.startTime = 3.0}};
|
||||
|
||||
ASSERT_EQ(expected, entries);
|
||||
}
|
||||
|
||||
static std::vector<std::string> getNames(
|
||||
const std::vector<RawPerformanceEntry>& entries) {
|
||||
const std::vector<PerformanceEntry>& entries) {
|
||||
std::vector<std::string> res;
|
||||
std::transform(
|
||||
entries.begin(),
|
||||
entries.end(),
|
||||
std::back_inserter(res),
|
||||
[](const RawPerformanceEntry& e) { return e.name; });
|
||||
[](const PerformanceEntry& e) { return e.name; });
|
||||
return res;
|
||||
}
|
||||
|
||||
static std::vector<int32_t> getTypes(
|
||||
const std::vector<RawPerformanceEntry>& entries) {
|
||||
std::vector<int32_t> res;
|
||||
static std::vector<PerformanceEntryType> getTypes(
|
||||
const std::vector<PerformanceEntry>& entries) {
|
||||
std::vector<PerformanceEntryType> res;
|
||||
std::transform(
|
||||
entries.begin(),
|
||||
entries.end(),
|
||||
std::back_inserter(res),
|
||||
[](const RawPerformanceEntry& e) { return e.entryType; });
|
||||
[](const PerformanceEntry& e) { return e.entryType; });
|
||||
return res;
|
||||
}
|
||||
|
||||
@@ -270,10 +280,34 @@ TEST(PerformanceEntryReporter, PerformanceEntryReporterTestGetEntries) {
|
||||
reporter.getEntries();
|
||||
const auto all = reporter.getEntries();
|
||||
|
||||
ASSERT_EQ(std::vector<int32_t>({2, 2, 2, 2, 2}), getTypes(measures));
|
||||
ASSERT_EQ(std::vector<int32_t>({1, 2}), getTypes(common_name));
|
||||
ASSERT_EQ(std::vector<int32_t>({1, 1, 1, 2, 2, 2, 2, 2}), getTypes(all));
|
||||
ASSERT_EQ(std::vector<int32_t>({1, 1, 1}), getTypes(marks));
|
||||
ASSERT_EQ(
|
||||
std::vector(
|
||||
{PerformanceEntryType::MEASURE,
|
||||
PerformanceEntryType::MEASURE,
|
||||
PerformanceEntryType::MEASURE,
|
||||
PerformanceEntryType::MEASURE,
|
||||
PerformanceEntryType::MEASURE}),
|
||||
getTypes(measures));
|
||||
ASSERT_EQ(
|
||||
std::vector({PerformanceEntryType::MARK, PerformanceEntryType::MEASURE}),
|
||||
getTypes(common_name));
|
||||
ASSERT_EQ(
|
||||
std::vector(
|
||||
{PerformanceEntryType::MARK,
|
||||
PerformanceEntryType::MARK,
|
||||
PerformanceEntryType::MARK,
|
||||
PerformanceEntryType::MEASURE,
|
||||
PerformanceEntryType::MEASURE,
|
||||
PerformanceEntryType::MEASURE,
|
||||
PerformanceEntryType::MEASURE,
|
||||
PerformanceEntryType::MEASURE}),
|
||||
getTypes(all));
|
||||
ASSERT_EQ(
|
||||
std::vector(
|
||||
{PerformanceEntryType::MARK,
|
||||
PerformanceEntryType::MARK,
|
||||
PerformanceEntryType::MARK}),
|
||||
getTypes(marks));
|
||||
|
||||
ASSERT_EQ(
|
||||
std::vector<std::string>({"common_name", "mark1", "mark2"}),
|
||||
|
||||
Reference in New Issue
Block a user