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