| 94 | } |
| 95 | |
| 96 | void PProfService::profile( |
| 97 | ::google::protobuf::RpcController* controller_base, |
| 98 | const ::brpc::ProfileRequest* /*request*/, |
| 99 | ::brpc::ProfileResponse* /*response*/, |
| 100 | ::google::protobuf::Closure* done) { |
| 101 | ClosureGuard done_guard(done); |
| 102 | Controller* cntl = static_cast<Controller*>(controller_base); |
| 103 | cntl->http_response().set_content_type("text/plain"); |
| 104 | if ((void*)ProfilerStart == NULL || (void*)ProfilerStop == NULL) { |
| 105 | cntl->SetFailed(ENOMETHOD, "%s, to enable cpu profiler, check out " |
| 106 | "docs/cn/cpu_profiler.md", |
| 107 | berror(ENOMETHOD)); |
| 108 | return; |
| 109 | } |
| 110 | int sleep_sec = ReadSeconds(cntl); |
| 111 | if (sleep_sec <= 0) { |
| 112 | if (!cntl->Failed()) { |
| 113 | cntl->SetFailed(EINVAL, "You have to specify ?seconds=N. If you're " |
| 114 | "using pprof, add --seconds=N"); |
| 115 | } |
| 116 | return; |
| 117 | } |
| 118 | // Log requester |
| 119 | std::ostringstream client_info; |
| 120 | client_info << cntl->remote_side(); |
| 121 | if (cntl->auth_context()) { |
| 122 | client_info << "(auth=" << cntl->auth_context()->user() << ')'; |
| 123 | } else { |
| 124 | client_info << "(no auth)"; |
| 125 | } |
| 126 | LOG(INFO) << client_info.str() << " requests for cpu profile for " |
| 127 | << sleep_sec << " seconds"; |
| 128 | |
| 129 | char prof_name[256]; |
| 130 | if (MakeProfName(PROFILING_CPU, prof_name, sizeof(prof_name)) != 0) { |
| 131 | cntl->SetFailed(errno, "Fail to create .prof file, %s", berror()); |
| 132 | return; |
| 133 | } |
| 134 | butil::File::Error error; |
| 135 | const butil::FilePath dir = butil::FilePath(prof_name).DirName(); |
| 136 | if (!butil::CreateDirectoryAndGetError(dir, &error)) { |
| 137 | cntl->SetFailed(EPERM, "Fail to create directory=`%s'",dir.value().c_str()); |
| 138 | return; |
| 139 | } |
| 140 | if (!ProfilerStart(prof_name)) { |
| 141 | cntl->SetFailed(EAGAIN, "Another profiler is running, try again later"); |
| 142 | return; |
| 143 | } |
| 144 | if (bthread_usleep(sleep_sec * 1000000L) != 0) { |
| 145 | PLOG(WARNING) << "Profiling has been interrupted"; |
| 146 | } |
| 147 | ProfilerStop(); |
| 148 | |
| 149 | butil::fd_guard fd(open(prof_name, O_RDONLY)); |
| 150 | if (fd < 0) { |
| 151 | cntl->SetFailed(ENOENT, "Fail to open %s", prof_name); |
| 152 | return; |
| 153 | } |