1*387f9dfdSAndroid Build Coastguard Worker /*
2*387f9dfdSAndroid Build Coastguard Worker * PyPerf Profile Python Processes with Python stack-trace.
3*387f9dfdSAndroid Build Coastguard Worker * For Linux, uses BCC, eBPF. Embedded C.
4*387f9dfdSAndroid Build Coastguard Worker *
5*387f9dfdSAndroid Build Coastguard Worker * Example of using BPF to profile Python Processes with Python stack-trace.
6*387f9dfdSAndroid Build Coastguard Worker *
7*387f9dfdSAndroid Build Coastguard Worker * USAGE: PyPerf [-d|--duration DURATION_MS] [-c|--sample-rate SAMPLE_RATE]
8*387f9dfdSAndroid Build Coastguard Worker * [-v|--verbosity LOG_VERBOSITY]
9*387f9dfdSAndroid Build Coastguard Worker *
10*387f9dfdSAndroid Build Coastguard Worker * Copyright (c) Facebook, Inc.
11*387f9dfdSAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License")
12*387f9dfdSAndroid Build Coastguard Worker */
13*387f9dfdSAndroid Build Coastguard Worker
14*387f9dfdSAndroid Build Coastguard Worker #include <cinttypes>
15*387f9dfdSAndroid Build Coastguard Worker #include <cstdlib>
16*387f9dfdSAndroid Build Coastguard Worker #include <string>
17*387f9dfdSAndroid Build Coastguard Worker #include <vector>
18*387f9dfdSAndroid Build Coastguard Worker
19*387f9dfdSAndroid Build Coastguard Worker #include "PyPerfDefaultPrinter.h"
20*387f9dfdSAndroid Build Coastguard Worker #include "PyPerfLoggingHelper.h"
21*387f9dfdSAndroid Build Coastguard Worker #include "PyPerfUtil.h"
22*387f9dfdSAndroid Build Coastguard Worker
main(int argc,char ** argv)23*387f9dfdSAndroid Build Coastguard Worker int main(int argc, char** argv) {
24*387f9dfdSAndroid Build Coastguard Worker // Argument parsing helpers
25*387f9dfdSAndroid Build Coastguard Worker int pos = 1;
26*387f9dfdSAndroid Build Coastguard Worker
27*387f9dfdSAndroid Build Coastguard Worker auto parseIntArg = [&](std::vector<std::string> argNames, uint64_t& target) {
28*387f9dfdSAndroid Build Coastguard Worker std::string arg(argv[pos]);
29*387f9dfdSAndroid Build Coastguard Worker for (const auto& name : argNames) {
30*387f9dfdSAndroid Build Coastguard Worker if (arg == name) {
31*387f9dfdSAndroid Build Coastguard Worker if (pos == argc) {
32*387f9dfdSAndroid Build Coastguard Worker std::fprintf(stderr, "Expect value after %s\n", arg.c_str());
33*387f9dfdSAndroid Build Coastguard Worker std::exit(1);
34*387f9dfdSAndroid Build Coastguard Worker }
35*387f9dfdSAndroid Build Coastguard Worker pos++;
36*387f9dfdSAndroid Build Coastguard Worker std::string value(argv[pos]);
37*387f9dfdSAndroid Build Coastguard Worker try {
38*387f9dfdSAndroid Build Coastguard Worker target = std::stoi(value);
39*387f9dfdSAndroid Build Coastguard Worker } catch (const std::exception& e) {
40*387f9dfdSAndroid Build Coastguard Worker std::fprintf(stderr, "Expect integer value after %s, got %s: %s\n",
41*387f9dfdSAndroid Build Coastguard Worker arg.c_str(), value.c_str(), e.what());
42*387f9dfdSAndroid Build Coastguard Worker std::exit(1);
43*387f9dfdSAndroid Build Coastguard Worker }
44*387f9dfdSAndroid Build Coastguard Worker return true;
45*387f9dfdSAndroid Build Coastguard Worker }
46*387f9dfdSAndroid Build Coastguard Worker }
47*387f9dfdSAndroid Build Coastguard Worker return false;
48*387f9dfdSAndroid Build Coastguard Worker };
49*387f9dfdSAndroid Build Coastguard Worker
50*387f9dfdSAndroid Build Coastguard Worker auto parseBoolArg = [&](std::vector<std::string> argNames, bool& target) {
51*387f9dfdSAndroid Build Coastguard Worker std::string arg(argv[pos]);
52*387f9dfdSAndroid Build Coastguard Worker for (const auto& name : argNames) {
53*387f9dfdSAndroid Build Coastguard Worker if (arg == ("--" + name)) {
54*387f9dfdSAndroid Build Coastguard Worker target = true;
55*387f9dfdSAndroid Build Coastguard Worker return true;
56*387f9dfdSAndroid Build Coastguard Worker }
57*387f9dfdSAndroid Build Coastguard Worker if (arg == "--no-" + name) {
58*387f9dfdSAndroid Build Coastguard Worker target = false;
59*387f9dfdSAndroid Build Coastguard Worker return true;
60*387f9dfdSAndroid Build Coastguard Worker }
61*387f9dfdSAndroid Build Coastguard Worker }
62*387f9dfdSAndroid Build Coastguard Worker return false;
63*387f9dfdSAndroid Build Coastguard Worker };
64*387f9dfdSAndroid Build Coastguard Worker
65*387f9dfdSAndroid Build Coastguard Worker // Default argument values
66*387f9dfdSAndroid Build Coastguard Worker uint64_t sampleRate = 1000000;
67*387f9dfdSAndroid Build Coastguard Worker uint64_t durationMs = 1000;
68*387f9dfdSAndroid Build Coastguard Worker uint64_t verbosityLevel = 0;
69*387f9dfdSAndroid Build Coastguard Worker bool showGILState = true;
70*387f9dfdSAndroid Build Coastguard Worker bool showThreadState = true;
71*387f9dfdSAndroid Build Coastguard Worker bool showPthreadIDState = false;
72*387f9dfdSAndroid Build Coastguard Worker
73*387f9dfdSAndroid Build Coastguard Worker while (true) {
74*387f9dfdSAndroid Build Coastguard Worker if (pos >= argc) {
75*387f9dfdSAndroid Build Coastguard Worker break;
76*387f9dfdSAndroid Build Coastguard Worker }
77*387f9dfdSAndroid Build Coastguard Worker bool found = false;
78*387f9dfdSAndroid Build Coastguard Worker found = found || parseIntArg({"-c", "--sample-rate"}, sampleRate);
79*387f9dfdSAndroid Build Coastguard Worker found = found || parseIntArg({"-d", "--duration"}, durationMs);
80*387f9dfdSAndroid Build Coastguard Worker found = found || parseIntArg({"-v", "--verbose"}, verbosityLevel);
81*387f9dfdSAndroid Build Coastguard Worker found = found || parseBoolArg({"show-gil-state"}, showGILState);
82*387f9dfdSAndroid Build Coastguard Worker found = found || parseBoolArg({"show-thread-state"}, showThreadState);
83*387f9dfdSAndroid Build Coastguard Worker found =
84*387f9dfdSAndroid Build Coastguard Worker found || parseBoolArg({"show-pthread-id-state"}, showPthreadIDState);
85*387f9dfdSAndroid Build Coastguard Worker if (!found) {
86*387f9dfdSAndroid Build Coastguard Worker std::fprintf(stderr, "Unexpected argument: %s\n", argv[pos]);
87*387f9dfdSAndroid Build Coastguard Worker std::exit(1);
88*387f9dfdSAndroid Build Coastguard Worker }
89*387f9dfdSAndroid Build Coastguard Worker pos++;
90*387f9dfdSAndroid Build Coastguard Worker }
91*387f9dfdSAndroid Build Coastguard Worker
92*387f9dfdSAndroid Build Coastguard Worker ebpf::pyperf::setVerbosity(verbosityLevel);
93*387f9dfdSAndroid Build Coastguard Worker ebpf::pyperf::logInfo(1, "Profiling Sample Rate: %" PRIu64 "\n", sampleRate);
94*387f9dfdSAndroid Build Coastguard Worker ebpf::pyperf::logInfo(1, "Profiling Duration: %" PRIu64 "ms\n", durationMs);
95*387f9dfdSAndroid Build Coastguard Worker ebpf::pyperf::logInfo(1, "Showing GIL state: %d\n", showGILState);
96*387f9dfdSAndroid Build Coastguard Worker ebpf::pyperf::logInfo(1, "Showing Thread state: %d\n", showThreadState);
97*387f9dfdSAndroid Build Coastguard Worker ebpf::pyperf::logInfo(1, "Showing Pthread ID state: %d\n",
98*387f9dfdSAndroid Build Coastguard Worker showPthreadIDState);
99*387f9dfdSAndroid Build Coastguard Worker
100*387f9dfdSAndroid Build Coastguard Worker ebpf::pyperf::PyPerfUtil util;
101*387f9dfdSAndroid Build Coastguard Worker util.init();
102*387f9dfdSAndroid Build Coastguard Worker
103*387f9dfdSAndroid Build Coastguard Worker ebpf::pyperf::PyPerfDefaultPrinter printer(showGILState, showThreadState,
104*387f9dfdSAndroid Build Coastguard Worker showPthreadIDState);
105*387f9dfdSAndroid Build Coastguard Worker util.profile(sampleRate, durationMs, &printer);
106*387f9dfdSAndroid Build Coastguard Worker
107*387f9dfdSAndroid Build Coastguard Worker return 0;
108*387f9dfdSAndroid Build Coastguard Worker }
109