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