xref: /oneTBB/test/common/utils_report.h (revision 68e075cb)
1 /*
2     Copyright (c) 2005-2021 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         #include <dbghelp.h>
57         #pragma warning (pop)
58         #pragma comment (lib, "dbghelp.lib")
59     #endif
60 #endif
61 
62 //! printf style tracing macro without automatic new line character adding
63 #define TRACENL utils::internal::tracer.set_trace_info(0, TRACE_ORIG_INFO)->trace
64 
65 //! printf style reporting macro
66 /** On heterogeneous platforms redirects its output to the host side. **/
67 #define REPORT TRACENL
68 
69 namespace utils {
70 namespace internal {
71 
72 #ifndef TBBReporter
73 struct TBBReporter {
74     void Report ( const char* msg ) {
75         printf( "%s", msg );
76         fflush(stdout);
77 #ifdef _WINDOWS_
78         OutputDebugStringA(msg);
79 #endif
80     }
81 };
82 #endif
83 
84 class Tracer {
85     int m_flags;
86     const char *m_file;
87     const char *m_func;
88     std::size_t m_line;
89 
90     TBBReporter m_reporter;
91 
92 public:
93     enum {
94         prefix = 1,
95         need_lf = 2
96     };
97 
98     Tracer(): m_flags(0), m_file(nullptr), m_func(nullptr), m_line(0) {}
99 
100     Tracer* set_trace_info( int flags, const char *file, std::size_t line, const char *func ) {
101         m_flags = flags;
102         m_line = line;
103         m_file = file;
104         m_func = func;
105         return  this;
106     }
107 
108     void trace( const char* fmt, ... ) {
109         char msg[MAX_TRACE_SIZE];
110         char msg_fmt_buf[MAX_TRACE_SIZE];
111         const char  *msg_fmt = fmt;
112         if (m_flags & prefix) {
113             snprintf (msg_fmt_buf, MAX_TRACE_SIZE, "[%s] %s", m_func, fmt);
114             msg_fmt = msg_fmt_buf;
115         }
116         std::va_list argptr;
117         va_start(argptr, fmt);
118         int len = vsnprintf(msg, MAX_TRACE_SIZE, msg_fmt, argptr);
119         va_end(argptr);
120         if (m_flags & need_lf && len < MAX_TRACE_SIZE - 1  &&  msg_fmt[len-1] != '\n') {
121             msg[len] = '\n';
122             msg[len + 1] = 0;
123         }
124         m_reporter.Report(msg);
125     }
126 }; // class Tracer
127 
128 static Tracer tracer;
129 
130 template<int>
131 bool not_the_first_call () {
132     static bool first_call = false;
133     bool res = first_call;
134     first_call = true;
135     return res;
136 }
137 
138 } // internal
139 
140 inline void print_call_stack() {
141     static std::mutex mutex;
142     std::lock_guard<std::mutex> lock(mutex);
143 
144     fflush(stdout); fflush(stderr);
145     #if BACKTRACE_FUNCTION_AVAILABLE
146         const int sz = 100; // max number of frames to capture
147         void *buff[sz];
148         int n = backtrace(buff, sz);
149         REPORT("Call stack info (%d):\n", n);
150         backtrace_symbols_fd(buff, n, fileno(stdout));
151     #elif __SUNPRO_CC
152         REPORT("Call stack info:\n");
153         printstack(fileno(stdout));
154     #elif _WIN32_WINNT > 0x0501 && _MSC_VER>=1500 && !__TBB_WIN8UI_SUPPORT && !defined(WINAPI_FAMILY)
155         const int sz = 62; // XP limitation for number of frames
156         void *buff[sz];
157         int n = CaptureStackBackTrace(0, sz, buff, NULL);
158         REPORT("Call stack info (%d):\n", n);
159         static LONG once = 0;
160         if( !InterlockedExchange(&once, 1) )
161             SymInitialize(GetCurrentProcess(), NULL, TRUE);
162         const int len = 255; // just some reasonable string buffer size
163         union { SYMBOL_INFO sym; char pad[sizeof(SYMBOL_INFO)+len]; };
164         sym.MaxNameLen = len;
165         sym.SizeOfStruct = sizeof( SYMBOL_INFO );
166         DWORD64 offset;
167         for(int i = 1; i < n; i++) { // skip current frame
168             if(!SymFromAddr( GetCurrentProcess(), DWORD64(buff[i]), &offset, &sym )) {
169                 sym.Address = ULONG64(buff[i]); offset = 0; sym.Name[0] = 0;
170             }
171             REPORT("[%d] %016I64X+%04I64X: %s\n", i, sym.Address, offset, sym.Name);
172         }
173     #endif
174 }
175 
176 } // util
177 
178 #endif // __TBB_test_common_utils_report_H
179