Skip to content

Commit

Permalink
Make SystraceSection feed into Instruments signposts API (#44496)
Browse files Browse the repository at this point in the history
Summary:
Pull Request resolved: #44496

When doing performance profiling on a React Native iOS app and trying to identify bottlenecks on the native side it can be helpful to correlate actions to what is happening inside React Native. We already have the SystraceSection class for this, but it does nothing in open source. This diff allows SystraceSection to feed into the Instruments signpost API on iOS/macOS.

Changelog:
[iOS][Added] - Add Instruments signposts API for SystraceSection

Reviewed By: sammy-SC

Differential Revision: D56280451

fbshipit-source-id: 4e962e932b6b6e09e5953abdc1aa621a2723c91e
  • Loading branch information
lyahdav authored and facebook-github-bot committed May 25, 2024
1 parent 91d12d9 commit 840c31c
Showing 1 changed file with 100 additions and 3 deletions.
103 changes: 100 additions & 3 deletions packages/react-native/ReactCommon/cxxreact/SystraceSection.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,18 @@
#include <fbsystrace.h>
#endif

#if defined(__APPLE__)
// This is required so that OS_LOG_TARGET_HAS_10_15_FEATURES will be set.
#include <os/trace_base.h>

#if OS_LOG_TARGET_HAS_10_15_FEATURES && !defined(WITH_LOOM_TRACE)
#include <os/log.h>
#include <os/signpost.h>
#include <sstream>
#endif

#endif

namespace facebook::react {

/**
Expand All @@ -20,7 +32,7 @@ namespace facebook::react {
* use a macro.
*/
#if defined(WITH_LOOM_TRACE)
#define SystraceSection \
#define SystraceSectionUnwrapped \
static constexpr const char systraceSectionFile[] = __FILE__; \
fbsystrace::FbSystraceSection<systraceSectionFile, __LINE__>
/**
Expand All @@ -44,7 +56,7 @@ struct ConcreteSystraceSection {
private:
fbsystrace::FbSystraceSection m_section;
};
using SystraceSection = ConcreteSystraceSection;
using SystraceSectionUnwrapped = ConcreteSystraceSection;
#else
struct DummySystraceSection {
public:
Expand All @@ -53,7 +65,92 @@ struct DummySystraceSection {
const __unused char* name,
__unused ConvertsToStringPiece&&... args) {}
};
using SystraceSection = DummySystraceSection;
using SystraceSectionUnwrapped = DummySystraceSection;
#endif

/**
* On recent Apple platforms we want to leverage the Instruments signposts APIs.
* To not break the other SystraceSection implementations above we wrap them.
* In the case of WITH_LOOM_TRACE we don't use the signposts APIs because of the
* templated type for SystraceSection.
*/
#if defined(__APPLE__) && OS_LOG_TARGET_HAS_10_15_FEATURES && \
!defined(WITH_LOOM_TRACE)
namespace systrace {

template <typename T, typename = void>
struct renderer {
static std::string render(const T& t) {
std::ostringstream oss;
oss << t;
return oss.str();
}
};

template <typename T>
static auto render(const T& t)
-> decltype(renderer<T>::render(std::declval<const T&>())) {
return renderer<T>::render(t);
}

inline os_log_t instrumentsLogHandle = nullptr;

} // namespace systrace

struct SystraceSection {
public:
template <typename... ConvertsToStringPiece>
explicit SystraceSection(const char* name, ConvertsToStringPiece&&... args)
: systraceSectionUnwrapped_(name, args...) {
if (!systrace::instrumentsLogHandle) {
systrace::instrumentsLogHandle = os_log_create(
"dev.reactnative.instruments", OS_LOG_CATEGORY_DYNAMIC_TRACING);
}

// If the log isn't enabled, we don't want the performance overhead of the
// rest of the code below.
if (!os_signpost_enabled(systrace::instrumentsLogHandle)) {
return;
}

name_ = name;

const auto argsVector = std::vector<std::string>{systrace::render(args)...};
std::string argsString = "";
for (size_t i = 0; i < argsVector.size(); i += 2) {
argsString += argsVector[i] + "=" + argsVector[i + 1] + ";";
}

signpostID_ =
os_signpost_id_make_with_pointer(systrace::instrumentsLogHandle, this);

os_signpost_interval_begin(
systrace::instrumentsLogHandle,
signpostID_,
"SystraceSection",
"%s begin: %s",
name,
argsString.c_str());
}

~SystraceSection() {
// We don't need to gate on os_signpost_enabled here because it's already
// checked in os_signpost_interval_end.
os_signpost_interval_end(
systrace::instrumentsLogHandle,
signpostID_,
"SystraceSection",
"%s end",
name_.data());
}

private:
os_signpost_id_t signpostID_ = OS_SIGNPOST_ID_INVALID;
std::string_view name_;
SystraceSectionUnwrapped systraceSectionUnwrapped_;
};
#else
#define SystraceSection SystraceSectionUnwrapped
#endif

} // namespace facebook::react

0 comments on commit 840c31c

Please sign in to comment.