109 lines
3.2 KiB
C++
109 lines
3.2 KiB
C++
/*
|
|
* PyPerf Profile Python Processes with Python stack-trace.
|
|
* For Linux, uses BCC, eBPF. Embedded C.
|
|
*
|
|
* Example of using BPF to profile Python Processes with Python stack-trace.
|
|
*
|
|
* USAGE: PyPerf [-d|--duration DURATION_MS] [-c|--sample-rate SAMPLE_RATE]
|
|
* [-v|--verbosity LOG_VERBOSITY]
|
|
*
|
|
* Copyright (c) Facebook, Inc.
|
|
* Licensed under the Apache License, Version 2.0 (the "License")
|
|
*/
|
|
|
|
#include <cinttypes>
|
|
#include <cstdlib>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
#include "PyPerfDefaultPrinter.h"
|
|
#include "PyPerfLoggingHelper.h"
|
|
#include "PyPerfUtil.h"
|
|
|
|
int main(int argc, char** argv) {
|
|
// Argument parsing helpers
|
|
int pos = 1;
|
|
|
|
auto parseIntArg = [&](std::vector<std::string> argNames, uint64_t& target) {
|
|
std::string arg(argv[pos]);
|
|
for (const auto& name : argNames) {
|
|
if (arg == name) {
|
|
if (pos == argc) {
|
|
std::fprintf(stderr, "Expect value after %s\n", arg.c_str());
|
|
std::exit(1);
|
|
}
|
|
pos++;
|
|
std::string value(argv[pos]);
|
|
try {
|
|
target = std::stoi(value);
|
|
} catch (const std::exception& e) {
|
|
std::fprintf(stderr, "Expect integer value after %s, got %s: %s\n",
|
|
arg.c_str(), value.c_str(), e.what());
|
|
std::exit(1);
|
|
}
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
};
|
|
|
|
auto parseBoolArg = [&](std::vector<std::string> argNames, bool& target) {
|
|
std::string arg(argv[pos]);
|
|
for (const auto& name : argNames) {
|
|
if (arg == ("--" + name)) {
|
|
target = true;
|
|
return true;
|
|
}
|
|
if (arg == "--no-" + name) {
|
|
target = false;
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
};
|
|
|
|
// Default argument values
|
|
uint64_t sampleRate = 1000000;
|
|
uint64_t durationMs = 1000;
|
|
uint64_t verbosityLevel = 0;
|
|
bool showGILState = true;
|
|
bool showThreadState = true;
|
|
bool showPthreadIDState = false;
|
|
|
|
while (true) {
|
|
if (pos >= argc) {
|
|
break;
|
|
}
|
|
bool found = false;
|
|
found = found || parseIntArg({"-c", "--sample-rate"}, sampleRate);
|
|
found = found || parseIntArg({"-d", "--duration"}, durationMs);
|
|
found = found || parseIntArg({"-v", "--verbose"}, verbosityLevel);
|
|
found = found || parseBoolArg({"show-gil-state"}, showGILState);
|
|
found = found || parseBoolArg({"show-thread-state"}, showThreadState);
|
|
found =
|
|
found || parseBoolArg({"show-pthread-id-state"}, showPthreadIDState);
|
|
if (!found) {
|
|
std::fprintf(stderr, "Unexpected argument: %s\n", argv[pos]);
|
|
std::exit(1);
|
|
}
|
|
pos++;
|
|
}
|
|
|
|
ebpf::pyperf::setVerbosity(verbosityLevel);
|
|
ebpf::pyperf::logInfo(1, "Profiling Sample Rate: %" PRIu64 "\n", sampleRate);
|
|
ebpf::pyperf::logInfo(1, "Profiling Duration: %" PRIu64 "ms\n", durationMs);
|
|
ebpf::pyperf::logInfo(1, "Showing GIL state: %d\n", showGILState);
|
|
ebpf::pyperf::logInfo(1, "Showing Thread state: %d\n", showThreadState);
|
|
ebpf::pyperf::logInfo(1, "Showing Pthread ID state: %d\n",
|
|
showPthreadIDState);
|
|
|
|
ebpf::pyperf::PyPerfUtil util;
|
|
util.init();
|
|
|
|
ebpf::pyperf::PyPerfDefaultPrinter printer(showGILState, showThreadState,
|
|
showPthreadIDState);
|
|
util.profile(sampleRate, durationMs, &printer);
|
|
|
|
return 0;
|
|
}
|