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 @@ -45,10 +45,8 @@ namespace {
#endif

NO_DESTROY const std::string TRACK_PREFIX = "Track:";
NO_DESTROY const std::string DEFAULT_TRACK_NAME = "# Web Performance";
NO_DESTROY const std::string CUSTOM_TRACK_NAME_PREFIX = "# Web Performance: ";

std::tuple<std::string, std::string_view> parseTrackName(
std::tuple<std::optional<std::string>, std::string_view> parseTrackName(
const std::string& name) {
// Until there's a standard way to pass through track information, parse it
// manually, e.g., "Track:Foo:Event name"
Expand All @@ -58,16 +56,13 @@ std::tuple<std::string, std::string_view> parseTrackName(
if (name.starts_with(TRACK_PREFIX)) {
const auto trackNameDelimiter = name.find(':', TRACK_PREFIX.length());
if (trackNameDelimiter != std::string::npos) {
trackName = CUSTOM_TRACK_NAME_PREFIX +
name.substr(
TRACK_PREFIX.length(),
trackNameDelimiter - TRACK_PREFIX.length());
trackName = name.substr(
TRACK_PREFIX.length(), trackNameDelimiter - TRACK_PREFIX.length());
eventName = std::string_view(name).substr(trackNameDelimiter + 1);
}
}

auto& trackNameRef = trackName.has_value() ? *trackName : DEFAULT_TRACK_NAME;
return std::make_tuple(trackNameRef, eventName);
return std::make_tuple(trackName, eventName);
}

class PerformanceObserverWrapper : public jsi::NativeState {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,13 @@

namespace facebook::react {

namespace {

/** Process ID for all emitted events. */
const uint64_t PID = 1000;

} // namespace

bool FuseboxTracer::isTracing() {
std::lock_guard lock(mutex_);
return tracing_;
Expand Down Expand Up @@ -43,34 +50,43 @@ bool FuseboxTracer::stopTracing(
}

auto traceEvents = folly::dynamic::array();

// Register "Main" process
traceEvents.push_back(folly::dynamic::object(
"args", folly::dynamic::object("name", "Main"))("cat", "__metadata")(
"name", "process_name")("ph", "M")("pid", PID)("tid", 0)("ts", 0));
// Register "Timings" track
// NOTE: This is a hack to make the trace viewer show a "Timings" track
// adjacent to custom tracks in our current build of Chrome DevTools.
// In future, we should align events exactly.
traceEvents.push_back(folly::dynamic::object(
"args", folly::dynamic::object("name", "Timings"))("cat", "__metadata")(
"name", "thread_name")("ph", "M")("pid", PID)("tid", 1000)("ts", 0));

auto savedBuffer = std::move(buffer_);
buffer_.clear();

std::unordered_map<std::string, uint64_t> trackIdMap;
uint64_t nextTrack = 1000;

// Name the main process. Only one process is supported currently.
traceEvents.push_back(folly::dynamic::object(
"args", folly::dynamic::object("name", "Main App"))("cat", "__metadata")(
"name", "process_name")("ph", "M")("pid", 1000)("tid", 0)("ts", 0));
uint64_t nextTrack = 1001;

for (auto& event : savedBuffer) {
if (!trackIdMap.contains(event.track)) {
// For events with a custom track name, register track
if (event.track.length() && !trackIdMap.contains(event.track)) {
auto trackId = nextTrack++;
trackIdMap[event.track] = trackId;
// New track
traceEvents.push_back(folly::dynamic::object(
"args", folly::dynamic::object("name", event.track))(
"cat", "__metadata")("name", "thread_name")("ph", "M")("pid", 1000)(
"cat", "__metadata")("name", "thread_name")("ph", "M")("pid", PID)(
"tid", trackId)("ts", 0));
}
auto trackId = trackIdMap[event.track];

// New event
auto trackId =
trackIdMap.contains(event.track) ? trackIdMap[event.track] : 1000;

// Emit "blink.user_timing" trace event
traceEvents.push_back(folly::dynamic::object(
"args", folly::dynamic::object())("cat", "react.native")(
"args", folly::dynamic::object())("cat", "blink.user_timing")(
"dur", (event.end - event.start) * 1000)("name", event.name)("ph", "X")(
"ts", event.start * 1000)("pid", 1000)("tid", trackId));
"ts", event.start * 1000)("pid", PID)("tid", trackId));

if (traceEvents.size() >= 1000) {
resultCallback(traceEvents);
Expand All @@ -88,13 +104,13 @@ void FuseboxTracer::addEvent(
const std::string_view& name,
uint64_t start,
uint64_t end,
const std::string_view& track) {
const std::optional<std::string_view>& track) {
std::lock_guard<std::mutex> lock(mutex_);
if (!tracing_) {
return;
}
buffer_.push_back(
BufferEvent{start, end, std::string(name), std::string(track)});
buffer_.push_back(BufferEvent{
start, end, std::string(name), std::string(track.value_or(""))});
}

bool FuseboxTracer::stopTracingAndWriteToFile(const std::string& path) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,11 @@

#pragma once

#include "folly/dynamic.h"

#include <functional>
#include <optional>
#include <vector>
#include "folly/dynamic.h"

namespace facebook::react {

Expand Down Expand Up @@ -38,7 +40,7 @@ class FuseboxTracer {
const std::string_view& name,
uint64_t start,
uint64_t end,
const std::string_view& track);
const std::optional<std::string_view>& track);

static FuseboxTracer& getFuseboxTracer();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,23 +14,41 @@
#endif
#include <chrono>

#ifdef WITH_PERFETTO
#include "ReactPerfetto.h"
#endif

namespace facebook::react {

#ifdef WITH_PERFETTO
namespace {

const std::string PERFETTO_DEFAULT_TRACK_NAME = "# Web Performance";
const std::string PERFETTO_TRACK_NAME_PREFIX = "# Web Performance: ";

std::string toPerfettoTrackName(
const std::optional<std::string_view>& trackName) {
return trackName.has_value()
? PERFETTO_TRACK_NAME_PREFIX + std::string(trackName.value())
: PERFETTO_DEFAULT_TRACK_NAME;
}

} // namespace
#endif

/* static */ void ReactPerfLogger::measure(
const std::string_view& eventName,
double startTime,
double endTime,
const std::string_view& trackName) {
const std::optional<std::string_view>& trackName) {
#ifdef HAS_FUSEBOX
FuseboxTracer::getFuseboxTracer().addEvent(
eventName, (uint64_t)startTime, (uint64_t)endTime, trackName);
#endif

#ifdef WITH_PERFETTO
if (TRACE_EVENT_CATEGORY_ENABLED("react-native")) {
auto track = getPerfettoWebPerfTrackAsync(std::string(trackName));
auto track = getPerfettoWebPerfTrackAsync(toPerfettoTrackName(trackName));
TRACE_EVENT_BEGIN(
"react-native",
perfetto::DynamicString(eventName.data(), eventName.size()),
Expand All @@ -45,15 +63,15 @@ namespace facebook::react {
/* static */ void ReactPerfLogger::mark(
const std::string_view& eventName,
double startTime,
const std::string_view& trackName) {
const std::optional<std::string_view>& trackName) {
// TODO(T203046480) Support mark in FuseboxTracer

#ifdef WITH_PERFETTO
if (TRACE_EVENT_CATEGORY_ENABLED("react-native")) {
TRACE_EVENT_INSTANT(
"react-native",
perfetto::DynamicString(eventName.data(), eventName.size()),
getPerfettoWebPerfTrackSync(std::string(trackName)),
getPerfettoWebPerfTrackSync(toPerfettoTrackName(trackName)),
performanceNowToPerfettoTraceTime(startTime));
}
#endif
Expand All @@ -62,4 +80,5 @@ namespace facebook::react {
/* static */ double ReactPerfLogger::performanceNow() {
return chronoToDOMHighResTimeStamp(std::chrono::steady_clock::now());
}

} // namespace facebook::react
Original file line number Diff line number Diff line change
Expand Up @@ -8,26 +8,30 @@
#pragma once

#include <reactperflogger/ReactPerfettoCategories.h>

#include <optional>
#include <string>

namespace facebook::react {

/**
* An internal interface for logging performance events to configured React
* Native performance tools, such as Perfetto or React Native DevTools.
*
* Approximates https://w3c.github.io/user-timing/.
*/
class ReactPerfLogger {
public:
static void mark(
const std::string_view& eventName,
double startTime,
const std::string_view& trackName);
const std::optional<std::string_view>& trackName);

/**
* This accepts performance events that should go to internal tracing
* frameworks like Perfetto, and should go to DevTools like Fusebox.
*/
static void measure(
const std::string_view& eventName,
double startTime,
double endTime,
const std::string_view& trackName);
const std::optional<std::string_view>& trackName);

static double performanceNow();
};
Expand Down