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