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