Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@
#include "NativePerformance.h"

#include <memory>
#include <mutex>
#include <unordered_map>
#include <variant>

#include <cxxreact/JSExecutor.h>
#include <cxxreact/ReactMarker.h>
Expand Down Expand Up @@ -47,6 +47,40 @@ void sortEntries(std::vector<PerformanceEntry>& entries) {
entries.begin(), entries.end(), PerformanceEntrySorter{});
}

NativePerformanceEntry toNativePerformanceEntry(const PerformanceEntry& entry) {
auto nativeEntry = std::visit(
[](const auto& entryData) -> NativePerformanceEntry {
return {
.name = entryData.name,
.entryType = entryData.entryType,
.startTime = entryData.startTime,
.duration = entryData.duration,
};
},
entry);

if (std::holds_alternative<PerformanceEventTiming>(entry)) {
auto eventEntry = std::get<PerformanceEventTiming>(entry);
nativeEntry.processingStart = eventEntry.processingStart;
nativeEntry.processingEnd = eventEntry.processingEnd;
nativeEntry.interactionId = eventEntry.interactionId;
}

return nativeEntry;
}

std::vector<NativePerformanceEntry> toNativePerformanceEntries(
std::vector<PerformanceEntry>& entries) {
std::vector<NativePerformanceEntry> result;
result.reserve(entries.size());

for (auto& entry : entries) {
result.emplace_back(toNativePerformanceEntry(entry));
}

return result;
}

const std::array<PerformanceEntryType, 2> ENTRY_TYPES_AVAILABLE_FROM_TIMELINE{
{PerformanceEntryType::MARK, PerformanceEntryType::MEASURE}};

Expand Down Expand Up @@ -122,7 +156,7 @@ void NativePerformance::clearMeasures(
}
}

