| /* | |
| * Copyright (c) Facebook, Inc. | |
| * Licensed under the Apache License, Version 2.0 (the "License") | |
| */ | |
| #include <map> | |
| #include <string> | |
| #include "PyPerfDefaultPrinter.h" | |
| #include "PyPerfUtil.h" | |
| namespace ebpf { | |
| namespace pyperf { | |
| const static std::string kLostSymbol = "[Lost Symbol]"; | |
| const static std::string kIncompleteStack = "[Truncated Stack]"; | |
| const static std::string kErrorStack = "[Stack Error]"; | |
| const static std::string kNonPythonStack = "[Non-Python Code]"; | |
| const static std::map<int, const char*> kGILStateValues = { | |
| {GIL_STATE_NO_INFO, "No GIL Info"}, | |
| {GIL_STATE_ERROR, "Error Reading GIL State"}, | |
| {GIL_STATE_UNINITIALIZED, "GIL Uninitialized"}, | |
| {GIL_STATE_NOT_LOCKED, "GIL Not Locked"}, | |
| {GIL_STATE_THIS_THREAD, "GIL on This Thread"}, | |
| {GIL_STATE_GLOBAL_CURRENT_THREAD, | |
| "GIL on Global _PyThreadState_Current Thread"}, | |
| {GIL_STATE_OTHER_THREAD, "GIL on Unexpected Thread"}, | |
| {GIL_STATE_NULL, "GIL State Empty"}}; | |
| const static std::map<int, const char*> kThreadStateValues = { | |
| {THREAD_STATE_UNKNOWN, "ThreadState Unknown"}, | |
| {THREAD_STATE_MATCH, "TLS ThreadState is Global _PyThreadState_Current"}, | |
| {THREAD_STATE_MISMATCH, | |
| "TLS ThreadState is not Global _PyThreadState_Current"}, | |
| {THREAD_STATE_THIS_THREAD_NULL, "TLS ThreadState is NULL"}, | |
| {THREAD_STATE_GLOBAL_CURRENT_THREAD_NULL, | |
| "Global _PyThreadState_Current is NULL"}, | |
| {THREAD_STATE_BOTH_NULL, | |
| "Both TLS ThreadState and Global _PyThreadState_Current is NULL"}, | |
| }; | |
| const static std::map<int, const char*> kPthreadIDStateValues = { | |
| {PTHREAD_ID_UNKNOWN, "Pthread ID Unknown"}, | |
| {PTHREAD_ID_MATCH, "System Pthread ID is Python ThreadState Pthread ID"}, | |
| {PTHREAD_ID_MISMATCH, | |
| "System Pthread ID is not Python ThreadState Pthread ID"}, | |
| {PTHREAD_ID_THREAD_STATE_NULL, "No Pthread ID: TLS ThreadState is NULL"}, | |
| {PTHREAD_ID_NULL, "Pthread ID on TLS ThreadState is NULL"}, | |
| {PTHREAD_ID_ERROR, "Error Reading System Pthread ID"}}; | |
| void PyPerfDefaultPrinter::processSamples( | |
| const std::vector<PyPerfSample>& samples, PyPerfUtil* util) { | |
| auto symbols = util->getSymbolMapping(); | |
| uint32_t lostSymbols = 0; | |
| uint32_t truncatedStack = 0; | |
| for (auto& sample : samples) { | |
| if (sample.threadStateMatch != THREAD_STATE_THIS_THREAD_NULL && | |
| sample.threadStateMatch != THREAD_STATE_BOTH_NULL) { | |
| for (const auto stackId : sample.pyStackIds) { | |
| auto symbIt = symbols.find(stackId); | |
| if (symbIt != symbols.end()) { | |
| std::printf(" %s\n", symbIt->second.c_str()); | |
| } else { | |
| std::printf(" %s\n", kLostSymbol.c_str()); | |
| lostSymbols++; | |
| } | |
| } | |
| switch (sample.stackStatus) { | |
| case STACK_STATUS_TRUNCATED: | |
| std::printf(" %s\n", kIncompleteStack.c_str()); | |
| truncatedStack++; | |
| break; | |
| case STACK_STATUS_ERROR: | |
| std::printf(" %s\n", kErrorStack.c_str()); | |
| break; | |
| default: | |
| break; | |
| } | |
| } else { | |
| std::printf(" %s\n", kNonPythonStack.c_str()); | |
| } | |
| std::printf("PID: %d TID: %d (%s)\n", sample.pid, sample.tid, | |
| sample.comm.c_str()); | |
| if (showGILState_) | |
| std::printf("GIL State: %s\n", kGILStateValues.at(sample.gilState)); | |
| if (showThreadState_) | |
| std::printf("Thread State: %s\n", | |
| kThreadStateValues.at(sample.threadStateMatch)); | |
| if (showPthreadIDState_) | |
| std::printf("Pthread ID State: %s\n", | |
| kPthreadIDStateValues.at(sample.pthreadIDMatch)); | |
| std::printf("\n"); | |
| } | |
| std::printf("%d samples collected\n", util->getTotalSamples()); | |
| std::printf("%d samples lost\n", util->getLostSamples()); | |
| std::printf("%d samples with truncated stack\n", truncatedStack); | |
| std::printf("%d times Python symbol lost\n", lostSymbols); | |
| } | |
| } // namespace pyperf | |
| } // namespace ebpf |