Commit a5a324a3 authored by zyearn's avatar zyearn

add pprof support in macos

parent 2d6535b6
......@@ -34,11 +34,11 @@ WARNING: 12-26 10:01:25: * 0 [src/brpc/input_messenger.cpp:132][4294969345] Au
热点分析一般开始于找到最大的框最粗的线考察其来源及去向。
cpu profiler的原理是在定期被调用的SIGPROF handler中采样所在线程的栈,由于handler(在linux 2.6后)会被随机地摆放于活跃线程的栈上运行,cpu profiler在运行一段时间后能以很大的概率采集到所有活跃线程中的活跃函数,最后根据栈代表的函数调用关系汇总为调用图,并把地址转换成符号,这就是我们看到的结果图了。采集频率由环境变量CPUPROFILE_FREQUENCY控制,默认100,即每秒钟100次或每10ms一次。在实践中cpu profiler对原程序的影响不明显。
cpu profiler的原理是在定期被调用的SIGPROF handler中采样所在线程的栈,由于handler(在linux 2.6后)会被随机地摆放于活跃线程的栈上运行,cpu profiler在运行一段时间后能以很大的概率采集到所有活跃线程中的活跃函数,最后根据栈代表的函数调用关系汇总为调用图,并把地址转换成符号,这就是我们看到的结果图了。采集频率由环境变量CPUPROFILE_FREQUENCY控制,默认100,即每秒钟100次或每10ms一次。在实践中cpu profiler对原程序的影响不明显。
![img](../images/echo_cpu_profiling.png)
你也可以使用[pprof](https://github.com/brpc/brpc/blob/master/tools/pprof)或gperftools中的pprof进行profiling。
在Linux下,你也可以使用[pprof](https://github.com/brpc/brpc/blob/master/tools/pprof)或gperftools中的pprof进行profiling。
比如`pprof --text localhost:9002 --seconds=5`的意思是统计运行在本机9002端口的server的cpu情况,时长5秒。一次运行的例子如下:
......@@ -91,3 +91,7 @@ Total: 2954 samples
37 1.3% 66.1% 37 1.3% memcpy
35 1.2% 67.3% 35 1.2% brpc::Socket::Address
```
# MacOS的额外配置
在MacOS下,gperftools中的perl pprof脚本会丢失函数名字,解决办法是需要自行下载[standalone pprof](https://github.com/google/pprof),并把下载的pprof二进制文件路径写入环境变量GOOGLE_PPROF_BINARY_PATH中,profiler才能正常工作。
......@@ -52,7 +52,7 @@ WARNING: 12-26 10:01:25: * 0 [src/brpc/input_messenger.cpp:132][4294969345] Au
![img](../images/heap_profiler_3.gif)
你也可以使用pprof脚本(tools/pprof)在命令行中查看文本格式结果:
在Linux下,你也可以使用pprof脚本(tools/pprof)在命令行中查看文本格式结果:
```
$ tools/pprof --text db-rpc-dev00.db01:8765/pprof/heap
......@@ -103,3 +103,6 @@ brpc还提供一个类似的growth profiler分析内存的分配去向(不考
![img](../images/growth_profiler.png)
# MacOS的额外配置
在MacOS下,gperftools中的perl pprof脚本会丢失函数名字,解决办法是需要自行下载[standalone pprof](https://github.com/google/pprof),并把下载的pprof二进制文件路径写入环境变量GOOGLE_PPROF_BINARY_PATH中,profiler才能正常工作。
......@@ -18,7 +18,8 @@
#include <gflags/gflags.h>
#include "butil/files/file_enumerator.h"
#include "butil/file_util.h" // butil::FilePath
#include "butil/popen.h" // butil::read_command_output
#include "butil/popen.h" // butil::read_command_output
#include "butil/fd_guard.h" // butil::fd_guard
#include "brpc/log.h"
#include "brpc/controller.h"
#include "brpc/server.h"
......@@ -308,6 +309,25 @@ static void NotifyWaiters(ProfilingType type, const Controller* cur_cntl,
}
}
#if defined(OS_MACOSX)
static bool check_GOOGLE_PPROF_BINARY_PATH() {
char* str = getenv("GOOGLE_PPROF_BINARY_PATH");
if (str == NULL) {
return false;
}
butil::fd_guard fd(open(str, O_RDONLY));
if (fd < 0) {
return false;
}
return true;
}
static bool has_GOOGLE_PPROF_BINARY_PATH() {
static bool val = check_GOOGLE_PPROF_BINARY_PATH();
return val;
}
#endif
static void DisplayResult(Controller* cntl,
google::protobuf::Closure* done,
const char* prof_name,
......@@ -383,6 +403,7 @@ static void DisplayResult(Controller* cntl,
pprof_tool.push_back('/');
pprof_tool += PPROF_FILENAME;
#if defined(OS_LINUX)
cmd_builder << "perl " << pprof_tool
<< (use_text ? " --text " : " --dot ")
<< (show_ccount ? " --contention " : "");
......@@ -390,6 +411,16 @@ static void DisplayResult(Controller* cntl,
cmd_builder << "--base " << *base_name << ' ';
}
cmd_builder << GetProgramName() << " " << prof_name << " 2>&1 ";
#elif defined(OS_MACOSX)
cmd_builder << getenv("GOOGLE_PPROF_BINARY_PATH") << " "
<< (use_text ? " -text " : " -dot ")
<< (show_ccount ? " -contentions " : "");
if (base_name) {
cmd_builder << "-base " << *base_name << ' ';
}
cmd_builder << prof_name << " 2>&1 ";
#endif
const std::string cmd = cmd_builder.str();
for (int ntry = 0; ntry < 2; ++ntry) {
if (!g_written_pprof_perl) {
......@@ -601,6 +632,16 @@ static void DoProfiling(ProfilingType type,
cntl->http_response().set_status_code(HTTP_STATUS_INTERNAL_SERVER_ERROR);
return NotifyWaiters(type, cntl, view);
}
#if defined(OS_MACOSX)
if (!has_GOOGLE_PPROF_BINARY_PATH()) {
os << "no GOOGLE_PPROF_BINARY_PATH in env"
<< (use_html ? "</body></html>" : "\n");
os.move_to(resp);
cntl->http_response().set_status_code(HTTP_STATUS_FORBIDDEN);
return NotifyWaiters(type, cntl, view);
}
#endif
if (type == PROFILING_CPU) {
if ((void*)ProfilerStart == NULL || (void*)ProfilerStop == NULL) {
os << "CPU profiler is not enabled"
......@@ -713,6 +754,7 @@ static void StartProfiling(ProfilingType type,
butil::IOBufBuilder os;
bool enabled = false;
const char* extra_desc = "";
if (type == PROFILING_CPU) {
enabled = cpu_profiler_enabled;
} else if (type == PROFILING_CONTENTION) {
......@@ -727,6 +769,13 @@ static void StartProfiling(ProfilingType type,
enabled = IsHeapProfilerEnabled();
}
const char* const type_str = ProfilingType2String(type);
#if defined(OS_MACOSX)
if (!has_GOOGLE_PPROF_BINARY_PATH()) {
enabled = false;
extra_desc = "(no GOOGLE_PPROF_BINARY_PATH in env)";
}
#endif
if (!use_html) {
if (!enabled) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment