1 /*
2 Copyright (c) 2005-2022 Intel Corporation
3
4 Licensed under the Apache License, Version 2.0 (the "License");
5 you may not use this file except in compliance with the License.
6 You may obtain a copy of the License at
7
8 http://www.apache.org/licenses/LICENSE-2.0
9
10 Unless required by applicable law or agreed to in writing, software
11 distributed under the License is distributed on an "AS IS" BASIS,
12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 See the License for the specific language governing permissions and
14 limitations under the License.
15 */
16
17 #ifndef __TBB_test_common_utils_report_H
18 #define __TBB_test_common_utils_report_H
19
20 #include "config.h"
21
22 #include <mutex>
23 #include <cstdarg>
24
25 #if __SUNPRO_CC
26 #include <stdio.h>
27 #else
28 #include <cstdio>
29 #endif
30
31 #if defined(MAX_TRACE_SIZE) && MAX_TRACE_SIZE < 1024
32 #undef MAX_TRACE_SIZE
33 #endif
34 #ifndef MAX_TRACE_SIZE
35 #define MAX_TRACE_SIZE 1024
36 #endif
37
38
39 #if __GLIBC__>2 || ( __GLIBC__==2 && __GLIBC_MINOR__ >= 1) || __APPLE__
40 #include <execinfo.h> /*backtrace*/
41 #define BACKTRACE_FUNCTION_AVAILABLE 1
42 #endif
43
44 #if defined(_MSC_VER) && _MSC_VER >= 1300 || defined(__GNUC__) || defined(__GNUG__)
45 #define TRACE_ORIG_INFO __FILE__, __LINE__, __FUNCTION__
46 #else
47 #define TRACE_ORIG_INFO __FILE__, __LINE__, ""
48 #define __FUNCTION__ ""
49 #endif
50
51 #if defined(_WIN32) || defined(_WIN64)
52 #if (_WIN32_WINNT > 0x0501 && defined(_MSC_VER) && !defined(_M_ARM))
53 // Suppress "typedef ignored ... when no variable is declared" warning by vc14
54 #pragma warning (push)
55 #pragma warning (disable: 4091)
56 #ifndef NOMINMAX
57 #define NOMINMAX
58 #endif
59 #include <windows.h>
60 #include <dbghelp.h>
61 #pragma warning (pop)
62 #pragma comment (lib, "dbghelp.lib")
63 #endif
64 #endif
65
66 //! printf style tracing macro without automatic new line character adding
67 #define TRACENL utils::internal::tracer.set_trace_info(0, TRACE_ORIG_INFO)->trace
68
69 //! printf style reporting macro
70 /** On heterogeneous platforms redirects its output to the host side. **/
71 #define REPORT TRACENL
72
73 namespace utils {
74 namespace internal {
75
76 #ifndef TBBReporter
77 struct TBBReporter {
ReportTBBReporter78 void Report ( const char* msg ) {
79 printf( "%s", msg );
80 fflush(stdout);
81 #ifdef _WINDOWS_
82 OutputDebugStringA(msg);
83 #endif
84 }
85 };
86 #endif
87
88 class Tracer {
89 int m_flags;
90 const char *m_file;
91 const char *m_func;
92 std::size_t m_line;
93
94 TBBReporter m_reporter;
95
96 public:
97 enum {
98 prefix = 1,
99 need_lf = 2
100 };
101
Tracer()102 Tracer(): m_flags(0), m_file(nullptr), m_func(nullptr), m_line(0) {}
103
set_trace_info(int flags,const char * file,std::size_t line,const char * func)104 Tracer* set_trace_info( int flags, const char *file, std::size_t line, const char *func ) {
105 m_flags = flags;
106 m_line = line;
107 m_file = file;
108 m_func = func;
109 return this;
110 }
111
trace(const char * fmt,...)112 void trace( const char* fmt, ... ) {
113 char msg[MAX_TRACE_SIZE];
114 char msg_fmt_buf[MAX_TRACE_SIZE];
115 const char *msg_fmt = fmt;
116 if (m_flags & prefix) {
117 snprintf (msg_fmt_buf, MAX_TRACE_SIZE, "[%s] %s", m_func, fmt);
118 msg_fmt = msg_fmt_buf;
119 }
120 std::va_list argptr;
121 va_start(argptr, fmt);
122 int len = vsnprintf(msg, MAX_TRACE_SIZE, msg_fmt, argptr);
123 va_end(argptr);
124 if (m_flags & need_lf && len < MAX_TRACE_SIZE - 1 && msg_fmt[len-1] != '\n') {
125 msg[len] = '\n';
126 msg[len + 1] = 0;
127 }
128 m_reporter.Report(msg);
129 }
130 }; // class Tracer
131
132 static Tracer tracer;
133
134 template<int>
not_the_first_call()135 bool not_the_first_call () {
136 static bool first_call = false;
137 bool res = first_call;
138 first_call = true;
139 return res;
140 }
141
142 } // internal
143
print_call_stack()144 inline void print_call_stack() {
145 static std::mutex mutex;
146 std::lock_guard<std::mutex> lock(mutex);
147
148 fflush(stdout); fflush(stderr);
149 #if BACKTRACE_FUNCTION_AVAILABLE
150 const int sz = 100; // max number of frames to capture
151 void *buff[sz];
152 int n = backtrace(buff, sz);
153 REPORT("Call stack info (%d):\n", n);
154 backtrace_symbols_fd(buff, n, fileno(stdout));
155 #elif __SUNPRO_CC
156 REPORT("Call stack info:\n");
157 printstack(fileno(stdout));
158 #elif _WIN32_WINNT > 0x0501 && _MSC_VER>=1500 && !__TBB_WIN8UI_SUPPORT && !defined(WINAPI_FAMILY)
159 const int sz = 62; // XP limitation for number of frames
160 void *buff[sz];
161 int n = CaptureStackBackTrace(0, sz, buff, nullptr);
162 REPORT("Call stack info (%d):\n", n);
163 static LONG once = 0;
164 if( !InterlockedExchange(&once, 1) )
165 SymInitialize(GetCurrentProcess(), nullptr, TRUE);
166 const int len = 255; // just some reasonable string buffer size
167 union { SYMBOL_INFO sym; char pad[sizeof(SYMBOL_INFO)+len]; };
168 sym.MaxNameLen = len;
169 sym.SizeOfStruct = sizeof( SYMBOL_INFO );
170 DWORD64 offset;
171 for(int i = 1; i < n; i++) { // skip current frame
172 if(!SymFromAddr( GetCurrentProcess(), DWORD64(buff[i]), &offset, &sym )) {
173 sym.Address = ULONG64(buff[i]); offset = 0; sym.Name[0] = 0;
174 }
175 REPORT("[%d] %016I64X+%04I64X: %s\n", i, sym.Address, offset, sym.Name);
176 }
177 #endif
178 }
179
180 } // util
181
182 #endif // __TBB_test_common_utils_report_H
183