static void DisplayResult()

in src/brpc/builtin/hotspots_service.cpp [400:607]


static void DisplayResult(Controller* cntl,
                          google::protobuf::Closure* done,
                          const char* prof_name,
                          const butil::IOBuf& result_prefix,
                          ProfilingType type) {
    ClosureGuard done_guard(done);
    butil::IOBuf prof_result;
    if (cntl->IsCanceled()) {
        // If the page is refreshed, older connections are likely to be
        // already closed by browser.
        return;
    }
    butil::IOBuf& resp = cntl->response_attachment();
    const bool use_html = UseHTML(cntl->http_request());
    const bool show_ccount = cntl->http_request().uri().GetQuery("ccount");
    const std::string* base_name = cntl->http_request().uri().GetQuery("base");
    const std::string* display_type_query = cntl->http_request().uri().GetQuery("display_type");
    DisplayType display_type = DisplayType::kDot;
#if defined(OS_LINUX)
    const char* flamegraph_tool = getenv("FLAMEGRAPH_PL_PATH");
#endif
    if (display_type_query) {
        display_type = StringToDisplayType(*display_type_query);
        if (display_type == DisplayType::kUnknown) {
            return cntl->SetFailed(EINVAL, "Invalid display_type=%s", display_type_query->c_str());
        }
#if defined(OS_LINUX)
        if (display_type == DisplayType::kFlameGraph && !flamegraph_tool) {
            return cntl->SetFailed(EINVAL, "Failed to find environment variable "
                "FLAMEGRAPH_PL_PATH, please read cpu_profiler doc"
                "(https://github.com/apache/brpc/blob/master/docs/cn/cpu_profiler.md)");
        }
#endif
    }
    if (base_name != NULL) {
        if (!ValidProfilePath(*base_name)) {
            return cntl->SetFailed(EINVAL, "Invalid query `base'");
        }
        if (!butil::PathExists(butil::FilePath(*base_name))) {
            return cntl->SetFailed(
                EINVAL, "The profile denoted by `base' does not exist");
        }
    }
    butil::IOBufBuilder os;
    os << result_prefix;
    char expected_result_name[256];
    MakeCacheName(expected_result_name, sizeof(expected_result_name),
                  prof_name, GetBaseName(base_name),
                  display_type, show_ccount);
    // Try to read cache first.
    FILE* fp = fopen(expected_result_name, "r");
    if (fp != NULL) {
        bool succ = false;
        char buffer[1024];
        while (1) {
            size_t nr = fread(buffer, 1, sizeof(buffer), fp);
            if (nr != 0) {
                prof_result.append(buffer, nr);
            }
            if (nr != sizeof(buffer)) {
                if (feof(fp)) {
                    succ = true;
                    break;
                } else if (ferror(fp)) {
                    LOG(ERROR) << "Encountered error while reading for "
                               << expected_result_name;
                    break;
                }
                // retry;
            }
        }
        PLOG_IF(ERROR, fclose(fp) != 0) << "Fail to close fp";
        if (succ) {
            RPC_VLOG << "Hit cache=" << expected_result_name;
            os.move_to(resp);
            if (use_html) {
                resp.append("<pre>");
            }
            resp.append(prof_result);
            if (use_html) {
                resp.append("</pre></body></html>");
            }
            return;
        }
    }
    
    std::ostringstream cmd_builder;

    std::string pprof_tool{GeneratePerlScriptPath(PPROF_FILENAME)};

#if defined(OS_LINUX)
    cmd_builder << "perl " << pprof_tool
                << DisplayTypeToPProfArgument(display_type)
                << ((show_ccount || type == PROFILING_IOBUF) ? " --contention " : "");
    if (base_name) {
        cmd_builder << "--base " << *base_name << ' ';
    }

    cmd_builder << GetProgramPath() << " " << prof_name;

    if (display_type == DisplayType::kFlameGraph) {
        // For flamegraph, we don't care about pprof error msg, 
        // which will cause confusing messages in the final result.
        cmd_builder << " 2>/dev/null  | perl " <<  flamegraph_tool << " --width "
                    << (FLAGS_max_flame_graph_width > 0 ? FLAGS_max_flame_graph_width : 1200);
    }
    cmd_builder << " 2>&1 ";
#elif defined(OS_MACOSX)
    cmd_builder << s_pprof_binary_path << " "
                << DisplayTypeToPProfArgument(display_type)
                << ((show_ccount || type == PROFILING_IOBUF) ? " --contention " : "");
    if (base_name) {
        cmd_builder << "-base " << *base_name << ' ';
    }
    cmd_builder << GetProgramPath() << " " << prof_name << " 2>&1 ";
#endif

    const std::string cmd = cmd_builder.str();
    for (int ntry = 0; ntry < 2; ++ntry) {
        if (!g_written_pprof_perl) {
            if (!WriteSmallFile(pprof_tool.c_str(), pprof_perl())) {
                os << "Fail to write " << pprof_tool
                   << (use_html ? "</body></html>" : "\n");
                os.move_to(resp);
                cntl->http_response().set_status_code(
                    HTTP_STATUS_INTERNAL_SERVER_ERROR);
                return;
            }
            g_written_pprof_perl = true;
        }
        errno = 0; // read_command_output may not set errno, clear it to make sure if
                   // we see non-zero errno, it's real error.
        butil::IOBufBuilder pprof_output;
        RPC_VLOG << "Running cmd=" << cmd;
        const int rc = butil::read_command_output(pprof_output, cmd.c_str());
        if (rc != 0) {
            butil::FilePath pprof_path(pprof_tool);
            if (!butil::PathExists(pprof_path)) {
                // Write the script again.
                g_written_pprof_perl = false;
                // tell user.
                os << pprof_path.value() << " was removed, recreate ...\n\n";
                continue;
            }
            if (rc < 0) {
                os << "Fail to execute `" << cmd << "', " << berror()
                   << (use_html ? "</body></html>" : "\n");
                os.move_to(resp);
                cntl->http_response().set_status_code(
                    HTTP_STATUS_INTERNAL_SERVER_ERROR);
                return;
            }
            // cmd returns non zero, quit normally 
        }
        pprof_output.move_to(prof_result);
        // Cache result in file.
        char result_name[256];
        MakeCacheName(result_name, sizeof(result_name), prof_name,
                      GetBaseName(base_name), display_type, show_ccount);

        // Append the profile name as the visual reminder for what
        // current profile is.
        butil::IOBuf before_label;
        butil::IOBuf tmp;
        if (cntl->http_request().uri().GetQuery("view") == NULL) {
            tmp.append(prof_name);
            tmp.append("[addToProfEnd]");
        }
        if (prof_result.cut_until(&before_label, ",label=\"") == 0) {
            tmp.append(before_label);
            tmp.append(",label=\"[");
            tmp.append(GetBaseName(prof_name));
            if (base_name) {
                tmp.append(" - ");
                tmp.append(GetBaseName(base_name));
            }
            tmp.append("]\\l");
            tmp.append(prof_result);
            tmp.swap(prof_result);
        } else {
            // Assume it's text. append before result directly.
            tmp.append("[");
            tmp.append(GetBaseName(prof_name));
            if (base_name) {
                tmp.append(" - ");
                tmp.append(GetBaseName(base_name));
            }
            tmp.append("]\n");
            tmp.append(prof_result);
            tmp.swap(prof_result);
        }
        
        if (!WriteSmallFile(result_name, prof_result)) {
            LOG(ERROR) << "Fail to write " << result_name;
            CHECK(butil::DeleteFile(butil::FilePath(result_name), false));
        }
        break;
    }
    // NOTE: not send prof_result to os first which does copying.
    os.move_to(resp);
    if (use_html) {
        resp.append("<pre>");
    }
    resp.append(prof_result);
    if (use_html) {
        resp.append("</pre></body></html>");
    }
}