Remove unused MicroProfiler
Summary:
This was introduced a while ago in D3635319 (0418353249
), and was never really adopted.
Changelog: [Internal]
Reviewed By: JoshuaGross
Differential Revision: D37460402
fbshipit-source-id: 70586b23697e02208c393e556625ae534773177f
This commit is contained in:
Родитель
cf0a0eff1b
Коммит
a5a956bab8
|
@ -146,7 +146,6 @@ rn_xplat_cxx_library(
|
|||
"//xplat/jsi:jsi",
|
||||
react_native_xplat_target("callinvoker:callinvoker"),
|
||||
react_native_xplat_target("jsinspector:jsinspector"),
|
||||
react_native_xplat_target("microprofiler:microprofiler"),
|
||||
react_native_xplat_target("runtimeexecutor:runtimeexecutor"),
|
||||
react_native_xplat_target("reactperflogger:reactperflogger"),
|
||||
react_native_xplat_target("logger:logger"),
|
||||
|
|
|
@ -1,5 +0,0 @@
|
|||
---
|
||||
Checks: '>
|
||||
clang-diagnostic-*,
|
||||
'
|
||||
...
|
|
@ -1,30 +0,0 @@
|
|||
load("//tools/build_defs/oss:rn_defs.bzl", "GLOG_DEP", "cxx_library")
|
||||
|
||||
cxx_library(
|
||||
name = "microprofiler",
|
||||
srcs = [
|
||||
"MicroProfiler.cpp",
|
||||
],
|
||||
header_namespace = "microprofiler",
|
||||
exported_headers = [
|
||||
"MicroProfiler.h",
|
||||
],
|
||||
compiler_flags = [
|
||||
"-Wall",
|
||||
"-Werror",
|
||||
"-std=c++17",
|
||||
"-fexceptions",
|
||||
"-fno-data-sections",
|
||||
],
|
||||
force_static = True,
|
||||
labels = [
|
||||
"pfh:ReactNative_CommonInfrastructurePlaceholder",
|
||||
"supermodule:xplat/default/public.react_native.infra",
|
||||
],
|
||||
visibility = [
|
||||
"PUBLIC",
|
||||
],
|
||||
deps = [
|
||||
GLOG_DEP,
|
||||
],
|
||||
)
|
|
@ -1,252 +0,0 @@
|
|||
/*
|
||||
* 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 <time.h>
|
||||
#include <algorithm>
|
||||
#include <chrono>
|
||||
#include <mutex>
|
||||
#include <sstream>
|
||||
#include <vector>
|
||||
|
||||
#include <glog/logging.h>
|
||||
|
||||
#include "MicroProfiler.h"
|
||||
|
||||
// iOS doesn't support 'thread_local'. If we reimplement this to use
|
||||
// pthread_setspecific we can get rid of this
|
||||
#if defined(__APPLE__)
|
||||
#define MICRO_PROFILER_STUB_IMPLEMENTATION 1
|
||||
#elif !defined(MICRO_PROFILER_STUB_IMPLEMENTATION)
|
||||
#define MICRO_PROFILER_STUB_IMPLEMENTATION 0
|
||||
#endif
|
||||
|
||||
namespace facebook {
|
||||
namespace react {
|
||||
|
||||
#if !MICRO_PROFILER_STUB_IMPLEMENTATION
|
||||
struct TraceData {
|
||||
TraceData();
|
||||
~TraceData();
|
||||
|
||||
void addTime(
|
||||
MicroProfilerName name,
|
||||
uint_fast64_t time,
|
||||
uint_fast32_t internalClockCalls);
|
||||
|
||||
std::thread::id threadId_;
|
||||
uint_fast64_t startTime_;
|
||||
std::atomic_uint_fast64_t times_[MicroProfilerName::__LENGTH__] = {};
|
||||
std::atomic_uint_fast32_t calls_[MicroProfilerName::__LENGTH__] = {};
|
||||
std::atomic_uint_fast32_t
|
||||
childProfileSections_[MicroProfilerName::__LENGTH__] = {};
|
||||
};
|
||||
|
||||
struct ProfilingImpl {
|
||||
std::mutex mutex_;
|
||||
std::vector<TraceData *> allTraceData_;
|
||||
bool isProfiling_ = false;
|
||||
uint_fast64_t startTime_;
|
||||
uint_fast64_t endTime_;
|
||||
uint_fast64_t clockOverhead_;
|
||||
uint_fast64_t profileSectionOverhead_;
|
||||
};
|
||||
|
||||
static ProfilingImpl profiling;
|
||||
thread_local TraceData myTraceData;
|
||||
thread_local uint_fast32_t profileSections = 0;
|
||||
|
||||
static uint_fast64_t nowNs() {
|
||||
struct timespec time;
|
||||
clock_gettime(CLOCK_REALTIME, &time);
|
||||
return uint_fast64_t(1000000000) * time.tv_sec + time.tv_nsec;
|
||||
}
|
||||
|
||||
static uint_fast64_t diffNs(uint_fast64_t start, uint_fast64_t end) {
|
||||
return end - start;
|
||||
}
|
||||
|
||||
static std::string formatTimeNs(uint_fast64_t timeNs) {
|
||||
std::ostringstream out;
|
||||
out.precision(2);
|
||||
if (timeNs < 1000) {
|
||||
out << timeNs << "ns";
|
||||
} else if (timeNs < 1000000) {
|
||||
out << timeNs / 1000.0 << "us";
|
||||
} else {
|
||||
out << std::fixed << timeNs / 1000000.0 << "ms";
|
||||
}
|
||||
return out.str();
|
||||
}
|
||||
|
||||
MicroProfilerSection::MicroProfilerSection(MicroProfilerName name)
|
||||
: isProfiling_(profiling.isProfiling_),
|
||||
name_(name),
|
||||
startNumProfileSections_(profileSections) {
|
||||
if (!isProfiling_) {
|
||||
return;
|
||||
}
|
||||
profileSections++;
|
||||
startTime_ = nowNs();
|
||||
}
|
||||
MicroProfilerSection::~MicroProfilerSection() {
|
||||
if (!isProfiling_ || !profiling.isProfiling_) {
|
||||
return;
|
||||
}
|
||||
auto endTime = nowNs();
|
||||
auto endNumProfileSections = profileSections;
|
||||
myTraceData.addTime(
|
||||
name_,
|
||||
endTime - startTime_,
|
||||
endNumProfileSections - startNumProfileSections_ - 1);
|
||||
}
|
||||
|
||||
TraceData::TraceData() : threadId_(std::this_thread::get_id()) {
|
||||
std::lock_guard<std::mutex> lock(profiling.mutex_);
|
||||
profiling.allTraceData_.push_back(this);
|
||||
}
|
||||
|
||||
TraceData::~TraceData() {
|
||||
std::lock_guard<std::mutex> lock(profiling.mutex_);
|
||||
auto &infos = profiling.allTraceData_;
|
||||
infos.erase(std::remove(infos.begin(), infos.end(), this), infos.end());
|
||||
}
|
||||
|
||||
void TraceData::addTime(
|
||||
MicroProfilerName name,
|
||||
uint_fast64_t time,
|
||||
uint_fast32_t childprofileSections) {
|
||||
times_[name] += time;
|
||||
calls_[name]++;
|
||||
childProfileSections_[name] += childprofileSections;
|
||||
}
|
||||
|
||||
static void printReport() {
|
||||
LOG(ERROR) << "======= MICRO PROFILER REPORT =======";
|
||||
LOG(ERROR) << "- Total Time: "
|
||||
<< formatTimeNs(diffNs(profiling.startTime_, profiling.endTime_));
|
||||
LOG(ERROR) << "- Clock Overhead: " << formatTimeNs(profiling.clockOverhead_);
|
||||
LOG(ERROR) << "- Profiler Section Overhead: "
|
||||
<< formatTimeNs(profiling.profileSectionOverhead_);
|
||||
for (auto info : profiling.allTraceData_) {
|
||||
LOG(ERROR) << "--- Thread ID 0x" << std::hex << info->threadId_ << " ---";
|
||||
for (int i = 0; i < MicroProfilerName::__LENGTH__; i++) {
|
||||
if (info->times_[i] > 0) {
|
||||
auto totalTime = info->times_[i].load();
|
||||
auto calls = info->calls_[i].load();
|
||||
auto clockOverhead = profiling.clockOverhead_ * calls +
|
||||
profiling.profileSectionOverhead_ *
|
||||
info->childProfileSections_[i].load();
|
||||
if (totalTime < clockOverhead) {
|
||||
LOG(ERROR) << "- "
|
||||
<< MicroProfiler::profilingNameToString(
|
||||
static_cast<MicroProfilerName>(i))
|
||||
<< ": "
|
||||
<< "ERROR: Total time was " << totalTime
|
||||
<< "ns but clock overhead was calculated to be "
|
||||
<< clockOverhead << "ns!";
|
||||
} else {
|
||||
auto correctedTime = totalTime - clockOverhead;
|
||||
auto timePerCall = correctedTime / calls;
|
||||
LOG(ERROR) << "- "
|
||||
<< MicroProfiler::profilingNameToString(
|
||||
static_cast<MicroProfilerName>(i))
|
||||
<< ": " << formatTimeNs(correctedTime) << " (" << calls
|
||||
<< " calls, " << formatTimeNs(timePerCall) << "/call)";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void clearProfiling() {
|
||||
CHECK(!profiling.isProfiling_)
|
||||
<< "Trying to clear profiling but profiling was already started!";
|
||||
for (auto info : profiling.allTraceData_) {
|
||||
for (unsigned int i = 0; i < MicroProfilerName::__LENGTH__; i++) {
|
||||
info->times_[i] = 0;
|
||||
info->calls_[i] = 0;
|
||||
info->childProfileSections_[i] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static uint_fast64_t calculateClockOverhead() {
|
||||
int numCalls = 1000000;
|
||||
uint_fast64_t start = nowNs();
|
||||
for (int i = 0; i < numCalls; i++) {
|
||||
nowNs();
|
||||
}
|
||||
uint_fast64_t end = nowNs();
|
||||
return (end - start) / numCalls;
|
||||
}
|
||||
|
||||
static uint_fast64_t calculateProfileSectionOverhead() {
|
||||
int numCalls = 1000000;
|
||||
uint_fast64_t start = nowNs();
|
||||
profiling.isProfiling_ = true;
|
||||
for (int i = 0; i < numCalls; i++) {
|
||||
MICRO_PROFILER_SECTION(static_cast<MicroProfilerName>(0));
|
||||
}
|
||||
uint_fast64_t end = nowNs();
|
||||
profiling.isProfiling_ = false;
|
||||
return (end - start) / numCalls;
|
||||
}
|
||||
|
||||
void MicroProfiler::startProfiling() {
|
||||
CHECK(!profiling.isProfiling_)
|
||||
<< "Trying to start profiling but profiling was already started!";
|
||||
|
||||
profiling.clockOverhead_ = calculateClockOverhead();
|
||||
profiling.profileSectionOverhead_ = calculateProfileSectionOverhead();
|
||||
|
||||
std::lock_guard<std::mutex> lock(profiling.mutex_);
|
||||
clearProfiling();
|
||||
|
||||
profiling.startTime_ = nowNs();
|
||||
profiling.isProfiling_ = true;
|
||||
}
|
||||
|
||||
void MicroProfiler::stopProfiling() {
|
||||
CHECK(profiling.isProfiling_)
|
||||
<< "Trying to stop profiling but profiling hasn't been started!";
|
||||
|
||||
profiling.isProfiling_ = false;
|
||||
profiling.endTime_ = nowNs();
|
||||
|
||||
std::lock_guard<std::mutex> lock(profiling.mutex_);
|
||||
|
||||
printReport();
|
||||
|
||||
clearProfiling();
|
||||
}
|
||||
|
||||
bool MicroProfiler::isProfiling() {
|
||||
return profiling.isProfiling_;
|
||||
}
|
||||
|
||||
void MicroProfiler::runInternalBenchmark() {
|
||||
MicroProfiler::startProfiling();
|
||||
for (int i = 0; i < 1000000; i++) {
|
||||
MICRO_PROFILER_SECTION_NAMED(outer, __INTERNAL_BENCHMARK_OUTER);
|
||||
{ MICRO_PROFILER_SECTION_NAMED(inner, __INTERNAL_BENCHMARK_INNER); }
|
||||
}
|
||||
MicroProfiler::stopProfiling();
|
||||
}
|
||||
#else
|
||||
void MicroProfiler::startProfiling() {
|
||||
CHECK(false)
|
||||
<< "This platform has a stub implementation of the micro profiler and cannot collect traces";
|
||||
}
|
||||
void MicroProfiler::stopProfiling() {}
|
||||
bool MicroProfiler::isProfiling() {
|
||||
return false;
|
||||
}
|
||||
void MicroProfiler::runInternalBenchmark() {}
|
||||
#endif
|
||||
|
||||
} // namespace react
|
||||
} // namespace facebook
|
|
@ -1,89 +0,0 @@
|
|||
/*
|
||||
* 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 <atomic>
|
||||
#include <thread>
|
||||
|
||||
// #define WITH_MICRO_PROFILER 1
|
||||
|
||||
#ifdef WITH_MICRO_PROFILER
|
||||
#define MICRO_PROFILER_SECTION(name) MicroProfilerSection __b(name)
|
||||
#define MICRO_PROFILER_SECTION_NAMED(var_name, name) \
|
||||
MicroProfilerSection var_name(name)
|
||||
#else
|
||||
#define MICRO_PROFILER_SECTION(name)
|
||||
#define MICRO_PROFILER_SECTION_NAMED(var_name, name)
|
||||
#endif
|
||||
|
||||
namespace facebook {
|
||||
namespace react {
|
||||
|
||||
enum MicroProfilerName {
|
||||
__INTERNAL_BENCHMARK_INNER,
|
||||
__INTERNAL_BENCHMARK_OUTER,
|
||||
__LENGTH__,
|
||||
};
|
||||
|
||||
/**
|
||||
* MicroProfiler is a performance profiler for measuring the cumulative impact
|
||||
* of a large number of small-ish calls. This is normally a problem for standard
|
||||
* profilers like Systrace because the overhead of the profiler itself skews the
|
||||
* timings you are able to collect. This is especially a problem when doing
|
||||
* nested calls to profiled functions, as the parent calls will contain the
|
||||
* overhead of their profiling plus the overhead of all their childrens'
|
||||
* profiling.
|
||||
*
|
||||
* MicroProfiler attempts to be low overhead by 1) aggregating timings in memory
|
||||
* and 2) trying to remove estimated profiling overhead from the returned
|
||||
* timings.
|
||||
*
|
||||
* To remove estimated overhead, at the beginning of each trace we calculate the
|
||||
* average cost of profiling a no-op code section, as well as invoking the
|
||||
* average cost of invoking the system clock. The former is subtracted out for
|
||||
* each child profiler section that is invoked within a parent profiler section.
|
||||
* The latter is subtracted from each section, child or not.
|
||||
*
|
||||
* After MicroProfiler::stopProfiling() is called, a table of tracing data is
|
||||
* emitted to glog (which shows up in logcat on Android).
|
||||
*/
|
||||
struct MicroProfiler {
|
||||
static const char *profilingNameToString(MicroProfilerName name) {
|
||||
switch (name) {
|
||||
case __INTERNAL_BENCHMARK_INNER:
|
||||
return "__INTERNAL_BENCHMARK_INNER";
|
||||
case __INTERNAL_BENCHMARK_OUTER:
|
||||
return "__INTERNAL_BENCHMARK_OUTER";
|
||||
case __LENGTH__:
|
||||
throw std::runtime_error("__LENGTH__ has no name");
|
||||
default:
|
||||
throw std::runtime_error(
|
||||
"Trying to convert unknown MicroProfilerName to string");
|
||||
}
|
||||
}
|
||||
|
||||
static void startProfiling();
|
||||
static void stopProfiling();
|
||||
static bool isProfiling();
|
||||
static void runInternalBenchmark();
|
||||
};
|
||||
|
||||
class MicroProfilerSection {
|
||||
public:
|
||||
MicroProfilerSection(MicroProfilerName name);
|
||||
~MicroProfilerSection();
|
||||
|
||||
private:
|
||||
bool isProfiling_;
|
||||
MicroProfilerName name_;
|
||||
uint_fast64_t startTime_;
|
||||
uint_fast32_t startNumProfileSections_;
|
||||
};
|
||||
|
||||
} // namespace react
|
||||
} // namespace facebook
|
Загрузка…
Ссылка в новой задаче