1 /*
2 * Copyright (c) Facebook, Inc.
3 * Licensed under the Apache License, Version 2.0 (the "License")
4 */
5
6 #include <map>
7 #include <string>
8
9 #include "PyPerfDefaultPrinter.h"
10 #include "PyPerfUtil.h"
11
12 namespace ebpf {
13 namespace pyperf {
14
15 const static std::string kLostSymbol = "[Lost Symbol]";
16 const static std::string kIncompleteStack = "[Truncated Stack]";
17 const static std::string kErrorStack = "[Stack Error]";
18 const static std::string kNonPythonStack = "[Non-Python Code]";
19
20 const static std::map<int, const char*> kGILStateValues = {
21 {GIL_STATE_NO_INFO, "No GIL Info"},
22 {GIL_STATE_ERROR, "Error Reading GIL State"},
23 {GIL_STATE_UNINITIALIZED, "GIL Uninitialized"},
24 {GIL_STATE_NOT_LOCKED, "GIL Not Locked"},
25 {GIL_STATE_THIS_THREAD, "GIL on This Thread"},
26 {GIL_STATE_GLOBAL_CURRENT_THREAD,
27 "GIL on Global _PyThreadState_Current Thread"},
28 {GIL_STATE_OTHER_THREAD, "GIL on Unexpected Thread"},
29 {GIL_STATE_NULL, "GIL State Empty"}};
30
31 const static std::map<int, const char*> kThreadStateValues = {
32 {THREAD_STATE_UNKNOWN, "ThreadState Unknown"},
33 {THREAD_STATE_MATCH, "TLS ThreadState is Global _PyThreadState_Current"},
34 {THREAD_STATE_MISMATCH,
35 "TLS ThreadState is not Global _PyThreadState_Current"},
36 {THREAD_STATE_THIS_THREAD_NULL, "TLS ThreadState is NULL"},
37 {THREAD_STATE_GLOBAL_CURRENT_THREAD_NULL,
38 "Global _PyThreadState_Current is NULL"},
39 {THREAD_STATE_BOTH_NULL,
40 "Both TLS ThreadState and Global _PyThreadState_Current is NULL"},
41 };
42
43 const static std::map<int, const char*> kPthreadIDStateValues = {
44 {PTHREAD_ID_UNKNOWN, "Pthread ID Unknown"},
45 {PTHREAD_ID_MATCH, "System Pthread ID is Python ThreadState Pthread ID"},
46 {PTHREAD_ID_MISMATCH,
47 "System Pthread ID is not Python ThreadState Pthread ID"},
48 {PTHREAD_ID_THREAD_STATE_NULL, "No Pthread ID: TLS ThreadState is NULL"},
49 {PTHREAD_ID_NULL, "Pthread ID on TLS ThreadState is NULL"},
50 {PTHREAD_ID_ERROR, "Error Reading System Pthread ID"}};
51
processSamples(const std::vector<PyPerfSample> & samples,PyPerfUtil * util)52 void PyPerfDefaultPrinter::processSamples(
53 const std::vector<PyPerfSample>& samples, PyPerfUtil* util) {
54 auto symbols = util->getSymbolMapping();
55 uint32_t lostSymbols = 0;
56 uint32_t truncatedStack = 0;
57
58 for (auto& sample : samples) {
59 if (sample.threadStateMatch != THREAD_STATE_THIS_THREAD_NULL &&
60 sample.threadStateMatch != THREAD_STATE_BOTH_NULL) {
61 for (const auto stackId : sample.pyStackIds) {
62 auto symbIt = symbols.find(stackId);
63 if (symbIt != symbols.end()) {
64 std::printf(" %s\n", symbIt->second.c_str());
65 } else {
66 std::printf(" %s\n", kLostSymbol.c_str());
67 lostSymbols++;
68 }
69 }
70 switch (sample.stackStatus) {
71 case STACK_STATUS_TRUNCATED:
72 std::printf(" %s\n", kIncompleteStack.c_str());
73 truncatedStack++;
74 break;
75 case STACK_STATUS_ERROR:
76 std::printf(" %s\n", kErrorStack.c_str());
77 break;
78 default:
79 break;
80 }
81 } else {
82 std::printf(" %s\n", kNonPythonStack.c_str());
83 }
84
85 std::printf("PID: %d TID: %d (%s)\n", sample.pid, sample.tid,
86 sample.comm.c_str());
87 if (showGILState_)
88 std::printf("GIL State: %s\n", kGILStateValues.at(sample.gilState));
89 if (showThreadState_)
90 std::printf("Thread State: %s\n",
91 kThreadStateValues.at(sample.threadStateMatch));
92 if (showPthreadIDState_)
93 std::printf("Pthread ID State: %s\n",
94 kPthreadIDStateValues.at(sample.pthreadIDMatch));
95
96 std::printf("\n");
97 }
98
99 std::printf("%d samples collected\n", util->getTotalSamples());
100 std::printf("%d samples lost\n", util->getLostSamples());
101 std::printf("%d samples with truncated stack\n", truncatedStack);
102 std::printf("%d times Python symbol lost\n", lostSymbols);
103 }
104
105 } // namespace pyperf
106 } // namespace ebpf
107