first commit

This commit is contained in:
2026-03-10 16:18:05 +00:00
commit 11f9c069b5
31635 changed files with 3187747 additions and 0 deletions

View File

@@ -0,0 +1,28 @@
# Copyright (c) Meta Platforms, Inc. and affiliates.
#
# This source code is licensed under the MIT license found in the
# LICENSE file in the root directory of this source tree.
cmake_minimum_required(VERSION 3.13)
set(CMAKE_VERBOSE_MAKEFILE on)
include(${REACT_COMMON_DIR}/cmake-utils/react-native-flags.cmake)
file(GLOB react_renderer_telemetry_SRC CONFIGURE_DEPENDS *.cpp)
add_library(react_renderer_telemetry OBJECT ${react_renderer_telemetry_SRC})
target_include_directories(react_renderer_telemetry PUBLIC ${REACT_COMMON_DIR})
target_link_libraries(react_renderer_telemetry
folly_runtime
glog
glog_init
react_debug
react_renderer_core
react_renderer_debug
react_utils
rrc_root
rrc_view
yoga)
target_compile_reactnative_options(react_renderer_telemetry PRIVATE)
target_compile_options(react_renderer_telemetry PRIVATE -Wpedantic)

View File

@@ -0,0 +1,83 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#include "SurfaceTelemetry.h"
#include <algorithm>
namespace facebook::react {
void SurfaceTelemetry::incorporate(
const TransactionTelemetry& telemetry,
int numberOfMutations) {
layoutTime_ += telemetry.getLayoutEndTime() - telemetry.getLayoutStartTime();
textMeasureTime_ += telemetry.getTextMeasureTime();
commitTime_ += telemetry.getCommitEndTime() - telemetry.getCommitStartTime();
diffTime_ += telemetry.getDiffEndTime() - telemetry.getDiffStartTime();
mountTime_ += telemetry.getMountEndTime() - telemetry.getMountStartTime();
numberOfTransactions_++;
numberOfMutations_ += numberOfMutations;
numberOfTextMeasurements_ += telemetry.getNumberOfTextMeasurements();
lastRevisionNumber_ = telemetry.getRevisionNumber();
while (recentTransactionTelemetries_.size() >=
kMaxNumberOfRecordedCommitTelemetries) {
recentTransactionTelemetries_.erase(recentTransactionTelemetries_.begin());
}
recentTransactionTelemetries_.push_back(telemetry);
}
TelemetryDuration SurfaceTelemetry::getLayoutTime() const {
return layoutTime_;
}
TelemetryDuration SurfaceTelemetry::getTextMeasureTime() const {
return textMeasureTime_;
}
TelemetryDuration SurfaceTelemetry::getCommitTime() const {
return commitTime_;
}
TelemetryDuration SurfaceTelemetry::getDiffTime() const {
return diffTime_;
}
TelemetryDuration SurfaceTelemetry::getMountTime() const {
return mountTime_;
}
int SurfaceTelemetry::getNumberOfTransactions() const {
return numberOfTransactions_;
}
int SurfaceTelemetry::getNumberOfMutations() const {
return numberOfMutations_;
}
int SurfaceTelemetry::getNumberOfTextMeasurements() const {
return numberOfTextMeasurements_;
}
int SurfaceTelemetry::getLastRevisionNumber() const {
return lastRevisionNumber_;
}
std::vector<TransactionTelemetry>
SurfaceTelemetry::getRecentTransactionTelemetries() const {
auto result = std::vector<TransactionTelemetry>{};
result.reserve(recentTransactionTelemetries_.size());
std::copy(
recentTransactionTelemetries_.begin(),
recentTransactionTelemetries_.end(),
std::back_inserter(result));
return result;
}
} // namespace facebook::react

View File

