File indexing completed on 2024-05-12 15:27:01

0001 /***************************************************************************
0002     File                 : trace.h
0003     Project              : LabPlot
0004     Description          : Function and macros related to performance and debugging tracing
0005     --------------------------------------------------------------------
0006     Copyright            : (C) 2017 Alexander Semke (alexander.semke@web.de)
0007 
0008  ***************************************************************************/
0009 
0010 /***************************************************************************
0011  *                                                                         *
0012  *  This program is free software; you can redistribute it and/or modify   *
0013  *  it under the terms of the GNU General Public License as published by   *
0014  *  the Free Software Foundation; either version 2 of the License, or      *
0015  *  (at your option) any later version.                                    *
0016  *                                                                         *
0017  *  This program is distributed in the hope that it will be useful,        *
0018  *  but WITHOUT ANY WARRANTY; without even the implied warranty of         *
0019  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the          *
0020  *  GNU General Public License for more details.                           *
0021  *                                                                         *
0022  *   You should have received a copy of the GNU General Public License     *
0023  *   along with this program; if not, write to the Free Software           *
0024  *   Foundation, Inc., 51 Franklin Street, Fifth Floor,                    *
0025  *   Boston, MA  02110-1301  USA                                           *
0026  *                                                                         *
0027  ***************************************************************************/
0028 #ifndef TRACE_H
0029 #define TRACE_H
0030 
0031 #include "backend/lib/macros.h"
0032 #include <chrono>
0033 
0034 class PerfTracer {
0035 public:
0036     explicit PerfTracer(const char* m) {
0037         msg = m;
0038         start = std::chrono::high_resolution_clock::now();
0039     };
0040     ~PerfTracer() {
0041         auto end = std::chrono::high_resolution_clock::now();
0042         auto diff = std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count();
0043         std::cout << msg << ": " << diff << " ms" << std::endl;
0044     }
0045 
0046 private:
0047     std::chrono::high_resolution_clock::time_point start;
0048     std::string msg;
0049 };
0050 
0051 #define PERFTRACE_ENABLED 1
0052 
0053 #define PERFTRACE_CURVES 1
0054 #define PERFTRACE_LIVE_IMPORT 1
0055 
0056 #ifdef PERFTRACE_ENABLED
0057 #define PERFTRACE(msg) PerfTracer tracer(msg)
0058 #else
0059 #define PERFTRACE(msg) DEBUG(msg)
0060 #endif
0061 
0062 
0063 #ifndef HAVE_WINDOWS
0064 
0065 #include <execinfo.h> //backtrace
0066 #include <dlfcn.h>    //dladdr
0067 #include <cxxabi.h>   //__cxa_demangle
0068 
0069 #include <cstdio>
0070 #include <cstdlib>
0071 #include <string>
0072 #include <sstream>
0073 
0074 /*!
0075  * this function prints the current call stack and helps to figure out why a certain (e.g. performance critical) function
0076  * is called multiple times and from where without involving the debugger.
0077  * To get the callstack, simple include \c print_callstack() in the function of interest.
0078  */
0079 static inline void print_callstack() {
0080     //get the current call stack
0081     const int max_frames_count = 10 + 1; //print the last 10 frames (+1 because of this function frame)
0082     void* callstack[max_frames_count];
0083     const int frames_count = backtrace(callstack, max_frames_count);
0084 
0085     //get the symbols
0086     char **symbols = backtrace_symbols(callstack, frames_count);
0087 
0088     std::ostringstream out;
0089     char buf[1024];
0090 
0091     // iterate over the frames, skip the first one (frame of this function call)
0092     for (int i = 1; i < frames_count; i++) {
0093         Dl_info info;
0094         if (dladdr(callstack[i], &info) && info.dli_sname) {
0095             char* demangled_name = nullptr;
0096             const char* name_to_print = nullptr;
0097             int status = -1;
0098             if (info.dli_sname[0] == '_')
0099                 demangled_name = abi::__cxa_demangle(info.dli_sname, nullptr, nullptr, &status);
0100 
0101             if (status == 0)
0102                 name_to_print = demangled_name;
0103             else {
0104                 if (info.dli_sname == nullptr)
0105                     name_to_print = symbols[i];
0106                 else
0107                     name_to_print = info.dli_sname;
0108             }
0109 
0110             snprintf(buf, sizeof(buf), "%-3d %*p %s + %zd\n",
0111                      i,
0112                      int(2 + sizeof(void*) * 2),
0113                      callstack[i],
0114                      name_to_print,
0115                      (char*)callstack[i] - (char*)info.dli_saddr);
0116 
0117             free(demangled_name);
0118         } else {
0119             snprintf(buf, sizeof(buf), "%-3d %*p %s\n",
0120                         i, int(2 + sizeof(void*) * 2), callstack[i], symbols[i]);
0121         }
0122         out << buf;
0123     }
0124     free(symbols);
0125 
0126     std::cout << "stack trace:\n" <<  out.str();
0127 }
0128 #endif //  #ifndef HAVE_WINDOWS
0129 
0130 #endif //TRACE_H