1 /* 2 * Copyright (c) Facebook, Inc. 3 * Licensed under the Apache License, Version 2.0 (the "License") 4 */ 5 6 #pragma once 7 8 #include <sys/types.h> 9 #include <cstdint> 10 #include <string> 11 #include <vector> 12 13 #define PYTHON_STACK_FRAMES_PER_PROG 25 14 #define PYTHON_STACK_PROG_CNT 3 15 #define STACK_MAX_LEN (PYTHON_STACK_FRAMES_PER_PROG * PYTHON_STACK_PROG_CNT) 16 #define CLASS_NAME_LEN 32 17 #define FUNCTION_NAME_LEN 64 18 #define FILE_NAME_LEN 128 19 #define TASK_COMM_LEN 16 20 21 namespace ebpf { 22 namespace pyperf { 23 24 enum { 25 STACK_STATUS_COMPLETE = 0, 26 STACK_STATUS_ERROR = 1, 27 STACK_STATUS_TRUNCATED = 2, 28 }; 29 30 enum { 31 GIL_STATE_NO_INFO = 0, 32 GIL_STATE_ERROR = 1, 33 GIL_STATE_UNINITIALIZED = 2, 34 GIL_STATE_NOT_LOCKED = 3, 35 GIL_STATE_THIS_THREAD = 4, 36 GIL_STATE_GLOBAL_CURRENT_THREAD = 5, 37 GIL_STATE_OTHER_THREAD = 6, 38 GIL_STATE_NULL = 7, 39 }; 40 41 enum { 42 THREAD_STATE_UNKNOWN = 0, 43 THREAD_STATE_MATCH = 1, 44 THREAD_STATE_MISMATCH = 2, 45 THREAD_STATE_THIS_THREAD_NULL = 3, 46 THREAD_STATE_GLOBAL_CURRENT_THREAD_NULL = 4, 47 THREAD_STATE_BOTH_NULL = 5, 48 }; 49 50 enum { 51 PTHREAD_ID_UNKNOWN = 0, 52 PTHREAD_ID_MATCH = 1, 53 PTHREAD_ID_MISMATCH = 2, 54 PTHREAD_ID_THREAD_STATE_NULL = 3, 55 PTHREAD_ID_NULL = 4, 56 PTHREAD_ID_ERROR = 5, 57 }; 58 59 typedef struct { 60 int64_t PyObject_type; 61 int64_t PyTypeObject_name; 62 int64_t PyThreadState_frame; 63 int64_t PyThreadState_thread; 64 int64_t PyFrameObject_back; 65 int64_t PyFrameObject_code; 66 int64_t PyFrameObject_lineno; 67 int64_t PyFrameObject_localsplus; 68 int64_t PyCodeObject_filename; 69 int64_t PyCodeObject_name; 70 int64_t PyCodeObject_varnames; 71 int64_t PyTupleObject_item; 72 int64_t String_data; 73 int64_t String_size; 74 } OffsetConfig; 75 76 typedef struct { 77 uintptr_t current_state_addr; // virtual address of _PyThreadState_Current 78 uintptr_t tls_key_addr; // virtual address of autoTLSkey for pthreads TLS 79 uintptr_t gil_locked_addr; // virtual address of gil_locked 80 uintptr_t gil_last_holder_addr; // virtual address of gil_last_holder 81 OffsetConfig offsets; 82 } PidData; 83 84 typedef struct { 85 char classname[CLASS_NAME_LEN]; 86 char name[FUNCTION_NAME_LEN]; 87 char file[FILE_NAME_LEN]; 88 // NOTE: PyFrameObject also has line number but it is typically just the 89 // first line of that function and PyCode_Addr2Line needs to be called 90 // to get the actual line 91 } Symbol; 92 93 typedef struct { 94 uint32_t pid; 95 uint32_t tid; 96 char comm[TASK_COMM_LEN]; 97 uint8_t thread_state_match; 98 uint8_t gil_state; 99 uint8_t pthread_id_match; 100 uint8_t stack_status; 101 // instead of storing symbol name here directly, we add it to another 102 // hashmap with Symbols and only store the ids here 103 int64_t stack_len; 104 int32_t stack[STACK_MAX_LEN]; 105 } Event; 106 107 struct PyPerfSample { 108 pid_t pid; 109 pid_t tid; 110 std::string comm; 111 uint8_t threadStateMatch; 112 uint8_t gilState; 113 uint8_t pthreadIDMatch; 114 uint8_t stackStatus; 115 std::vector<int32_t> pyStackIds; 116 PyPerfSamplePyPerfSample117 explicit PyPerfSample(const Event* raw, int rawSize) 118 : pid(raw->pid), 119 tid(raw->tid), 120 comm(raw->comm), 121 threadStateMatch(raw->thread_state_match), 122 gilState(raw->gil_state), 123 pthreadIDMatch(raw->pthread_id_match), 124 stackStatus(raw->stack_status), 125 pyStackIds(raw->stack, raw->stack + raw->stack_len) {} 126 }; 127 128 } // namespace pyperf 129 } // namespace ebpf 130