xref: /oneTBB/test/common/utils_report.h (revision c21e688a)
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