@@ -0,0 +1,62 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#pragma once
#include <vector>
#include <react/renderer/telemetry/TransactionTelemetry.h>
#include <react/utils/Telemetry.h>
namespace facebook::react {
/*
* Represents telemetry data associated with a particular running Surface.
* Contains information aggregated from multiple completed transaction.
*/
class SurfaceTelemetry final {
public:
constexpr static size_t kMaxNumberOfRecordedCommitTelemetries = 16;
/*
* Metrics
*/
TelemetryDuration getLayoutTime() const;
TelemetryDuration getTextMeasureTime() const;
TelemetryDuration getCommitTime() const;
TelemetryDuration getDiffTime() const;
TelemetryDuration getMountTime() const;
int getNumberOfTransactions() const;
int getNumberOfMutations() const;
int getNumberOfTextMeasurements() const;
int getLastRevisionNumber() const;
std::vector<TransactionTelemetry> getRecentTransactionTelemetries() const;
/*
* Incorporate data from given transaction telemetry into aggregated data
* for the Surface.
*/
void incorporate(const TransactionTelemetry &telemetry, int numberOfMutations);
private:
TelemetryDuration layoutTime_{};
TelemetryDuration commitTime_{};
TelemetryDuration textMeasureTime_{};
TelemetryDuration diffTime_{};
TelemetryDuration mountTime_{};
int numberOfTransactions_{};
int numberOfMutations_{};
int numberOfTextMeasurements_{};
int lastRevisionNumber_{};
std::vector<TransactionTelemetry> recentTransactionTelemetries_{};
};
} // namespace facebook::react

View File

