From 07b72a53ec1dd103079bdea727a9de8d1e327fa4 Mon Sep 17 00:00:00 2001 From: tqcq <99722391+tqcq@users.noreply.github.com> Date: Tue, 30 Apr 2024 15:24:45 +0800 Subject: [PATCH] feat add log for cpu profiler --- 3party/gperftools/src/profiler.cc | 584 ++++++++++-------- .../profiling/internal/remote_gperf_impl.cc | 32 + .../profiling/internal/remote_gperf_impl.h | 28 + src/sled/profiling/remote_gperf.h | 28 + src/sled/system/thread_pool_test.cc | 12 + 5 files changed, 414 insertions(+), 270 deletions(-) create mode 100644 src/sled/profiling/internal/remote_gperf_impl.cc create mode 100644 src/sled/profiling/internal/remote_gperf_impl.h create mode 100644 src/sled/profiling/remote_gperf.h diff --git a/3party/gperftools/src/profiler.cc b/3party/gperftools/src/profiler.cc index 2468067..dd175d5 100644 --- a/3party/gperftools/src/profiler.cc +++ b/3party/gperftools/src/profiler.cc @@ -35,14 +35,14 @@ // Profile current program by sampling stack-trace every so often #include "config.h" -#include "getpc.h" // should be first to get the _GNU_SOURCE dfn -#include +#include "getpc.h"// should be first to get the _GNU_SOURCE dfn #include -#include #include +#include +#include #include #ifdef HAVE_UNISTD_H -#include // for getpid() +#include // for getpid() #endif #if HAVE_SYS_UCONTEXT_H #include @@ -52,19 +52,19 @@ #include typedef ucontext ucontext_t; #else -typedef int ucontext_t; // just to quiet the compiler, mostly +typedef int ucontext_t;// just to quiet the compiler, mostly #endif -#include -#include +#include "base/commandlineflags.h" +#include "base/googleinit.h" +#include "base/logging.h" +#include "base/spinlock.h" +#include "base/sysinfo.h" /* for GetUniquePathFromEnv, etc */ +#include "profile-handler.h" +#include "profiledata.h" #include #include -#include "base/commandlineflags.h" -#include "base/logging.h" -#include "base/googleinit.h" -#include "base/spinlock.h" -#include "base/sysinfo.h" /* for GetUniquePathFromEnv, etc */ -#include "profiledata.h" -#include "profile-handler.h" +#include +#include using std::string; @@ -84,88 +84,87 @@ DEFINE_bool(cpu_profiler_unittest, // having to start and stop the daemon or having to modify the // source code to use the cpu profiler API. class CpuProfiler { - public: - CpuProfiler(); - ~CpuProfiler(); +public: + CpuProfiler(); + ~CpuProfiler(); - // Start profiler to write profile info into fname - bool Start(const char* fname, const ProfilerOptions* options); + // Start profiler to write profile info into fname + bool Start(const char *fname, const ProfilerOptions *options); - // Stop profiling and write the data to disk. - void Stop(); + // Stop profiling and write the data to disk. + void Stop(); - // Write the data to disk (and continue profiling). - void FlushTable(); + // Write the data to disk (and continue profiling). + void FlushTable(); - bool Enabled(); + bool Enabled(); - void GetCurrentState(ProfilerState* state); + void GetCurrentState(ProfilerState *state); - static CpuProfiler instance_; + static CpuProfiler instance_; - private: - // This lock implements the locking requirements described in the ProfileData - // documentation, specifically: - // - // lock_ is held all over all collector_ method calls except for the 'Add' - // call made from the signal handler, to protect against concurrent use of - // collector_'s control routines. Code other than signal handler must - // unregister the signal handler before calling any collector_ method. - // 'Add' method in the collector is protected by a guarantee from - // ProfileHandle that only one instance of prof_handler can run at a time. - SpinLock lock_; - ProfileData collector_; +private: + // This lock implements the locking requirements described in the ProfileData + // documentation, specifically: + // + // lock_ is held all over all collector_ method calls except for the 'Add' + // call made from the signal handler, to protect against concurrent use of + // collector_'s control routines. Code other than signal handler must + // unregister the signal handler before calling any collector_ method. + // 'Add' method in the collector is protected by a guarantee from + // ProfileHandle that only one instance of prof_handler can run at a time. + SpinLock lock_; + ProfileData collector_; - // Filter function and its argument, if any. (NULL means include all - // samples). Set at start, read-only while running. Written while holding - // lock_, read and executed in the context of SIGPROF interrupt. - int (*filter_)(void*); - void* filter_arg_; + // Filter function and its argument, if any. (NULL means include all + // samples). Set at start, read-only while running. Written while holding + // lock_, read and executed in the context of SIGPROF interrupt. + int (*filter_)(void *); + void *filter_arg_; - // Opaque token returned by the profile handler. To be used when calling - // ProfileHandlerUnregisterCallback. - ProfileHandlerToken* prof_handler_token_; + // Opaque token returned by the profile handler. To be used when calling + // ProfileHandlerUnregisterCallback. + ProfileHandlerToken *prof_handler_token_; - // Sets up a callback to receive SIGPROF interrupt. - void EnableHandler(); + // Sets up a callback to receive SIGPROF interrupt. + void EnableHandler(); - // Disables receiving SIGPROF interrupt. - void DisableHandler(); + // Disables receiving SIGPROF interrupt. + void DisableHandler(); - // Signal handler that records the interrupted pc in the profile data. - static void prof_handler(int sig, siginfo_t*, void* signal_ucontext, - void* cpu_profiler); + // Signal handler that records the interrupted pc in the profile data. + static void prof_handler(int sig, siginfo_t *, void *signal_ucontext, void *cpu_profiler); }; // Signal handler that is registered when a user selectable signal // number is defined in the environment variable CPUPROFILESIGNAL. -static void CpuProfilerSwitch(int signal_number) +static void +CpuProfilerSwitch(int signal_number) { - static unsigned profile_count; - static char base_profile_name[PATH_MAX]; - static bool started = false; + static unsigned profile_count; + static char base_profile_name[PATH_MAX]; + static bool started = false; - if (base_profile_name[0] == '\0') { - if (!GetUniquePathFromEnv("CPUPROFILE", base_profile_name)) { - RAW_LOG(FATAL,"Cpu profiler switch is registered but no CPUPROFILE is defined"); - return; + if (base_profile_name[0] == '\0') { + if (!GetUniquePathFromEnv("CPUPROFILE", base_profile_name)) { + RAW_LOG(FATAL, "Cpu profiler switch is registered but no CPUPROFILE is defined"); + return; + } } - } - if (!started) { char full_profile_name[PATH_MAX + 16]; - - snprintf(full_profile_name, sizeof(full_profile_name), "%s.%u", - base_profile_name, profile_count++); - - if(!ProfilerStart(full_profile_name)) { - RAW_LOG(FATAL, "Can't turn on cpu profiling for '%s': %s\n", - full_profile_name, strerror(errno)); + snprintf(full_profile_name, sizeof(full_profile_name), "%s.%u", base_profile_name, profile_count); + if (!started) { + ++profile_count; + if (!ProfilerStart(full_profile_name)) { + RAW_LOG(FATAL, "Can't turn on cpu profiling for '%s': %s\n", full_profile_name, strerror(errno)); + } + RAW_LOG(INFO, "Start New cpu Profiling for '%s'", full_profile_name); + } else { + ProfilerStop(); + RAW_LOG(INFO, "Stop cpu Profiling for '%s'", full_profile_name); } - } else { - ProfilerStop(); - } - started = !started; + started = !started; } // Profile data structure singleton: Constructor will check to see if @@ -174,154 +173,157 @@ static void CpuProfilerSwitch(int signal_number) CpuProfiler CpuProfiler::instance_; // Initialize profiling: activated if getenv("CPUPROFILE") exists. -CpuProfiler::CpuProfiler() - : prof_handler_token_(NULL) { - // TODO(cgd) Move this code *out* of the CpuProfile constructor into a - // separate object responsible for initialization. With ProfileHandler there - // is no need to limit the number of profilers. - if (getenv("CPUPROFILE") == NULL) { - if (!FLAGS_cpu_profiler_unittest) { - RAW_LOG(WARNING, "CPU profiler linked but no valid CPUPROFILE environment variable found\n"); +CpuProfiler::CpuProfiler() : prof_handler_token_(NULL) +{ + // TODO(cgd) Move this code *out* of the CpuProfile constructor into a + // separate object responsible for initialization. With ProfileHandler there + // is no need to limit the number of profilers. + if (getenv("CPUPROFILE") == NULL) { + if (!FLAGS_cpu_profiler_unittest) { + RAW_LOG(WARNING, "CPU profiler linked but no valid CPUPROFILE environment variable found\n"); + } + return; } - return; - } - // We don't enable profiling if setuid -- it's a security risk + // We don't enable profiling if setuid -- it's a security risk #ifdef HAVE_GETEUID - if (getuid() != geteuid()) { - if (!FLAGS_cpu_profiler_unittest) { - RAW_LOG(WARNING, "Cannot perform CPU profiling when running with setuid\n"); + if (getuid() != geteuid()) { + if (!FLAGS_cpu_profiler_unittest) { + RAW_LOG(WARNING, "Cannot perform CPU profiling when running with setuid\n"); + } + return; } - return; - } #endif - char *signal_number_str = getenv("CPUPROFILESIGNAL"); - if (signal_number_str != NULL) { - long int signal_number = strtol(signal_number_str, NULL, 10); - if (signal_number >= 1 && signal_number <= 64) { - intptr_t old_signal_handler = reinterpret_cast(signal(signal_number, CpuProfilerSwitch)); - if (old_signal_handler == 0) { - RAW_LOG(INFO,"Using signal %d as cpu profiling switch", signal_number); - } else { - RAW_LOG(FATAL, "Signal %d already in use\n", signal_number); - } + char *signal_number_str = getenv("CPUPROFILESIGNAL"); + if (signal_number_str != NULL) { + long int signal_number = strtol(signal_number_str, NULL, 10); + if (signal_number >= 1 && signal_number <= 64) { + intptr_t old_signal_handler = reinterpret_cast(signal(signal_number, CpuProfilerSwitch)); + if (old_signal_handler == 0) { + RAW_LOG(INFO, "Using signal %d as cpu profiling switch", signal_number); + } else { + RAW_LOG(FATAL, "Signal %d already in use\n", signal_number); + } + } else { + RAW_LOG(FATAL, "Signal number %s is invalid\n", signal_number_str); + } } else { - RAW_LOG(FATAL, "Signal number %s is invalid\n", signal_number_str); + char fname[PATH_MAX]; + if (!GetUniquePathFromEnv("CPUPROFILE", fname)) { + if (!FLAGS_cpu_profiler_unittest) { + RAW_LOG(WARNING, "CPU profiler linked but no valid CPUPROFILE environment variable found\n"); + } + return; + } + + if (!Start(fname, NULL)) { + RAW_LOG(FATAL, "Can't turn on cpu profiling for '%s': %s\n", fname, strerror(errno)); + } } - } else { - char fname[PATH_MAX]; - if (!GetUniquePathFromEnv("CPUPROFILE", fname)) { - if (!FLAGS_cpu_profiler_unittest) { - RAW_LOG(WARNING, "CPU profiler linked but no valid CPUPROFILE environment variable found\n"); - } - return; - } +} - if (!Start(fname, NULL)) { - RAW_LOG(FATAL, "Can't turn on cpu profiling for '%s': %s\n", - fname, strerror(errno)); +bool +CpuProfiler::Start(const char *fname, const ProfilerOptions *options) +{ + SpinLockHolder cl(&lock_); + + if (collector_.enabled()) { return false; } + + ProfileHandlerState prof_handler_state; + ProfileHandlerGetState(&prof_handler_state); + + ProfileData::Options collector_options; + collector_options.set_frequency(prof_handler_state.frequency); + if (!collector_.Start(fname, collector_options)) { return false; } + + filter_ = NULL; + if (options != NULL && options->filter_in_thread != NULL) { + filter_ = options->filter_in_thread; + filter_arg_ = options->filter_in_thread_arg; } - } + + // Setup handler for SIGPROF interrupts + EnableHandler(); + + return true; } -bool CpuProfiler::Start(const char* fname, const ProfilerOptions* options) { - SpinLockHolder cl(&lock_); - - if (collector_.enabled()) { - return false; - } - - ProfileHandlerState prof_handler_state; - ProfileHandlerGetState(&prof_handler_state); - - ProfileData::Options collector_options; - collector_options.set_frequency(prof_handler_state.frequency); - if (!collector_.Start(fname, collector_options)) { - return false; - } - - filter_ = NULL; - if (options != NULL && options->filter_in_thread != NULL) { - filter_ = options->filter_in_thread; - filter_arg_ = options->filter_in_thread_arg; - } - - // Setup handler for SIGPROF interrupts - EnableHandler(); - - return true; -} - -CpuProfiler::~CpuProfiler() { - Stop(); -} +CpuProfiler::~CpuProfiler() { Stop(); } // Stop profiling and write out any collected profile data -void CpuProfiler::Stop() { - SpinLockHolder cl(&lock_); - - if (!collector_.enabled()) { - return; - } - - // Unregister prof_handler to stop receiving SIGPROF interrupts before - // stopping the collector. - DisableHandler(); - - // DisableHandler waits for the currently running callback to complete and - // guarantees no future invocations. It is safe to stop the collector. - collector_.Stop(); -} - -void CpuProfiler::FlushTable() { - SpinLockHolder cl(&lock_); - - if (!collector_.enabled()) { - return; - } - - // Unregister prof_handler to stop receiving SIGPROF interrupts before - // flushing the profile data. - DisableHandler(); - - // DisableHandler waits for the currently running callback to complete and - // guarantees no future invocations. It is safe to flush the profile data. - collector_.FlushTable(); - - EnableHandler(); -} - -bool CpuProfiler::Enabled() { - SpinLockHolder cl(&lock_); - return collector_.enabled(); -} - -void CpuProfiler::GetCurrentState(ProfilerState* state) { - ProfileData::State collector_state; - { +void +CpuProfiler::Stop() +{ SpinLockHolder cl(&lock_); - collector_.GetCurrentState(&collector_state); - } - state->enabled = collector_state.enabled; - state->start_time = static_cast(collector_state.start_time); - state->samples_gathered = collector_state.samples_gathered; - int buf_size = sizeof(state->profile_name); - strncpy(state->profile_name, collector_state.profile_name, buf_size); - state->profile_name[buf_size-1] = '\0'; + if (!collector_.enabled()) { return; } + + // Unregister prof_handler to stop receiving SIGPROF interrupts before + // stopping the collector. + DisableHandler(); + + // DisableHandler waits for the currently running callback to complete and + // guarantees no future invocations. It is safe to stop the collector. + collector_.Stop(); } -void CpuProfiler::EnableHandler() { - RAW_CHECK(prof_handler_token_ == NULL, "SIGPROF handler already registered"); - prof_handler_token_ = ProfileHandlerRegisterCallback(prof_handler, this); - RAW_CHECK(prof_handler_token_ != NULL, "Failed to set up SIGPROF handler"); +void +CpuProfiler::FlushTable() +{ + SpinLockHolder cl(&lock_); + + if (!collector_.enabled()) { return; } + + // Unregister prof_handler to stop receiving SIGPROF interrupts before + // flushing the profile data. + DisableHandler(); + + // DisableHandler waits for the currently running callback to complete and + // guarantees no future invocations. It is safe to flush the profile data. + collector_.FlushTable(); + + EnableHandler(); } -void CpuProfiler::DisableHandler() { - RAW_CHECK(prof_handler_token_ != NULL, "SIGPROF handler is not registered"); - ProfileHandlerUnregisterCallback(prof_handler_token_); - prof_handler_token_ = NULL; +bool +CpuProfiler::Enabled() +{ + SpinLockHolder cl(&lock_); + return collector_.enabled(); +} + +void +CpuProfiler::GetCurrentState(ProfilerState *state) +{ + ProfileData::State collector_state; + { + SpinLockHolder cl(&lock_); + collector_.GetCurrentState(&collector_state); + } + + state->enabled = collector_state.enabled; + state->start_time = static_cast(collector_state.start_time); + state->samples_gathered = collector_state.samples_gathered; + int buf_size = sizeof(state->profile_name); + strncpy(state->profile_name, collector_state.profile_name, buf_size); + state->profile_name[buf_size - 1] = '\0'; +} + +void +CpuProfiler::EnableHandler() +{ + RAW_CHECK(prof_handler_token_ == NULL, "SIGPROF handler already registered"); + prof_handler_token_ = ProfileHandlerRegisterCallback(prof_handler, this); + RAW_CHECK(prof_handler_token_ != NULL, "Failed to set up SIGPROF handler"); +} + +void +CpuProfiler::DisableHandler() +{ + RAW_CHECK(prof_handler_token_ != NULL, "SIGPROF handler is not registered"); + ProfileHandlerUnregisterCallback(prof_handler_token_); + prof_handler_token_ = NULL; } // Signal handler that records the pc in the profile-data structure. We do no @@ -330,105 +332,147 @@ void CpuProfiler::DisableHandler() { // access the data touched by prof_handler() disable this signal handler before // accessing the data and therefore cannot execute concurrently with // prof_handler(). -void CpuProfiler::prof_handler(int sig, siginfo_t*, void* signal_ucontext, - void* cpu_profiler) { - CpuProfiler* instance = static_cast(cpu_profiler); +void +CpuProfiler::prof_handler(int sig, siginfo_t *, void *signal_ucontext, void *cpu_profiler) +{ + CpuProfiler *instance = static_cast(cpu_profiler); - if (instance->filter_ == NULL || - (*instance->filter_)(instance->filter_arg_)) { - void* stack[ProfileData::kMaxStackDepth]; + if (instance->filter_ == NULL || (*instance->filter_)(instance->filter_arg_)) { + void *stack[ProfileData::kMaxStackDepth]; - // Under frame-pointer-based unwinding at least on x86, the - // top-most active routine doesn't show up as a normal frame, but - // as the "pc" value in the signal handler context. - stack[0] = GetPC(*reinterpret_cast(signal_ucontext)); + // Under frame-pointer-based unwinding at least on x86, the + // top-most active routine doesn't show up as a normal frame, but + // as the "pc" value in the signal handler context. + stack[0] = GetPC(*reinterpret_cast(signal_ucontext)); - // We skip the top three stack trace entries (this function, - // SignalHandler::SignalHandler and one signal handler frame) - // since they are artifacts of profiling and should not be - // measured. Other profiling related frames may be removed by - // "pprof" at analysis time. Instead of skipping the top frames, - // we could skip nothing, but that would increase the profile size - // unnecessarily. - int depth = GetStackTraceWithContext(stack + 1, arraysize(stack) - 1, - 3, signal_ucontext); + // We skip the top three stack trace entries (this function, + // SignalHandler::SignalHandler and one signal handler frame) + // since they are artifacts of profiling and should not be + // measured. Other profiling related frames may be removed by + // "pprof" at analysis time. Instead of skipping the top frames, + // we could skip nothing, but that would increase the profile size + // unnecessarily. + int depth = GetStackTraceWithContext(stack + 1, arraysize(stack) - 1, 3, signal_ucontext); - void **used_stack; - if (depth > 0 && stack[1] == stack[0]) { - // in case of non-frame-pointer-based unwinding we will get - // duplicate of PC in stack[1], which we don't want - used_stack = stack + 1; - } else { - used_stack = stack; - depth++; // To account for pc value in stack[0]; + void **used_stack; + if (depth > 0 && stack[1] == stack[0]) { + // in case of non-frame-pointer-based unwinding we will get + // duplicate of PC in stack[1], which we don't want + used_stack = stack + 1; + } else { + used_stack = stack; + depth++;// To account for pc value in stack[0]; + } + + instance->collector_.Add(depth, used_stack); } - - instance->collector_.Add(depth, used_stack); - } } #if !(defined(__CYGWIN__) || defined(__CYGWIN32__)) -extern "C" PERFTOOLS_DLL_DECL void ProfilerRegisterThread() { - ProfileHandlerRegisterThread(); +extern "C" PERFTOOLS_DLL_DECL void +ProfilerRegisterThread() +{ + ProfileHandlerRegisterThread(); } -extern "C" PERFTOOLS_DLL_DECL void ProfilerFlush() { - CpuProfiler::instance_.FlushTable(); +extern "C" PERFTOOLS_DLL_DECL void +ProfilerFlush() +{ + CpuProfiler::instance_.FlushTable(); } -extern "C" PERFTOOLS_DLL_DECL int ProfilingIsEnabledForAllThreads() { - return CpuProfiler::instance_.Enabled(); +extern "C" PERFTOOLS_DLL_DECL int +ProfilingIsEnabledForAllThreads() +{ + return CpuProfiler::instance_.Enabled(); } -extern "C" PERFTOOLS_DLL_DECL int ProfilerStart(const char* fname) { - return CpuProfiler::instance_.Start(fname, NULL); +extern "C" PERFTOOLS_DLL_DECL int +ProfilerStart(const char *fname) +{ + return CpuProfiler::instance_.Start(fname, NULL); } -extern "C" PERFTOOLS_DLL_DECL int ProfilerStartWithOptions( - const char *fname, const ProfilerOptions *options) { - return CpuProfiler::instance_.Start(fname, options); +extern "C" PERFTOOLS_DLL_DECL int +ProfilerStartWithOptions(const char *fname, const ProfilerOptions *options) +{ + return CpuProfiler::instance_.Start(fname, options); } -extern "C" PERFTOOLS_DLL_DECL void ProfilerStop() { - CpuProfiler::instance_.Stop(); +extern "C" PERFTOOLS_DLL_DECL void +ProfilerStop() +{ + CpuProfiler::instance_.Stop(); } -extern "C" PERFTOOLS_DLL_DECL void ProfilerGetCurrentState( - ProfilerState* state) { - CpuProfiler::instance_.GetCurrentState(state); +extern "C" PERFTOOLS_DLL_DECL void +ProfilerGetCurrentState(ProfilerState *state) +{ + CpuProfiler::instance_.GetCurrentState(state); } -extern "C" PERFTOOLS_DLL_DECL int ProfilerGetStackTrace( - void** result, int max_depth, int skip_count, const void *uc) { - return GetStackTraceWithContext(result, max_depth, skip_count, uc); +extern "C" PERFTOOLS_DLL_DECL int +ProfilerGetStackTrace(void **result, int max_depth, int skip_count, const void *uc) +{ + return GetStackTraceWithContext(result, max_depth, skip_count, uc); } -#else // OS_CYGWIN +#else// OS_CYGWIN // ITIMER_PROF doesn't work under cygwin. ITIMER_REAL is available, but doesn't // work as well for profiling, and also interferes with alarm(). Because of // these issues, unless a specific need is identified, profiler support is // disabled under Cygwin. -extern "C" void ProfilerRegisterThread() { } -extern "C" void ProfilerFlush() { } -extern "C" int ProfilingIsEnabledForAllThreads() { return 0; } -extern "C" int ProfilerStart(const char* fname) { return 0; } -extern "C" int ProfilerStartWithOptions(const char *fname, - const ProfilerOptions *options) { - return 0; -} -extern "C" void ProfilerStop() { } -extern "C" void ProfilerGetCurrentState(ProfilerState* state) { - memset(state, 0, sizeof(*state)); -} -extern "C" int ProfilerGetStackTrace( - void** result, int max_depth, int skip_count, const void *uc) { - return 0; +extern "C" void +ProfilerRegisterThread() +{} + +extern "C" void +ProfilerFlush() +{} + +extern "C" int +ProfilingIsEnabledForAllThreads() +{ + return 0; } -#endif // OS_CYGWIN +extern "C" int +ProfilerStart(const char *fname) +{ + return 0; +} + +extern "C" int +ProfilerStartWithOptions(const char *fname, const ProfilerOptions *options) +{ + return 0; +} + +extern "C" void +ProfilerStop() +{} + +extern "C" void +ProfilerGetCurrentState(ProfilerState *state) +{ + memset(state, 0, sizeof(*state)); +} + +extern "C" int +ProfilerGetStackTrace(void **result, int max_depth, int skip_count, const void *uc) +{ + return 0; +} + +#endif// OS_CYGWIN // DEPRECATED routines -extern "C" PERFTOOLS_DLL_DECL void ProfilerEnable() { } -extern "C" PERFTOOLS_DLL_DECL void ProfilerDisable() { } +extern "C" PERFTOOLS_DLL_DECL void +ProfilerEnable() +{} + +extern "C" PERFTOOLS_DLL_DECL void +ProfilerDisable() +{} diff --git a/src/sled/profiling/internal/remote_gperf_impl.cc b/src/sled/profiling/internal/remote_gperf_impl.cc new file mode 100644 index 0000000..5a01030 --- /dev/null +++ b/src/sled/profiling/internal/remote_gperf_impl.cc @@ -0,0 +1,32 @@ +#include "remote_gperf_impl.h" +#include +#include +#include + +namespace sled { +RemoteGPerfImpl::RemoteGPerfImpl(int port) {} + +RemoteGPerfImpl::~RemoteGPerfImpl() {} + +std::string +RemoteGPerfImpl::HeapGET() +{ + MallocExtensionWriter writer; + MallocExtension::instance()->GetHeapSample(&writer); + return writer; +} + +std::string +RemoteGPerfImpl::GrowthGET() +{ + MallocExtensionWriter writer; + MallocExtension::instance()->GetHeapGrowthStacks(&writer); + return writer; +} + +std::string +RemoteGPerfImpl::CmdLineGET() +{ + return ""; +} +}// namespace sled diff --git a/src/sled/profiling/internal/remote_gperf_impl.h b/src/sled/profiling/internal/remote_gperf_impl.h new file mode 100644 index 0000000..0828b76 --- /dev/null +++ b/src/sled/profiling/internal/remote_gperf_impl.h @@ -0,0 +1,28 @@ +#ifndef SLED_PROFILING_INTERNAL_REMOTE_GPERF_IMPL_H +#define SLED_PROFILING_INTERNAL_REMOTE_GPERF_IMPL_H + +#pragma once +#include "sled/buffer.h" + +namespace sled { +class RemoteGPerfImpl { +public: + RemoteGPerfImpl(int port); + ~RemoteGPerfImpl(); + +private: + std::string HeapGET(); + std::string GrowthGET(); + + // 1. read data from /proc/selfcmdline + // 2. replace all NULL(\0) by new Lines + std::string CmdLineGET(); + + std::string SymbolGET(); + // request: 0x0824d061+0x0824d1cf + // response: + std::string SymbolPOST(const std::string &address); +}; +}// namespace sled + +#endif// SLED_PROFILING_INTERNAL_REMOTE_GPERF_IMPL_H diff --git a/src/sled/profiling/remote_gperf.h b/src/sled/profiling/remote_gperf.h new file mode 100644 index 0000000..2d73399 --- /dev/null +++ b/src/sled/profiling/remote_gperf.h @@ -0,0 +1,28 @@ +#ifndef SLED_PROFILING_REMOTE_GPERF_H +#define SLED_PROFILING_REMOTE_GPERF_H + +#pragma once + +namespace sled { +// DOCS: https://gperftools.github.io/gperftools/pprof_remote_servers.html + +// interface +// 1. http://host:80/pprof/heap +// 2. http://host:80/pprof/profile +// http://host:80/ +// http://host:80 +// 3. http://host:80/pprof/growth +// 4. http://host:80/myservice/pprof/heap +// 5. http://host:80/profile/ + +class RemoteGPerf { +public: + RemoteGPerf(int port); + ~RemoteGPerf(); + +private: +}; + +}// namespace sled + +#endif// SLED_PROFILING_REMOTE_GPERF_H diff --git a/src/sled/system/thread_pool_test.cc b/src/sled/system/thread_pool_test.cc index d1d229a..8a0ce0f 100644 --- a/src/sled/system/thread_pool_test.cc +++ b/src/sled/system/thread_pool_test.cc @@ -1,5 +1,6 @@ #include #include +#include #include std::random_device rd; @@ -81,4 +82,15 @@ TEST_SUITE("ThreadPool") CHECK(waiter.Wait(sled::TimeDelta::Millis(150))); delete tp; } + + TEST_CASE("10^6 task test") + { + sled::ThreadPool *tp = new sled::ThreadPool(); + const int task_num = 1E6; + sled::WaitGroup wg(task_num); + for (int i = 0; i < task_num; i++) { + tp->PostTask([wg] { wg.Done(); }); + } + wg.Wait(); + } }