xref: /llvm-project/offload/plugins-nextgen/common/include/ErrorReporting.h (revision 3b7611594f010ecd5233ab9580b2feb88837f9ef)
1c95abe94SJohannes Doerfert //===- ErrorReporting.h - Helper to provide nice error messages ----- c++ -===//
2c95abe94SJohannes Doerfert //
3c95abe94SJohannes Doerfert // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4c95abe94SJohannes Doerfert // See https://llvm.org/LICENSE.txt for license information.
5c95abe94SJohannes Doerfert // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6c95abe94SJohannes Doerfert //
7c95abe94SJohannes Doerfert //===----------------------------------------------------------------------===//
8c95abe94SJohannes Doerfert //
9c95abe94SJohannes Doerfert //===----------------------------------------------------------------------===//
10c95abe94SJohannes Doerfert 
11c95abe94SJohannes Doerfert #ifndef OFFLOAD_PLUGINS_NEXTGEN_COMMON_ERROR_REPORTING_H
12c95abe94SJohannes Doerfert #define OFFLOAD_PLUGINS_NEXTGEN_COMMON_ERROR_REPORTING_H
13c95abe94SJohannes Doerfert 
14c95abe94SJohannes Doerfert #include "PluginInterface.h"
15c95abe94SJohannes Doerfert #include "Shared/EnvironmentVar.h"
16c95abe94SJohannes Doerfert 
179a101322SJohannes Doerfert #include "llvm/ADT/STLExtras.h"
18c95abe94SJohannes Doerfert #include "llvm/ADT/SmallString.h"
19c95abe94SJohannes Doerfert #include "llvm/ADT/StringRef.h"
20f3bfc563SJohannes Doerfert #include "llvm/Frontend/OpenMP/OMP.h"
21c95abe94SJohannes Doerfert #include "llvm/Support/ErrorHandling.h"
22c95abe94SJohannes Doerfert #include "llvm/Support/WithColor.h"
23c95abe94SJohannes Doerfert #include "llvm/Support/raw_ostream.h"
24c95abe94SJohannes Doerfert 
25c95abe94SJohannes Doerfert #include <cstdint>
26c95abe94SJohannes Doerfert #include <cstdio>
27c95abe94SJohannes Doerfert #include <cstdlib>
28c95abe94SJohannes Doerfert #include <functional>
29c95abe94SJohannes Doerfert #include <optional>
30c95abe94SJohannes Doerfert #include <string>
31c95abe94SJohannes Doerfert #include <unistd.h>
32c95abe94SJohannes Doerfert 
33c95abe94SJohannes Doerfert namespace llvm {
34c95abe94SJohannes Doerfert namespace omp {
35c95abe94SJohannes Doerfert namespace target {
36c95abe94SJohannes Doerfert namespace plugin {
37c95abe94SJohannes Doerfert 
38c95abe94SJohannes Doerfert class ErrorReporter {
39c95abe94SJohannes Doerfert 
40c95abe94SJohannes Doerfert   enum ColorTy {
41c95abe94SJohannes Doerfert     Yellow = int(HighlightColor::Address),
42c95abe94SJohannes Doerfert     Green = int(HighlightColor::String),
43c95abe94SJohannes Doerfert     DarkBlue = int(HighlightColor::Tag),
44c95abe94SJohannes Doerfert     Cyan = int(HighlightColor::Attribute),
45c95abe94SJohannes Doerfert     DarkPurple = int(HighlightColor::Enumerator),
46c95abe94SJohannes Doerfert     DarkRed = int(HighlightColor::Macro),
47c95abe94SJohannes Doerfert     BoldRed = int(HighlightColor::Error),
48c95abe94SJohannes Doerfert     BoldLightPurple = int(HighlightColor::Warning),
49c95abe94SJohannes Doerfert     BoldDarkGrey = int(HighlightColor::Note),
50c95abe94SJohannes Doerfert     BoldLightBlue = int(HighlightColor::Remark),
51c95abe94SJohannes Doerfert   };
52c95abe94SJohannes Doerfert 
53c95abe94SJohannes Doerfert   /// The banner printed at the beginning of an error report.
54c95abe94SJohannes Doerfert   static constexpr auto ErrorBanner = "OFFLOAD ERROR: ";
55c95abe94SJohannes Doerfert 
56c95abe94SJohannes Doerfert   /// Return the device id as string, or n/a if not available.
57c95abe94SJohannes Doerfert   static std::string getDeviceIdStr(GenericDeviceTy *Device) {
58c95abe94SJohannes Doerfert     return Device ? std::to_string(Device->getDeviceId()) : "n/a";
59c95abe94SJohannes Doerfert   }
60c95abe94SJohannes Doerfert 
61c95abe94SJohannes Doerfert   /// Return a nice name for an TargetAllocTy.
62c95abe94SJohannes Doerfert   static StringRef getAllocTyName(TargetAllocTy Kind) {
63c95abe94SJohannes Doerfert     switch (Kind) {
64c95abe94SJohannes Doerfert     case TARGET_ALLOC_DEVICE_NON_BLOCKING:
65c95abe94SJohannes Doerfert     case TARGET_ALLOC_DEFAULT:
66c95abe94SJohannes Doerfert     case TARGET_ALLOC_DEVICE:
67c95abe94SJohannes Doerfert       return "device memory";
68c95abe94SJohannes Doerfert     case TARGET_ALLOC_HOST:
69c95abe94SJohannes Doerfert       return "pinned host memory";
70c95abe94SJohannes Doerfert     case TARGET_ALLOC_SHARED:
71c95abe94SJohannes Doerfert       return "managed memory";
72c95abe94SJohannes Doerfert       break;
73c95abe94SJohannes Doerfert     }
74c95abe94SJohannes Doerfert     llvm_unreachable("Unknown target alloc kind");
75c95abe94SJohannes Doerfert   }
76c95abe94SJohannes Doerfert 
77c95abe94SJohannes Doerfert #pragma clang diagnostic push
78c95abe94SJohannes Doerfert #pragma clang diagnostic ignored "-Wgcc-compat"
79c95abe94SJohannes Doerfert #pragma clang diagnostic ignored "-Wformat-security"
80c95abe94SJohannes Doerfert   /// Print \p Format, instantiated with \p Args to stderr.
81c95abe94SJohannes Doerfert   /// TODO: Allow redirection into a file stream.
82c95abe94SJohannes Doerfert   template <typename... ArgsTy>
83c95abe94SJohannes Doerfert   [[gnu::format(__printf__, 1, 2)]] static void print(const char *Format,
84c95abe94SJohannes Doerfert                                                       ArgsTy &&...Args) {
85c95abe94SJohannes Doerfert     raw_fd_ostream OS(STDERR_FILENO, false);
86c95abe94SJohannes Doerfert     OS << llvm::format(Format, Args...);
87c95abe94SJohannes Doerfert   }
88c95abe94SJohannes Doerfert 
89c95abe94SJohannes Doerfert   /// Print \p Format, instantiated with \p Args to stderr, but colored.
90c95abe94SJohannes Doerfert   /// TODO: Allow redirection into a file stream.
91c95abe94SJohannes Doerfert   template <typename... ArgsTy>
92c95abe94SJohannes Doerfert   [[gnu::format(__printf__, 2, 3)]] static void
93c95abe94SJohannes Doerfert   print(ColorTy Color, const char *Format, ArgsTy &&...Args) {
94c95abe94SJohannes Doerfert     raw_fd_ostream OS(STDERR_FILENO, false);
95c95abe94SJohannes Doerfert     WithColor(OS, HighlightColor(Color)) << llvm::format(Format, Args...);
96c95abe94SJohannes Doerfert   }
97c95abe94SJohannes Doerfert 
98c95abe94SJohannes Doerfert   /// Print \p Format, instantiated with \p Args to stderr, but colored and with
99c95abe94SJohannes Doerfert   /// a banner.
100c95abe94SJohannes Doerfert   /// TODO: Allow redirection into a file stream.
101c95abe94SJohannes Doerfert   template <typename... ArgsTy>
102c95abe94SJohannes Doerfert   [[gnu::format(__printf__, 1, 2)]] static void reportError(const char *Format,
103c95abe94SJohannes Doerfert                                                             ArgsTy &&...Args) {
104c95abe94SJohannes Doerfert     print(BoldRed, "%s", ErrorBanner);
105c95abe94SJohannes Doerfert     print(BoldRed, Format, Args...);
106c95abe94SJohannes Doerfert     print("\n");
107c95abe94SJohannes Doerfert   }
108c95abe94SJohannes Doerfert #pragma clang diagnostic pop
109c95abe94SJohannes Doerfert 
110c95abe94SJohannes Doerfert   static void reportError(const char *Str) { reportError("%s", Str); }
111c95abe94SJohannes Doerfert   static void print(const char *Str) { print("%s", Str); }
112c95abe94SJohannes Doerfert   static void print(StringRef Str) { print("%s", Str.str().c_str()); }
113c95abe94SJohannes Doerfert   static void print(ColorTy Color, const char *Str) { print(Color, "%s", Str); }
114c95abe94SJohannes Doerfert   static void print(ColorTy Color, StringRef Str) {
115c95abe94SJohannes Doerfert     print(Color, "%s", Str.str().c_str());
116c95abe94SJohannes Doerfert   }
117c95abe94SJohannes Doerfert 
118c95abe94SJohannes Doerfert   /// Pretty print a stack trace.
119c95abe94SJohannes Doerfert   static void reportStackTrace(StringRef StackTrace) {
120c95abe94SJohannes Doerfert     if (StackTrace.empty())
121c95abe94SJohannes Doerfert       return;
122c95abe94SJohannes Doerfert 
123c95abe94SJohannes Doerfert     SmallVector<StringRef> Lines, Parts;
124c95abe94SJohannes Doerfert     StackTrace.split(Lines, "\n", /*MaxSplit=*/-1, /*KeepEmpty=*/false);
125c95abe94SJohannes Doerfert     int Start = Lines.empty() || !Lines[0].contains("PrintStackTrace") ? 0 : 1;
126c95abe94SJohannes Doerfert     unsigned NumDigits =
127c95abe94SJohannes Doerfert         (int)(floor(log10(Lines.size() - Start - /*0*/ 1)) + 1);
128c95abe94SJohannes Doerfert     for (int I = Start, E = Lines.size(); I < E; ++I) {
129c95abe94SJohannes Doerfert       auto Line = Lines[I];
130c95abe94SJohannes Doerfert       Parts.clear();
131c95abe94SJohannes Doerfert       Line = Line.drop_while([](char C) { return std::isspace(C); });
132c95abe94SJohannes Doerfert       Line.split(Parts, " ", /*MaxSplit=*/2);
133c95abe94SJohannes Doerfert       if (Parts.size() != 3 || Parts[0].size() < 2 || Parts[0][0] != '#') {
134c95abe94SJohannes Doerfert         print("%s\n", Line.str().c_str());
135c95abe94SJohannes Doerfert         continue;
136c95abe94SJohannes Doerfert       }
137c95abe94SJohannes Doerfert       unsigned FrameIdx = std::stoi(Parts[0].drop_front(1).str());
138c95abe94SJohannes Doerfert       if (Start)
139c95abe94SJohannes Doerfert         FrameIdx -= 1;
140c95abe94SJohannes Doerfert       print(DarkPurple, "    %s", Parts[0].take_front().str().c_str());
141c95abe94SJohannes Doerfert       print(Green, "%*u", NumDigits, FrameIdx);
142c95abe94SJohannes Doerfert       print(BoldLightBlue, " %s", Parts[1].str().c_str());
143c95abe94SJohannes Doerfert       print(" %s\n", Parts[2].str().c_str());
144c95abe94SJohannes Doerfert     }
145c95abe94SJohannes Doerfert     print("\n");
146c95abe94SJohannes Doerfert   }
147c95abe94SJohannes Doerfert 
148c95abe94SJohannes Doerfert   /// Report information about an allocation associated with \p ATI.
149c95abe94SJohannes Doerfert   static void reportAllocationInfo(AllocationTraceInfoTy *ATI) {
150c95abe94SJohannes Doerfert     if (!ATI)
151c95abe94SJohannes Doerfert       return;
152c95abe94SJohannes Doerfert 
153c95abe94SJohannes Doerfert     if (!ATI->DeallocationTrace.empty()) {
154c95abe94SJohannes Doerfert       print(BoldLightPurple, "Last deallocation:\n");
155c95abe94SJohannes Doerfert       reportStackTrace(ATI->DeallocationTrace);
156c95abe94SJohannes Doerfert     }
157c95abe94SJohannes Doerfert 
158c95abe94SJohannes Doerfert     if (ATI->HostPtr)
159c95abe94SJohannes Doerfert       print(BoldLightPurple,
160*3b761159SJohannes Doerfert             "Last allocation of size %lu for host pointer %p -> device pointer "
161*3b761159SJohannes Doerfert             "%p:\n",
162*3b761159SJohannes Doerfert             ATI->Size, ATI->HostPtr, ATI->DevicePtr);
163c95abe94SJohannes Doerfert     else
164*3b761159SJohannes Doerfert       print(BoldLightPurple,
165*3b761159SJohannes Doerfert             "Last allocation of size %lu -> device pointer %p:\n", ATI->Size,
166*3b761159SJohannes Doerfert             ATI->DevicePtr);
167c95abe94SJohannes Doerfert     reportStackTrace(ATI->AllocationTrace);
168c95abe94SJohannes Doerfert     if (!ATI->LastAllocationInfo)
169c95abe94SJohannes Doerfert       return;
170c95abe94SJohannes Doerfert 
171c95abe94SJohannes Doerfert     unsigned I = 0;
172c95abe94SJohannes Doerfert     print(BoldLightPurple, "Prior allocations with the same base pointer:");
173c95abe94SJohannes Doerfert     while (ATI->LastAllocationInfo) {
174c95abe94SJohannes Doerfert       print("\n");
175c95abe94SJohannes Doerfert       ATI = ATI->LastAllocationInfo;
176c95abe94SJohannes Doerfert       print(BoldLightPurple, " #%u Prior deallocation of size %lu:\n", I,
177c95abe94SJohannes Doerfert             ATI->Size);
178c95abe94SJohannes Doerfert       reportStackTrace(ATI->DeallocationTrace);
179c95abe94SJohannes Doerfert       if (ATI->HostPtr)
180*3b761159SJohannes Doerfert         print(
181*3b761159SJohannes Doerfert             BoldLightPurple,
182*3b761159SJohannes Doerfert             " #%u Prior allocation for host pointer %p -> device pointer %p:\n",
183*3b761159SJohannes Doerfert             I, ATI->HostPtr, ATI->DevicePtr);
184c95abe94SJohannes Doerfert       else
185*3b761159SJohannes Doerfert         print(BoldLightPurple, " #%u Prior allocation -> device pointer %p:\n",
186*3b761159SJohannes Doerfert               I, ATI->DevicePtr);
187c95abe94SJohannes Doerfert       reportStackTrace(ATI->AllocationTrace);
188c95abe94SJohannes Doerfert       ++I;
189c95abe94SJohannes Doerfert     }
190c95abe94SJohannes Doerfert   }
191c95abe94SJohannes Doerfert 
192c95abe94SJohannes Doerfert   /// End the execution of the program.
193c95abe94SJohannes Doerfert   static void abortExecution() { abort(); }
194c95abe94SJohannes Doerfert 
195c95abe94SJohannes Doerfert public:
196c95abe94SJohannes Doerfert #define DEALLOCATION_ERROR(Format, ...)                                        \
197c95abe94SJohannes Doerfert   reportError(Format, __VA_ARGS__);                                            \
198c95abe94SJohannes Doerfert   reportStackTrace(StackTrace);                                                \
199c95abe94SJohannes Doerfert   reportAllocationInfo(ATI);                                                   \
200c95abe94SJohannes Doerfert   abortExecution();
201c95abe94SJohannes Doerfert 
202c95abe94SJohannes Doerfert   static void reportDeallocationOfNonAllocatedPtr(void *DevicePtr,
203c95abe94SJohannes Doerfert                                                   TargetAllocTy Kind,
204c95abe94SJohannes Doerfert                                                   AllocationTraceInfoTy *ATI,
205c95abe94SJohannes Doerfert                                                   std::string &StackTrace) {
206c95abe94SJohannes Doerfert     DEALLOCATION_ERROR("deallocation of non-allocated %s: %p",
207c95abe94SJohannes Doerfert                        getAllocTyName(Kind).data(), DevicePtr);
208c95abe94SJohannes Doerfert   }
209c95abe94SJohannes Doerfert 
210c95abe94SJohannes Doerfert   static void reportDeallocationOfDeallocatedPtr(void *DevicePtr,
211c95abe94SJohannes Doerfert                                                  TargetAllocTy Kind,
212c95abe94SJohannes Doerfert                                                  AllocationTraceInfoTy *ATI,
213c95abe94SJohannes Doerfert                                                  std::string &StackTrace) {
214c95abe94SJohannes Doerfert     DEALLOCATION_ERROR("double-free of %s: %p", getAllocTyName(Kind).data(),
215c95abe94SJohannes Doerfert                        DevicePtr);
216c95abe94SJohannes Doerfert   }
217c95abe94SJohannes Doerfert 
218c95abe94SJohannes Doerfert   static void reportDeallocationOfWrongPtrKind(void *DevicePtr,
219c95abe94SJohannes Doerfert                                                TargetAllocTy Kind,
220c95abe94SJohannes Doerfert                                                AllocationTraceInfoTy *ATI,
221c95abe94SJohannes Doerfert                                                std::string &StackTrace) {
222c95abe94SJohannes Doerfert     DEALLOCATION_ERROR("deallocation requires %s but allocation was %s: %p",
223c95abe94SJohannes Doerfert                        getAllocTyName(Kind).data(),
224c95abe94SJohannes Doerfert                        getAllocTyName(ATI->Kind).data(), DevicePtr);
225c95abe94SJohannes Doerfert #undef DEALLOCATION_ERROR
226c95abe94SJohannes Doerfert   }
2279a101322SJohannes Doerfert 
228*3b761159SJohannes Doerfert   static void reportMemoryAccessError(GenericDeviceTy &Device, void *DevicePtr,
229*3b761159SJohannes Doerfert                                       std::string &ErrorStr, bool Abort) {
230*3b761159SJohannes Doerfert     reportError(ErrorStr.c_str());
231*3b761159SJohannes Doerfert 
232*3b761159SJohannes Doerfert     if (!Device.OMPX_TrackAllocationTraces) {
233*3b761159SJohannes Doerfert       print(Yellow, "Use '%s=true' to track device allocations\n",
234*3b761159SJohannes Doerfert             Device.OMPX_TrackAllocationTraces.getName().data());
235*3b761159SJohannes Doerfert       if (Abort)
236*3b761159SJohannes Doerfert         abortExecution();
237*3b761159SJohannes Doerfert       return;
238*3b761159SJohannes Doerfert     }
239*3b761159SJohannes Doerfert     uintptr_t Distance = false;
240*3b761159SJohannes Doerfert     auto *ATI =
241*3b761159SJohannes Doerfert         Device.getClosestAllocationTraceInfoForAddr(DevicePtr, Distance);
242*3b761159SJohannes Doerfert     if (!ATI) {
243*3b761159SJohannes Doerfert       print(Cyan,
244*3b761159SJohannes Doerfert             "No host-issued allocations; device pointer %p might be "
245*3b761159SJohannes Doerfert             "a global, stack, or shared location\n",
246*3b761159SJohannes Doerfert             DevicePtr);
247*3b761159SJohannes Doerfert       if (Abort)
248*3b761159SJohannes Doerfert         abortExecution();
249*3b761159SJohannes Doerfert       return;
250*3b761159SJohannes Doerfert     }
251*3b761159SJohannes Doerfert     if (!Distance) {
252*3b761159SJohannes Doerfert       print(Cyan, "Device pointer %p points into%s host-issued allocation:\n",
253*3b761159SJohannes Doerfert             DevicePtr, ATI->DeallocationTrace.empty() ? "" : " prior");
254*3b761159SJohannes Doerfert       reportAllocationInfo(ATI);
255*3b761159SJohannes Doerfert       if (Abort)
256*3b761159SJohannes Doerfert         abortExecution();
257*3b761159SJohannes Doerfert       return;
258*3b761159SJohannes Doerfert     }
259*3b761159SJohannes Doerfert 
260*3b761159SJohannes Doerfert     bool IsClose = Distance < (1L << 29L /*512MB=*/);
261*3b761159SJohannes Doerfert     print(Cyan,
262*3b761159SJohannes Doerfert           "Device pointer %p does not point into any (current or prior) "
263*3b761159SJohannes Doerfert           "host-issued allocation%s.\n",
264*3b761159SJohannes Doerfert           DevicePtr,
265*3b761159SJohannes Doerfert           IsClose ? "" : " (might be a global, stack, or shared location)");
266*3b761159SJohannes Doerfert     if (IsClose) {
267*3b761159SJohannes Doerfert       print(Cyan,
268*3b761159SJohannes Doerfert             "Closest host-issued allocation (distance %" PRIuPTR
269*3b761159SJohannes Doerfert             " byte%s; might be by page):\n",
270*3b761159SJohannes Doerfert             Distance, Distance > 1 ? "s" : "");
271*3b761159SJohannes Doerfert       reportAllocationInfo(ATI);
272*3b761159SJohannes Doerfert     }
273*3b761159SJohannes Doerfert     if (Abort)
274*3b761159SJohannes Doerfert       abortExecution();
275*3b761159SJohannes Doerfert   }
276*3b761159SJohannes Doerfert 
2779a101322SJohannes Doerfert   /// Report that a kernel encountered a trap instruction.
2789a101322SJohannes Doerfert   static void reportTrapInKernel(
2799a101322SJohannes Doerfert       GenericDeviceTy &Device, KernelTraceInfoRecordTy &KTIR,
2809a101322SJohannes Doerfert       std::function<bool(__tgt_async_info &)> AsyncInfoWrapperMatcher) {
2819a101322SJohannes Doerfert     assert(AsyncInfoWrapperMatcher && "A matcher is required");
2829a101322SJohannes Doerfert 
2839a101322SJohannes Doerfert     uint32_t Idx = 0;
2849a101322SJohannes Doerfert     for (uint32_t I = 0, E = KTIR.size(); I < E; ++I) {
2859a101322SJohannes Doerfert       auto KTI = KTIR.getKernelTraceInfo(I);
2869a101322SJohannes Doerfert       if (KTI.Kernel == nullptr)
2879a101322SJohannes Doerfert         break;
2889a101322SJohannes Doerfert       // Skip kernels issued in other queues.
2899a101322SJohannes Doerfert       if (KTI.AsyncInfo && !(AsyncInfoWrapperMatcher(*KTI.AsyncInfo)))
2909a101322SJohannes Doerfert         continue;
2919a101322SJohannes Doerfert       Idx = I;
2929a101322SJohannes Doerfert       break;
2939a101322SJohannes Doerfert     }
2949a101322SJohannes Doerfert 
2959a101322SJohannes Doerfert     auto KTI = KTIR.getKernelTraceInfo(Idx);
296f3bfc563SJohannes Doerfert     if (KTI.AsyncInfo && (AsyncInfoWrapperMatcher(*KTI.AsyncInfo))) {
297f3bfc563SJohannes Doerfert       auto PrettyKernelName =
298f3bfc563SJohannes Doerfert           llvm::omp::prettifyFunctionName(KTI.Kernel->getName());
299f3bfc563SJohannes Doerfert       reportError("Kernel '%s'", PrettyKernelName.c_str());
300f3bfc563SJohannes Doerfert     }
3019a101322SJohannes Doerfert     reportError("execution interrupted by hardware trap instruction");
3029a101322SJohannes Doerfert     if (KTI.AsyncInfo && (AsyncInfoWrapperMatcher(*KTI.AsyncInfo))) {
3039a101322SJohannes Doerfert       if (!KTI.LaunchTrace.empty())
3049a101322SJohannes Doerfert         reportStackTrace(KTI.LaunchTrace);
3059a101322SJohannes Doerfert       else
3069a101322SJohannes Doerfert         print(Yellow, "Use '%s=1' to show the stack trace of the kernel\n",
3079a101322SJohannes Doerfert               Device.OMPX_TrackNumKernelLaunches.getName().data());
3089a101322SJohannes Doerfert     }
3099a101322SJohannes Doerfert     abort();
3109a101322SJohannes Doerfert   }
3119a101322SJohannes Doerfert 
3129a101322SJohannes Doerfert   /// Report the kernel traces taken from \p KTIR, up to
3139a101322SJohannes Doerfert   /// OFFLOAD_TRACK_NUM_KERNEL_LAUNCH_TRACES many.
3149a101322SJohannes Doerfert   static void reportKernelTraces(GenericDeviceTy &Device,
3159a101322SJohannes Doerfert                                  KernelTraceInfoRecordTy &KTIR) {
3169a101322SJohannes Doerfert     uint32_t NumKTIs = 0;
3179a101322SJohannes Doerfert     for (uint32_t I = 0, E = KTIR.size(); I < E; ++I) {
3189a101322SJohannes Doerfert       auto KTI = KTIR.getKernelTraceInfo(I);
3199a101322SJohannes Doerfert       if (KTI.Kernel == nullptr)
3209a101322SJohannes Doerfert         break;
3219a101322SJohannes Doerfert       ++NumKTIs;
3229a101322SJohannes Doerfert     }
3239a101322SJohannes Doerfert     if (NumKTIs == 0) {
3249a101322SJohannes Doerfert       print(BoldRed, "No kernel launches known\n");
3259a101322SJohannes Doerfert       return;
3269a101322SJohannes Doerfert     }
3279a101322SJohannes Doerfert 
3289a101322SJohannes Doerfert     uint32_t TracesToShow =
3299a101322SJohannes Doerfert         std::min(Device.OMPX_TrackNumKernelLaunches.get(), NumKTIs);
3309a101322SJohannes Doerfert     if (TracesToShow == 0) {
3319a101322SJohannes Doerfert       if (NumKTIs == 1)
3329a101322SJohannes Doerfert         print(BoldLightPurple, "Display only launched kernel:\n");
3339a101322SJohannes Doerfert       else
3349a101322SJohannes Doerfert         print(BoldLightPurple, "Display last %u kernels launched:\n", NumKTIs);
3359a101322SJohannes Doerfert     } else {
3369a101322SJohannes Doerfert       if (NumKTIs == 1)
3379a101322SJohannes Doerfert         print(BoldLightPurple, "Display kernel launch trace:\n");
3389a101322SJohannes Doerfert       else
3399a101322SJohannes Doerfert         print(BoldLightPurple,
3409a101322SJohannes Doerfert               "Display %u of the %u last kernel launch traces:\n", TracesToShow,
3419a101322SJohannes Doerfert               NumKTIs);
3429a101322SJohannes Doerfert     }
3439a101322SJohannes Doerfert 
3449a101322SJohannes Doerfert     for (uint32_t Idx = 0, I = 0; I < NumKTIs; ++Idx) {
3459a101322SJohannes Doerfert       auto KTI = KTIR.getKernelTraceInfo(Idx);
346f3bfc563SJohannes Doerfert       auto PrettyKernelName =
347f3bfc563SJohannes Doerfert           llvm::omp::prettifyFunctionName(KTI.Kernel->getName());
3489a101322SJohannes Doerfert       if (NumKTIs == 1)
349f3bfc563SJohannes Doerfert         print(BoldLightPurple, "Kernel '%s'\n", PrettyKernelName.c_str());
3509a101322SJohannes Doerfert       else
351f3bfc563SJohannes Doerfert         print(BoldLightPurple, "Kernel %d: '%s'\n", I,
352f3bfc563SJohannes Doerfert               PrettyKernelName.c_str());
3539a101322SJohannes Doerfert       reportStackTrace(KTI.LaunchTrace);
3549a101322SJohannes Doerfert       ++I;
3559a101322SJohannes Doerfert     }
3569a101322SJohannes Doerfert 
3579a101322SJohannes Doerfert     if (NumKTIs != 1) {
3589a101322SJohannes Doerfert       print(Yellow,
3599a101322SJohannes Doerfert             "Use '%s=<num>' to adjust the number of shown stack traces (%u "
3609a101322SJohannes Doerfert             "now, up to %zu)\n",
3619a101322SJohannes Doerfert             Device.OMPX_TrackNumKernelLaunches.getName().data(),
3629a101322SJohannes Doerfert             Device.OMPX_TrackNumKernelLaunches.get(), KTIR.size());
3639a101322SJohannes Doerfert     }
3649a101322SJohannes Doerfert     // TODO: Let users know how to serialize kernels
3659a101322SJohannes Doerfert   }
366c95abe94SJohannes Doerfert };
367c95abe94SJohannes Doerfert 
368c95abe94SJohannes Doerfert } // namespace plugin
369c95abe94SJohannes Doerfert } // namespace target
370c95abe94SJohannes Doerfert } // namespace omp
371c95abe94SJohannes Doerfert } // namespace llvm
372c95abe94SJohannes Doerfert 
373c95abe94SJohannes Doerfert #endif // OFFLOAD_PLUGINS_NEXTGEN_COMMON_ERROR_REPORTING_H
374