1 //===------- Debug.h - Target independent OpenMP target RTL -- C++ --------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // Routines used to provide debug messages and information from libomptarget
10 // and plugin RTLs to the user.
11 //
12 // Each plugin RTL and libomptarget define TARGET_NAME and DEBUG_PREFIX for use
13 // when sending messages to the user. These indicate which RTL sent the message
14 //
15 // Debug and information messages are controlled by the environment variables
16 // LIBOMPTARGET_DEBUG and LIBOMPTARGET_INFO which is set upon initialization
17 // of libomptarget or the plugin RTL.
18 //
19 // To printf a pointer in hex with a fixed width of 16 digits and a leading 0x,
20 // use printf("ptr=" DPxMOD "...\n", DPxPTR(ptr));
21 //
22 // DPxMOD expands to:
23 //   "0x%0*" PRIxPTR
24 // where PRIxPTR expands to an appropriate modifier for the type uintptr_t on a
25 // specific platform, e.g. "lu" if uintptr_t is typedef'd as unsigned long:
26 //   "0x%0*lu"
27 //
28 // Ultimately, the whole statement expands to:
29 //   printf("ptr=0x%0*lu...\n",  // the 0* modifier expects an extra argument
30 //                               // specifying the width of the output
31 //   (int)(2*sizeof(uintptr_t)), // the extra argument specifying the width
32 //                               // 8 digits for 32bit systems
33 //                               // 16 digits for 64bit
34 //   (uintptr_t) ptr);
35 //
36 //===----------------------------------------------------------------------===//
37 #ifndef _OMPTARGET_DEBUG_H
38 #define _OMPTARGET_DEBUG_H
39 
40 #include <atomic>
41 #include <mutex>
42 
43 /// 32-Bit field data attributes controlling information presented to the user.
44 enum OpenMPInfoType : uint32_t {
45   // Print data arguments and attributes upon entering an OpenMP device kernel.
46   OMP_INFOTYPE_KERNEL_ARGS = 0x0001,
47   // Indicate when an address already exists in the device mapping table.
48   OMP_INFOTYPE_MAPPING_EXISTS = 0x0002,
49   // Dump the contents of the device pointer map at kernel exit or failure.
50   OMP_INFOTYPE_DUMP_TABLE = 0x0004,
51   // Indicate when an address is added to the device mapping table.
52   OMP_INFOTYPE_MAPPING_CHANGED = 0x0008,
53   // Print kernel information from target device plugins.
54   OMP_INFOTYPE_PLUGIN_KERNEL = 0x0010,
55   // Print whenever data is transferred to the device
56   OMP_INFOTYPE_DATA_TRANSFER = 0x0020,
57   // Enable every flag.
58   OMP_INFOTYPE_ALL = 0xffffffff,
59 };
60 
61 #define GCC_VERSION                                                            \
62   (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__)
63 
64 #if !defined(__clang__) && defined(__GNUC__) && GCC_VERSION < 70100
65 #define USED __attribute__((used))
66 #else
67 #define USED
68 #endif
69 
70 // Add __attribute__((used)) to work around a bug in gcc 5/6.
getInfoLevelInternal()71 USED inline std::atomic<uint32_t> &getInfoLevelInternal() {
72   static std::atomic<uint32_t> InfoLevel;
73   static std::once_flag Flag{};
74   std::call_once(Flag, []() {
75     if (char *EnvStr = getenv("LIBOMPTARGET_INFO"))
76       InfoLevel.store(std::stoi(EnvStr));
77   });
78 
79   return InfoLevel;
80 }
81 
getInfoLevel()82 USED inline uint32_t getInfoLevel() { return getInfoLevelInternal().load(); }
83 
84 // Add __attribute__((used)) to work around a bug in gcc 5/6.
getDebugLevel()85 USED inline uint32_t getDebugLevel() {
86   static uint32_t DebugLevel = 0;
87   static std::once_flag Flag{};
88   std::call_once(Flag, []() {
89     if (char *EnvStr = getenv("LIBOMPTARGET_DEBUG"))
90       DebugLevel = std::stoi(EnvStr);
91   });
92 
93   return DebugLevel;
94 }
95 
96 #undef USED
97 #undef GCC_VERSION
98 
99 #ifndef __STDC_FORMAT_MACROS
100 #define __STDC_FORMAT_MACROS
101 #endif
102 #include <inttypes.h>
103 #undef __STDC_FORMAT_MACROS
104 
105 #define DPxMOD "0x%0*" PRIxPTR
106 #define DPxPTR(ptr) ((int)(2 * sizeof(uintptr_t))), ((uintptr_t)(ptr))
107 #define GETNAME2(name) #name
108 #define GETNAME(name) GETNAME2(name)
109 
110 /// Print a generic message string from libomptarget or a plugin RTL
111 #define MESSAGE0(_str)                                                         \
112   do {                                                                         \
113     fprintf(stderr, GETNAME(TARGET_NAME) " message: %s\n", _str);              \
114   } while (0)
115 
116 /// Print a printf formatting string message from libomptarget or a plugin RTL
117 #define MESSAGE(_str, ...)                                                     \
118   do {                                                                         \
119     fprintf(stderr, GETNAME(TARGET_NAME) " message: " _str "\n", __VA_ARGS__); \
120   } while (0)
121 
122 /// Print fatal error message with an error string and error identifier
123 #define FATAL_MESSAGE0(_num, _str)                                             \
124   do {                                                                         \
125     fprintf(stderr, GETNAME(TARGET_NAME) " fatal error %d: %s\n", _num, _str); \
126     abort();                                                                   \
127   } while (0)
128 
129 /// Print fatal error message with a printf string and error identifier
130 #define FATAL_MESSAGE(_num, _str, ...)                                         \
131   do {                                                                         \
132     fprintf(stderr, GETNAME(TARGET_NAME) " fatal error %d:" _str "\n", _num,   \
133             __VA_ARGS__);                                                      \
134     abort();                                                                   \
135   } while (0)
136 
137 /// Print a generic error string from libomptarget or a plugin RTL
138 #define FAILURE_MESSAGE(...)                                                   \
139   do {                                                                         \
140     fprintf(stderr, GETNAME(TARGET_NAME) " error: ");                          \
141     fprintf(stderr, __VA_ARGS__);                                              \
142   } while (0)
143 
144 /// Print a generic information string used if LIBOMPTARGET_INFO=1
145 #define INFO_MESSAGE(_num, ...)                                                \
146   do {                                                                         \
147     fprintf(stderr, GETNAME(TARGET_NAME) " device %d info: ", (int)_num);      \
148     fprintf(stderr, __VA_ARGS__);                                              \
149   } while (0)
150 
151 // Debugging messages
152 #ifdef OMPTARGET_DEBUG
153 #include <stdio.h>
154 
155 #define DEBUGP(prefix, ...)                                                    \
156   {                                                                            \
157     fprintf(stderr, "%s --> ", prefix);                                        \
158     fprintf(stderr, __VA_ARGS__);                                              \
159   }
160 
161 /// Emit a message for debugging
162 #define DP(...)                                                                \
163   do {                                                                         \
164     if (getDebugLevel() > 0) {                                                 \
165       DEBUGP(DEBUG_PREFIX, __VA_ARGS__);                                       \
166     }                                                                          \
167   } while (false)
168 
169 /// Emit a message for debugging or failure if debugging is disabled
170 #define REPORT(...)                                                            \
171   do {                                                                         \
172     if (getDebugLevel() > 0) {                                                 \
173       DP(__VA_ARGS__);                                                         \
174     } else {                                                                   \
175       FAILURE_MESSAGE(__VA_ARGS__);                                            \
176     }                                                                          \
177   } while (false)
178 #else
179 #define DEBUGP(prefix, ...)                                                    \
180   {}
181 #define DP(...)                                                                \
182   {}
183 #define REPORT(...) FAILURE_MESSAGE(__VA_ARGS__);
184 #endif // OMPTARGET_DEBUG
185 
186 /// Emit a message giving the user extra information about the runtime if
187 #define INFO(_flags, _id, ...)                                                 \
188   do {                                                                         \
189     if (getDebugLevel() > 0) {                                                 \
190       DEBUGP(DEBUG_PREFIX, __VA_ARGS__);                                       \
191     } else if (getInfoLevel() & _flags) {                                      \
192       INFO_MESSAGE(_id, __VA_ARGS__);                                          \
193     }                                                                          \
194   } while (false)
195 
196 #endif // _OMPTARGET_DEBUG_H
197