std::vector<PerformanceEntry> NativePerformance::getEntries(
std::vector<NativePerformanceEntry> NativePerformance::getEntries(
jsi::Runtime& /*rt*/) {
std::vector<PerformanceEntry> entries;

Expand All @@ -132,10 +166,10 @@ std::vector<PerformanceEntry> NativePerformance::getEntries(

sortEntries(entries);

return entries;
return toNativePerformanceEntries(entries);
}

std::vector<PerformanceEntry> NativePerformance::getEntriesByName(
std::vector<NativePerformanceEntry> NativePerformance::getEntriesByName(
jsi::Runtime& /*rt*/,
std::string entryName,
std::optional<PerformanceEntryType> entryType) {
Expand All @@ -155,10 +189,10 @@ std::vector<PerformanceEntry> NativePerformance::getEntriesByName(

sortEntries(entries);

return entries;
return toNativePerformanceEntries(entries);
}

std::vector<PerformanceEntry> NativePerformance::getEntriesByType(
std::vector<NativePerformanceEntry> NativePerformance::getEntriesByType(
jsi::Runtime& /*rt*/,
PerformanceEntryType entryType) {
std::vector<PerformanceEntry> entries;
Expand All @@ -169,7 +203,7 @@ std::vector<PerformanceEntry> NativePerformance::getEntriesByType(

sortEntries(entries);

return entries;
return toNativePerformanceEntries(entries);
}

std::vector<std::pair<std::string, uint32_t>> NativePerformance::getEventCounts(
Expand Down Expand Up @@ -304,7 +338,7 @@ void NativePerformance::disconnect(jsi::Runtime& rt, jsi::Object observerObj) {
observer->disconnect();
}

std::vector<PerformanceEntry> NativePerformance::takeRecords(
std::vector<NativePerformanceEntry> NativePerformance::takeRecords(
jsi::Runtime& rt,
jsi::Object observerObj,
bool sort) {
Expand All @@ -320,7 +354,7 @@ std::vector<PerformanceEntry> NativePerformance::takeRecords(
if (sort) {
sortEntries(records);
}
return records;
return toNativePerformanceEntries(records);
}

std::vector<PerformanceEntryType>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,23 @@ struct Bridging<PerformanceEntryType> {
}
};

// Our Native Module codegen does not support JS type unions, so we use a
// flattened object here as an intermediate format.
struct NativePerformanceEntry {
std::string name;
PerformanceEntryType entryType;
DOMHighResTimeStamp startTime;
DOMHighResTimeStamp duration;

// For PerformanceEventTiming only
std::optional<DOMHighResTimeStamp> processingStart;
std::optional<DOMHighResTimeStamp> processingEnd;
std::optional<PerformanceEntryInteractionId> interactionId;
};

template <>
struct Bridging<PerformanceEntry>
: NativePerformanceRawPerformanceEntryBridging<PerformanceEntry> {};
struct Bridging<NativePerformanceEntry>
: NativePerformanceRawPerformanceEntryBridging<NativePerformanceEntry> {};

template <>
struct Bridging<NativePerformancePerformanceObserverObserveOptions>
Expand Down Expand Up @@ -98,15 +112,15 @@ class NativePerformance : public NativePerformanceCxxSpec<NativePerformance> {
#pragma mark - Performance Timeline (https://w3c.github.io/performance-timeline/#performance-timeline)

// https://www.w3.org/TR/performance-timeline/#getentries-method
std::vector<PerformanceEntry> getEntries(jsi::Runtime& rt);
std::vector<NativePerformanceEntry> getEntries(jsi::Runtime& rt);

// https://www.w3.org/TR/performance-timeline/#getentriesbytype-method
std::vector<PerformanceEntry> getEntriesByType(
std::vector<NativePerformanceEntry> getEntriesByType(
jsi::Runtime& rt,
PerformanceEntryType entryType);

// https://www.w3.org/TR/performance-timeline/#getentriesbyname-method
std::vector<PerformanceEntry> getEntriesByName(
std::vector<NativePerformanceEntry> getEntriesByName(
jsi::Runtime& rt,
std::string entryName,
std::optional<PerformanceEntryType> entryType = std::nullopt);
Expand All @@ -125,7 +139,7 @@ class NativePerformance : public NativePerformanceCxxSpec<NativePerformance> {
jsi::Object observer,
NativePerformancePerformanceObserverObserveOptions options);
void disconnect(jsi::Runtime& rt, jsi::Object observer);
std::vector<PerformanceEntry> takeRecords(
std::vector<NativePerformanceEntry> takeRecords(
jsi::Runtime& rt,
jsi::Object observerObj,
// When called via `observer.takeRecords` it should be in insertion order.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
#include <algorithm>
#include <functional>
#include <vector>
#include "PerformanceEntry.h"

namespace facebook::react {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,8 @@
#pragma once

#include <react/timing/primitives.h>
#include <optional>
#include <string>
#include <unordered_set>
#include <variant>

namespace facebook::react {

Expand All @@ -25,28 +24,50 @@ enum class PerformanceEntryType {
_NEXT = 5,
};

struct PerformanceEntry {
struct AbstractPerformanceEntry {
std::string name;
PerformanceEntryType entryType;
DOMHighResTimeStamp startTime;
DOMHighResTimeStamp duration = 0;
};

struct PerformanceMark : AbstractPerformanceEntry {
static constexpr PerformanceEntryType entryType = PerformanceEntryType::MARK;
};

struct PerformanceMeasure : AbstractPerformanceEntry {
static constexpr PerformanceEntryType entryType =
PerformanceEntryType::MEASURE;
};

struct PerformanceEventTiming : AbstractPerformanceEntry {
static constexpr PerformanceEntryType entryType = PerformanceEntryType::EVENT;
DOMHighResTimeStamp processingStart;
DOMHighResTimeStamp processingEnd;
PerformanceEntryInteractionId interactionId;
};

// For "event" entries only:
std::optional<DOMHighResTimeStamp> processingStart;
std::optional<DOMHighResTimeStamp> processingEnd;
std::optional<PerformanceEntryInteractionId> interactionId;
struct PerformanceLongTaskTiming : AbstractPerformanceEntry {
static constexpr PerformanceEntryType entryType =
PerformanceEntryType::LONGTASK;
};

constexpr size_t NUM_PERFORMANCE_ENTRY_TYPES =
(size_t)PerformanceEntryType::_NEXT - 1; // Valid types start from 1.
using PerformanceEntry = std::variant<
PerformanceMark,
PerformanceMeasure,
PerformanceEventTiming,
PerformanceLongTaskTiming>;

struct PerformanceEntrySorter {
bool operator()(const PerformanceEntry& lhs, const PerformanceEntry& rhs) {
if (lhs.startTime != rhs.startTime) {
return lhs.startTime < rhs.startTime;
} else {
return lhs.duration < rhs.duration;
}
return std::visit(
[](const auto& left, const auto& right) {
if (left.startTime != right.startTime) {
return left.startTime < right.startTime;
}
return left.duration < right.duration;
},
lhs,
rhs);
}
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@

#include "PerformanceEntryCircularBuffer.h"

#include <variant>

namespace facebook::react {

void PerformanceEntryCircularBuffer::add(const PerformanceEntry& entry) {
Expand All @@ -23,16 +25,23 @@ void PerformanceEntryCircularBuffer::getEntries(
void PerformanceEntryCircularBuffer::getEntries(
std::vector<PerformanceEntry>& target,
const std::string& name) const {
buffer_.getEntries(
target, [&](const PerformanceEntry& e) { return e.name == name; });
buffer_.getEntries(target, [&](const PerformanceEntry& entry) {
return std::visit(
[&name](const auto& entryData) { return entryData.name == name; },
entry);
});
}

void PerformanceEntryCircularBuffer::clear() {
buffer_.clear();
}

void PerformanceEntryCircularBuffer::clear(const std::string& name) {
buffer_.clear([&](const PerformanceEntry& e) { return e.name == name; });
buffer_.clear([&](const PerformanceEntry& entry) {
return std::visit(
[&name](const auto& entryData) { return entryData.name == name; },
entry);
});
}

} // namespace facebook::react
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,15 @@
namespace facebook::react {

void PerformanceEntryKeyedBuffer::add(const PerformanceEntry& entry) {
auto node = entryMap_.find(entry.name);
auto name =
std::visit([](const auto& entryData) { return entryData.name; }, entry);

auto node = entryMap_.find(name);

if (node != entryMap_.end()) {
node->second.push_back(entry);
} else {
entryMap_.emplace(entry.name, std::vector<PerformanceEntry>{entry});
entryMap_.emplace(name, std::vector<PerformanceEntry>{entry});
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
#pragma once

#include <optional>
#include <string_view>
#include <unordered_map>
#include <vector>
#include "PerformanceEntryBuffer.h"
Expand Down
Loading
Loading