| /* | |
| * 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; | |
| } |