File indexing completed on 2024-05-12 03:47:46
0001 /* 0002 File : trace.h 0003 Project : LabPlot 0004 Description : Function and macros related to performance and debugging tracing 0005 -------------------------------------------------------------------- 0006 SPDX-FileCopyrightText: 2017 Alexander Semke <alexander.semke@web.de> 0007 SPDX-License-Identifier: GPL-2.0-or-later 0008 */ 0009 0010 #ifndef TRACE_H 0011 #define TRACE_H 0012 0013 #include "backend/lib/macros.h" 0014 #include <chrono> 0015 0016 class PerfTracer { 0017 public: 0018 explicit PerfTracer(QString m) { 0019 msg = STDSTRING(m); 0020 start = std::chrono::high_resolution_clock::now(); 0021 }; 0022 ~PerfTracer() { 0023 auto end = std::chrono::high_resolution_clock::now(); 0024 auto diff = std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count(); 0025 std::cout << msg << ": " << diff << " ms" << std::endl; 0026 } 0027 0028 private: 0029 std::chrono::high_resolution_clock::time_point start; 0030 std::string msg; 0031 }; 0032 0033 #define PERFTRACE_ENABLED 1 0034 0035 #define PERFTRACE_CURVES 1 0036 #define PERFTRACE_AXIS 1 0037 #define PERFTRACE_LIVE_IMPORT 1 0038 #define PERFTRACE_AUTOSCALE 1 0039 #define PERFTRACE_EXPRESSION_PARSER 1 0040 0041 #ifdef PERFTRACE_ENABLED 0042 #define PERFTRACE(msg) PerfTracer tracer(msg) 0043 #else 0044 #define PERFTRACE(msg) DEBUG(msg) 0045 #endif 0046 0047 #ifndef HAVE_WINDOWS 0048 0049 #include <cxxabi.h> //__cxa_demangle 0050 #include <dlfcn.h> //dladdr 0051 #include <execinfo.h> //backtrace 0052 0053 #include <cstdio> 0054 #include <cstdlib> 0055 #include <sstream> 0056 #include <string> 0057 0058 /*! 0059 * this function prints the current call stack and helps to figure out why a certain (e.g. performance critical) function 0060 * is called multiple times and from where without involving the debugger. 0061 * To get the callstack, simple include \c print_callstack() in the function of interest. 0062 */ 0063 static inline void print_callstack() { 0064 // get the current call stack 0065 const int max_frames_count = 10 + 1; // print the last 10 frames (+1 because of this function frame) 0066 void* callstack[max_frames_count]; 0067 const int frames_count = backtrace(callstack, max_frames_count); 0068 0069 // get the symbols 0070 char** symbols = backtrace_symbols(callstack, frames_count); 0071 0072 std::ostringstream out; 0073 char buf[1024]; 0074 0075 // iterate over the frames, skip the first one (frame of this function call) 0076 for (int i = 1; i < frames_count; i++) { 0077 Dl_info info; 0078 if (dladdr(callstack[i], &info) && info.dli_sname) { 0079 char* demangled_name = nullptr; 0080 const char* name_to_print = nullptr; 0081 int status = -1; 0082 if (info.dli_sname[0] == '_') 0083 demangled_name = abi::__cxa_demangle(info.dli_sname, nullptr, nullptr, &status); 0084 0085 if (status == 0) 0086 name_to_print = demangled_name; 0087 else { 0088 if (info.dli_sname == nullptr) 0089 name_to_print = symbols[i]; 0090 else 0091 name_to_print = info.dli_sname; 0092 } 0093 0094 snprintf(buf, 0095 sizeof(buf), 0096 "%-3d %*p %s + %zd\n", 0097 i, 0098 int(2 + sizeof(void*) * 2), 0099 callstack[i], 0100 name_to_print, 0101 (char*)callstack[i] - (char*)info.dli_saddr); 0102 0103 free(demangled_name); 0104 } else { 0105 snprintf(buf, sizeof(buf), "%-3d %*p %s\n", i, int(2 + sizeof(void*) * 2), callstack[i], symbols[i]); 0106 } 0107 out << buf; 0108 } 0109 free(symbols); 0110 0111 std::cout << "stack trace:\n" << out.str(); 0112 } 0113 #endif // #ifndef HAVE_WINDOWS 0114 0115 #define DEBUG_DUMP_PAINTER_PATH 1 0116 #if DEBUG_DUMP_PAINTER_PATH == 0 0117 #define DUMP_PAINTER_PATH(path) \ 0118 do { \ 0119 DEBUG("Dump QPainterPath"); \ 0120 if (path.isEmpty()) \ 0121 DEBUG("\tPath is empty"); \ 0122 for (int i = 0; i < path.elementCount(); i++) { \ 0123 const auto& element = path.elementAt(i); \ 0124 QString type; \ 0125 switch (element.type) { \ 0126 case QPainterPath::MoveToElement: \ 0127 type = QStringLiteral("MoveToElement"); \ 0128 break; \ 0129 case QPainterPath::LineToElement: \ 0130 type = QStringLiteral("LineToElement"); \ 0131 break; \ 0132 case QPainterPath::CurveToElement: \ 0133 type = QStringLiteral("CurveToElement"); \ 0134 break; \ 0135 case QPainterPath::CurveToDataElement: \ 0136 type = QStringLiteral("CurveToDataElement"); \ 0137 break; \ 0138 } \ 0139 DEBUG("\tQPainterPathElement: " << type.toStdString() << " (" << element.x << "," << element.y << ")"); \ 0140 } \ 0141 } while (false); 0142 #else 0143 #define DUMP_PAINTER_PATH(path) 0144 #endif 0145 0146 #endif // TRACE_H