Skip to content

Commit

Permalink
Make SystraceSection feed into Instruments signposts API (facebook#44496
Browse files Browse the repository at this point in the history
)

Summary:

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

Differential Revision: D56280451
  • Loading branch information
lyahdav authored and facebook-github-bot committed May 9, 2024
1 parent a45c589 commit fb50bc2
Showing 1 changed file with 99 additions and 3 deletions.
102 changes: 99 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,17 @@
#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>
#endif

#endif

namespace facebook::react {

/**
Expand All @@ -20,7 +31,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 +55,7 @@ struct ConcreteSystraceSection {
private:
fbsystrace::FbSystraceSection m_section;
};
using SystraceSection = ConcreteSystraceSection;
using SystraceSectionUnwrapped = ConcreteSystraceSection;
#else
struct DummySystraceSection {
public:
Expand All @@ -53,7 +64,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_);
}

private:
os_signpost_id_t signpostID_ = OS_SIGNPOST_ID_INVALID;
const char* name_;
SystraceSectionUnwrapped systraceSectionUnwrapped_;
};
#else
#define SystraceSection SystraceSectionUnwrapped
#endif

} // namespace facebook::react

0 comments on commit fb50bc2

Please sign in to comment.