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