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. 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 82 USED inline uint32_t getInfoLevel() { return getInfoLevelInternal().load(); } 83 84 // Add __attribute__((used)) to work around a bug in gcc 5/6. 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