@@ -0,0 +1,172 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#include "TransactionTelemetry.h"
#include <react/debug/react_native_assert.h>
#include <utility>
namespace facebook::react {
thread_local TransactionTelemetry* threadLocalTransactionTelemetry = nullptr;
TransactionTelemetry::TransactionTelemetry()
: TransactionTelemetry(telemetryTimePointNow) {}
TransactionTelemetry::TransactionTelemetry(
std::function<TelemetryTimePoint()> now)
: now_{std::move(now)} {}
TransactionTelemetry* TransactionTelemetry::threadLocalTelemetry() {
return threadLocalTransactionTelemetry;
}
void TransactionTelemetry::setAsThreadLocal() {
threadLocalTransactionTelemetry = this;
}
void TransactionTelemetry::unsetAsThreadLocal() {
threadLocalTransactionTelemetry = nullptr;
}
void TransactionTelemetry::willCommit() {
react_native_assert(commitStartTime_ == kTelemetryUndefinedTimePoint);
react_native_assert(commitEndTime_ == kTelemetryUndefinedTimePoint);
commitStartTime_ = now_();
}
void TransactionTelemetry::didCommit() {
react_native_assert(commitStartTime_ != kTelemetryUndefinedTimePoint);
react_native_assert(commitEndTime_ == kTelemetryUndefinedTimePoint);
commitEndTime_ = now_();
}
void TransactionTelemetry::willDiff() {
react_native_assert(diffStartTime_ == kTelemetryUndefinedTimePoint);
react_native_assert(diffEndTime_ == kTelemetryUndefinedTimePoint);
diffStartTime_ = now_();
}
void TransactionTelemetry::didDiff() {
react_native_assert(diffStartTime_ != kTelemetryUndefinedTimePoint);
react_native_assert(diffEndTime_ == kTelemetryUndefinedTimePoint);
diffEndTime_ = now_();
}
void TransactionTelemetry::willLayout() {
react_native_assert(layoutStartTime_ == kTelemetryUndefinedTimePoint);
react_native_assert(layoutEndTime_ == kTelemetryUndefinedTimePoint);
layoutStartTime_ = now_();
}
void TransactionTelemetry::willMeasureText() {
react_native_assert(
lastTextMeasureStartTime_ == kTelemetryUndefinedTimePoint);
lastTextMeasureStartTime_ = now_();
}
void TransactionTelemetry::didMeasureText() {
numberOfTextMeasurements_++;
react_native_assert(
lastTextMeasureStartTime_ != kTelemetryUndefinedTimePoint);
textMeasureTime_ += now_() - lastTextMeasureStartTime_;
lastTextMeasureStartTime_ = kTelemetryUndefinedTimePoint;
}
void TransactionTelemetry::didLayout() {
react_native_assert(layoutStartTime_ != kTelemetryUndefinedTimePoint);
react_native_assert(layoutEndTime_ == kTelemetryUndefinedTimePoint);
layoutEndTime_ = now_();
}
void TransactionTelemetry::didLayout(int affectedLayoutNodesCount) {
didLayout();
affectedLayoutNodesCount_ = affectedLayoutNodesCount;
}
void TransactionTelemetry::willMount() {
react_native_assert(mountStartTime_ == kTelemetryUndefinedTimePoint);
react_native_assert(mountEndTime_ == kTelemetryUndefinedTimePoint);
mountStartTime_ = now_();
}
void TransactionTelemetry::didMount() {
react_native_assert(mountStartTime_ != kTelemetryUndefinedTimePoint);
react_native_assert(mountEndTime_ == kTelemetryUndefinedTimePoint);
mountEndTime_ = now_();
}
void TransactionTelemetry::setRevisionNumber(int revisionNumber) {
revisionNumber_ = revisionNumber;
}
TelemetryTimePoint TransactionTelemetry::getDiffStartTime() const {
react_native_assert(diffStartTime_ != kTelemetryUndefinedTimePoint);
react_native_assert(diffEndTime_ != kTelemetryUndefinedTimePoint);
return diffStartTime_;
}
TelemetryTimePoint TransactionTelemetry::getDiffEndTime() const {
react_native_assert(diffStartTime_ != kTelemetryUndefinedTimePoint);
react_native_assert(diffEndTime_ != kTelemetryUndefinedTimePoint);
return diffEndTime_;
}
TelemetryTimePoint TransactionTelemetry::getCommitStartTime() const {
react_native_assert(commitStartTime_ != kTelemetryUndefinedTimePoint);
react_native_assert(commitEndTime_ != kTelemetryUndefinedTimePoint);
return commitStartTime_;
}
TelemetryTimePoint TransactionTelemetry::getCommitEndTime() const {
react_native_assert(commitStartTime_ != kTelemetryUndefinedTimePoint);
react_native_assert(commitEndTime_ != kTelemetryUndefinedTimePoint);
return commitEndTime_;
}
TelemetryTimePoint TransactionTelemetry::getLayoutStartTime() const {
react_native_assert(layoutStartTime_ != kTelemetryUndefinedTimePoint);
react_native_assert(layoutEndTime_ != kTelemetryUndefinedTimePoint);
return layoutStartTime_;
}
TelemetryTimePoint TransactionTelemetry::getLayoutEndTime() const {
react_native_assert(layoutStartTime_ != kTelemetryUndefinedTimePoint);
react_native_assert(layoutEndTime_ != kTelemetryUndefinedTimePoint);
return layoutEndTime_;
}
TelemetryTimePoint TransactionTelemetry::getMountStartTime() const {
react_native_assert(mountStartTime_ != kTelemetryUndefinedTimePoint);
react_native_assert(mountEndTime_ != kTelemetryUndefinedTimePoint);
return mountStartTime_;
}
TelemetryTimePoint TransactionTelemetry::getMountEndTime() const {
react_native_assert(mountStartTime_ != kTelemetryUndefinedTimePoint);
react_native_assert(mountEndTime_ != kTelemetryUndefinedTimePoint);
return mountEndTime_;
}
TelemetryDuration TransactionTelemetry::getTextMeasureTime() const {
return textMeasureTime_;
}
int TransactionTelemetry::getNumberOfTextMeasurements() const {
return numberOfTextMeasurements_;
}
int TransactionTelemetry::getRevisionNumber() const {
return revisionNumber_;
}
int TransactionTelemetry::getAffectedLayoutNodesCount() const {
return affectedLayoutNodesCount_;
}
} // namespace facebook::react

View File

@@ -0,0 +1,90 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#pragma once
#include <chrono>
#include <cstdint>
#include <functional>
#include <react/utils/Telemetry.h>
namespace facebook::react {
/*
* Represents telemetry data associated with a particular revision of
* `ShadowTree`.
*/
class TransactionTelemetry final {
public:
/*
* Thread-local Telemetry instance
*/
static TransactionTelemetry *threadLocalTelemetry();
TransactionTelemetry();
TransactionTelemetry(std::function<TelemetryTimePoint()> now);
void setAsThreadLocal();
void unsetAsThreadLocal();
/*
* Signaling
*/
void willDiff();
void didDiff();
void willCommit();
void didCommit();
void willLayout();
void willMeasureText();
void didMeasureText();
void didLayout();
void didLayout(int affectedLayoutNodesCount);
void willMount();
void didMount();
void setRevisionNumber(int revisionNumber);
/*
* Reading
*/
TelemetryTimePoint getDiffStartTime() const;
TelemetryTimePoint getDiffEndTime() const;
TelemetryTimePoint getLayoutStartTime() const;
TelemetryTimePoint getLayoutEndTime() const;
TelemetryTimePoint getCommitStartTime() const;
TelemetryTimePoint getCommitEndTime() const;
TelemetryTimePoint getMountStartTime() const;
TelemetryTimePoint getMountEndTime() const;
TelemetryDuration getTextMeasureTime() const;
int getNumberOfTextMeasurements() const;
int getRevisionNumber() const;
int getAffectedLayoutNodesCount() const;
private:
TelemetryTimePoint diffStartTime_{kTelemetryUndefinedTimePoint};
TelemetryTimePoint diffEndTime_{kTelemetryUndefinedTimePoint};
TelemetryTimePoint commitStartTime_{kTelemetryUndefinedTimePoint};
TelemetryTimePoint commitEndTime_{kTelemetryUndefinedTimePoint};
TelemetryTimePoint layoutStartTime_{kTelemetryUndefinedTimePoint};
TelemetryTimePoint layoutEndTime_{kTelemetryUndefinedTimePoint};
TelemetryTimePoint mountStartTime_{kTelemetryUndefinedTimePoint};
TelemetryTimePoint mountEndTime_{kTelemetryUndefinedTimePoint};
TelemetryTimePoint lastTextMeasureStartTime_{kTelemetryUndefinedTimePoint};
TelemetryDuration textMeasureTime_{0};
int numberOfTextMeasurements_{0};
int revisionNumber_{0};
std::function<TelemetryTimePoint()> now_;
int affectedLayoutNodesCount_{0};
};
} // namespace facebook::react

View File

