From 28e9b47eb5c3d13887852aaab4d37120690e9cfd Mon Sep 17 00:00:00 2001 From: Bright Chen Date: Wed, 3 Jan 2024 23:46:26 +0800 Subject: [PATCH 1/4] Support IOBuf Profiler --- BUILD.bazel | 1 + CMakeLists.txt | 1 + Makefile | 1 + src/brpc/builtin/common.cpp | 1 + src/brpc/builtin/common.h | 1 + src/brpc/builtin/hotspots_service.cpp | 80 ++++-- src/brpc/builtin/hotspots_service.h | 10 + src/brpc/builtin/pprof_perl.cpp | 3 +- src/brpc/builtin_service.proto | 2 + src/butil/iobuf.cpp | 37 ++- src/butil/iobuf_profiler.cpp | 385 ++++++++++++++++++++++++++ src/butil/iobuf_profiler.h | 166 +++++++++++ 12 files changed, 665 insertions(+), 23 deletions(-) create mode 100644 src/butil/iobuf_profiler.cpp create mode 100644 src/butil/iobuf_profiler.h diff --git a/BUILD.bazel b/BUILD.bazel index 0bdaa4d38f..b2a453e0c9 100644 --- a/BUILD.bazel +++ b/BUILD.bazel @@ -213,6 +213,7 @@ BUTIL_SRCS = [ "src/butil/crc32c.cc", "src/butil/containers/case_ignored_flat_map.cpp", "src/butil/iobuf.cpp", + "src/butil/iobuf_profiler.cpp", "src/butil/binary_printer.cpp", "src/butil/recordio.cc", "src/butil/popen.cpp", diff --git a/CMakeLists.txt b/CMakeLists.txt index 2eeec04976..3940721b10 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -402,6 +402,7 @@ set(BUTIL_SOURCES ${PROJECT_SOURCE_DIR}/src/butil/crc32c.cc ${PROJECT_SOURCE_DIR}/src/butil/containers/case_ignored_flat_map.cpp ${PROJECT_SOURCE_DIR}/src/butil/iobuf.cpp + ${PROJECT_SOURCE_DIR}/src/butil/iobuf_profiler.cpp ${PROJECT_SOURCE_DIR}/src/butil/binary_printer.cpp ${PROJECT_SOURCE_DIR}/src/butil/recordio.cc ${PROJECT_SOURCE_DIR}/src/butil/popen.cpp diff --git a/Makefile b/Makefile index 0ed8a352c2..da6ac9f49b 100644 --- a/Makefile +++ b/Makefile @@ -163,6 +163,7 @@ BUTIL_SOURCES = \ src/butil/crc32c.cc \ src/butil/containers/case_ignored_flat_map.cpp \ src/butil/iobuf.cpp \ + src/butil/iobuf_profiler.cpp \ src/butil/binary_printer.cpp \ src/butil/recordio.cc \ src/butil/popen.cpp diff --git a/src/brpc/builtin/common.cpp b/src/brpc/builtin/common.cpp index 9cdc72fee6..7b5d33a348 100644 --- a/src/brpc/builtin/common.cpp +++ b/src/brpc/builtin/common.cpp @@ -308,6 +308,7 @@ const char* ProfilingType2String(ProfilingType t) { case PROFILING_HEAP: return "heap"; case PROFILING_GROWTH: return "growth"; case PROFILING_CONTENTION: return "contention"; + case PROFILING_IOBUF: return "iobuf"; } return "unknown"; } diff --git a/src/brpc/builtin/common.h b/src/brpc/builtin/common.h index f4d6962729..5fd8a9c98e 100644 --- a/src/brpc/builtin/common.h +++ b/src/brpc/builtin/common.h @@ -52,6 +52,7 @@ enum ProfilingType { PROFILING_HEAP = 1, PROFILING_GROWTH = 2, PROFILING_CONTENTION = 3, + PROFILING_IOBUF = 4, }; DECLARE_string(rpc_profiling_dir); diff --git a/src/brpc/builtin/hotspots_service.cpp b/src/brpc/builtin/hotspots_service.cpp index b70266f49f..c01ce536d7 100644 --- a/src/brpc/builtin/hotspots_service.cpp +++ b/src/brpc/builtin/hotspots_service.cpp @@ -23,6 +23,7 @@ #include "butil/file_util.h" // butil::FilePath #include "butil/popen.h" // butil::read_command_output #include "butil/fd_guard.h" // butil::fd_guard +#include "butil/iobuf_profiler.h" #include "brpc/log.h" #include "brpc/controller.h" #include "brpc/server.h" @@ -154,7 +155,8 @@ struct ProfilingEnvironment { }; // Different ProfilingType have different env. -static ProfilingEnvironment g_env[4] = { +static ProfilingEnvironment g_env[5] = { + { PTHREAD_MUTEX_INITIALIZER, 0, NULL, NULL, NULL }, { PTHREAD_MUTEX_INITIALIZER, 0, NULL, NULL, NULL }, { PTHREAD_MUTEX_INITIALIZER, 0, NULL, NULL, NULL }, { PTHREAD_MUTEX_INITIALIZER, 0, NULL, NULL, NULL }, @@ -399,7 +401,8 @@ static bool has_GOOGLE_PPROF_BINARY_PATH() { static void DisplayResult(Controller* cntl, google::protobuf::Closure* done, const char* prof_name, - const butil::IOBuf& result_prefix) { + const butil::IOBuf& result_prefix, + ProfilingType type) { ClosureGuard done_guard(done); butil::IOBuf prof_result; if (cntl->IsCanceled()) { @@ -488,7 +491,7 @@ static void DisplayResult(Controller* cntl, #if defined(OS_LINUX) cmd_builder << "perl " << pprof_tool << DisplayTypeToPProfArgument(display_type) - << (show_ccount ? " --contention " : ""); + << ((show_ccount || type == PROFILING_IOBUF) ? " --contention " : ""); if (base_name) { cmd_builder << "--base " << *base_name << ' '; } @@ -505,7 +508,7 @@ static void DisplayResult(Controller* cntl, #elif defined(OS_MACOSX) cmd_builder << s_pprof_binary_path << " " << DisplayTypeToPProfArgument(display_type) - << (show_ccount ? " -contentions " : ""); + << ((show_ccount || type == PROFILING_IOBUF) ? " --contention " : ""); if (base_name) { cmd_builder << "-base " << *base_name << ' '; } @@ -637,7 +640,7 @@ static void DoProfiling(ProfilingType type, return cntl->SetFailed( EINVAL, "The profile denoted by `view' does not exist"); } - DisplayResult(cntl, done_guard.release(), view->c_str(), os.buf()); + DisplayResult(cntl, done_guard.release(), view->c_str(), os.buf(), type); return; } @@ -774,6 +777,15 @@ static void DoProfiling(ProfilingType type, PLOG(WARNING) << "Profiling has been interrupted"; } bthread::ContentionProfilerStop(); + } else if (type == PROFILING_IOBUF) { + if (!butil::IsIOBufProfilerEnabled()) { + os << "IOBuf profiler is not enabled" + << (use_html ? "" : "\n"); + os.move_to(resp); + cntl->http_response().set_status_code(HTTP_STATUS_FORBIDDEN); + return NotifyWaiters(type, cntl, view); + } + butil::IOBufProfilerFlush(prof_name); } else if (type == PROFILING_HEAP) { MallocExtension* malloc_ext = MallocExtension::instance(); if (malloc_ext == NULL || !has_TCMALLOC_SAMPLE_PARAMETER()) { @@ -827,11 +839,11 @@ static void DoProfiling(ProfilingType type, std::vector waiters; // NOTE: Must be called before DisplayResult which calls done->Run() and // deletes cntl. - ConsumeWaiters(type, cntl, &waiters); - DisplayResult(cntl, done_guard.release(), prof_name, os.buf()); + ConsumeWaiters(type, cntl, &waiters); + DisplayResult(cntl, done_guard.release(), prof_name, os.buf(), type); for (size_t i = 0; i < waiters.size(); ++i) { - DisplayResult(waiters[i].cntl, waiters[i].done, prof_name, os.buf()); + DisplayResult(waiters[i].cntl, waiters[i].done, prof_name, os.buf(), type); } } @@ -849,7 +861,12 @@ static void StartProfiling(ProfilingType type, enabled = cpu_profiler_enabled; } else if (type == PROFILING_CONTENTION) { enabled = true; - } else if (type == PROFILING_HEAP) { + } else if (type == PROFILING_IOBUF) { + enabled = butil::IsIOBufProfilerEnabled(); + if (!enabled) { + extra_desc = " (no ENABLE_IOBUF_PROFILER=1 in env or no link tcmalloc )"; + } + } else if (type == PROFILING_HEAP) { enabled = IsHeapProfilerEnabled(); if (enabled && !has_TCMALLOC_SAMPLE_PARAMETER()) { enabled = false; @@ -925,7 +942,8 @@ static void StartProfiling(ProfilingType type, "