@@ -0,0 +1,176 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#include <chrono>
#include <thread>
#include <gtest/gtest.h>
#include <react/renderer/telemetry/TransactionTelemetry.h>
#include <react/test_utils/MockClock.h>
#include <react/utils/Telemetry.h>
using namespace facebook::react;
MockClock::time_point MockClock::time_ = {};
/**
* Ensures that the at least the specified time passes on a real clock.
* Why at least? Because operating systems provide no guarantee that our thread
* gets processing time after the specified time. What about using a busywait?
* Busywait are also affected by the non-deterministic OS process scheduling.
* The OS might decide right before the specified time elapsed to schedule
* another thread/process, with the result that more time passes in reality than
* the caller intended. Prefer the `MockClock` and only use this function to
* verify that at least the specified time has passed but without making exact
* verifications.
*/
static void sleepAtLeast(double durationInSeconds) {
std::this_thread::sleep_for(
std::chrono::milliseconds((long long)(durationInSeconds * 1000)));
}
TEST(TransactionTelemetryTest, timepoints) {
auto timepointA = telemetryTimePointNow();
sleepAtLeast(0.1);
auto timepointB = telemetryTimePointNow();
auto duration = telemetryDurationToMilliseconds(timepointB - timepointA);
EXPECT_GE(duration, 100);
}
TEST(TransactionTelemetryTest, normalUseCase) {
auto telemetry = TransactionTelemetry{[]() { return MockClock::now(); }};
telemetry.setAsThreadLocal();
telemetry.willCommit();
MockClock::advance_by(std::chrono::milliseconds(100));
telemetry.willLayout();
MockClock::advance_by(std::chrono::milliseconds(200));
TransactionTelemetry::threadLocalTelemetry()->willMeasureText();
MockClock::advance_by(std::chrono::milliseconds(100));
TransactionTelemetry::threadLocalTelemetry()->didMeasureText();
TransactionTelemetry::threadLocalTelemetry()->willMeasureText();
MockClock::advance_by(std::chrono::milliseconds(200));
TransactionTelemetry::threadLocalTelemetry()->didMeasureText();
TransactionTelemetry::threadLocalTelemetry()->willMeasureText();
MockClock::advance_by(std::chrono::milliseconds(300));
TransactionTelemetry::threadLocalTelemetry()->didMeasureText();
telemetry.didLayout();
MockClock::advance_by(std::chrono::milliseconds(100));
telemetry.didCommit();
telemetry.setRevisionNumber(42);
telemetry.unsetAsThreadLocal();
MockClock::advance_by(std::chrono::milliseconds(300));
telemetry.willMount();
MockClock::advance_by(std::chrono::milliseconds(100));
telemetry.didMount();
auto commitDuration = telemetryDurationToMilliseconds(
telemetry.getCommitEndTime() - telemetry.getCommitStartTime());
auto layoutDuration = telemetryDurationToMilliseconds(
telemetry.getLayoutEndTime() - telemetry.getLayoutStartTime());
auto mountDuration = telemetryDurationToMilliseconds(
telemetry.getMountEndTime() - telemetry.getMountStartTime());
EXPECT_EQ(commitDuration, 1000);
EXPECT_EQ(layoutDuration, 800);
EXPECT_EQ(mountDuration, 100);
EXPECT_EQ(telemetry.getNumberOfTextMeasurements(), 3);
EXPECT_EQ(
telemetryDurationToMilliseconds(telemetry.getTextMeasureTime()), 600);
EXPECT_EQ(telemetry.getRevisionNumber(), 42);
}
TEST(TransactionTelemetryTest, defaultImplementation) {
auto telemetry = TransactionTelemetry{};
telemetry.setAsThreadLocal();
telemetry.willCommit();
sleepAtLeast(0.1);
telemetry.willLayout();
sleepAtLeast(0.2);
TransactionTelemetry::threadLocalTelemetry()->willMeasureText();
sleepAtLeast(0.1);
TransactionTelemetry::threadLocalTelemetry()->didMeasureText();
telemetry.didLayout();
sleepAtLeast(0.1);
telemetry.didCommit();
telemetry.unsetAsThreadLocal();
telemetry.willMount();
sleepAtLeast(0.1);
telemetry.didMount();
auto commitDuration = telemetryDurationToMilliseconds(
telemetry.getCommitEndTime() - telemetry.getCommitStartTime());
auto layoutDuration = telemetryDurationToMilliseconds(
telemetry.getLayoutEndTime() - telemetry.getLayoutStartTime());
auto mountDuration = telemetryDurationToMilliseconds(
telemetry.getMountEndTime() - telemetry.getMountStartTime());
EXPECT_GE(commitDuration, 500);
EXPECT_GE(layoutDuration, 300);
EXPECT_GE(mountDuration, 100);
}
TEST(TransactionTelemetryTest, abnormalUseCases) {
// Calling `did` before `will` should crash.
EXPECT_DEATH_IF_SUPPORTED(
{
auto telemetry = TransactionTelemetry{};
telemetry.didDiff();
},
"diffStartTime_");
EXPECT_DEATH_IF_SUPPORTED(
{
auto telemetry = TransactionTelemetry{};
telemetry.didCommit();
},
"commitStartTime_");
EXPECT_DEATH_IF_SUPPORTED(
{
auto telemetry = TransactionTelemetry{};
telemetry.didMount();
},
"mountStartTime_");
// Getting `start` *or* `end` timepoints before a pair of `will` and `did`
// should crash.
EXPECT_DEATH_IF_SUPPORTED(
{
auto telemetry = TransactionTelemetry{};
telemetry.willCommit();
telemetry.getCommitStartTime();
},
"commitEndTime_");
EXPECT_DEATH_IF_SUPPORTED(
{
auto telemetry = TransactionTelemetry{};
telemetry.willCommit();
telemetry.getCommitEndTime();
},
"commitEndTime_");
}