[llvm] [OFFLOAD] Add support for more fine grained debug messages control (PR #165416)
Alex Duran via llvm-commits
llvm-commits at lists.llvm.org
Tue Nov 4 12:49:21 PST 2025
https://github.com/adurang updated https://github.com/llvm/llvm-project/pull/165416
>From 2965164487fc0e4bf4c25047430e36dbe350a1a8 Mon Sep 17 00:00:00 2001
From: Alex Duran <alejandro.duran at intel.com>
Date: Tue, 28 Oct 2025 15:33:47 +0100
Subject: [PATCH 1/5] [OFFLOAD] Add support for more fine grained debug
messages control
---
offload/include/Shared/Debug.h | 188 +++++++++++++++++++++++
offload/libomptarget/OffloadRTL.cpp | 2 +-
offload/libomptarget/PluginManager.cpp | 2 +-
offload/plugins-nextgen/host/src/rtl.cpp | 2 +
4 files changed, 192 insertions(+), 2 deletions(-)
diff --git a/offload/include/Shared/Debug.h b/offload/include/Shared/Debug.h
index 7c3db8dbf119f..25922d190d20e 100644
--- a/offload/include/Shared/Debug.h
+++ b/offload/include/Shared/Debug.h
@@ -42,6 +42,8 @@
#include <mutex>
#include <string>
+#include "llvm/Support/circular_raw_ostream.h"
+
/// 32-Bit field data attributes controlling information presented to the user.
enum OpenMPInfoType : uint32_t {
// Print data arguments and attributes upon entering an OpenMP device kernel.
@@ -198,4 +200,190 @@ inline uint32_t getDebugLevel() {
} \
} while (false)
+// New macros that will allow for more granular control over debugging output
+// Each message can be classified by Component, Type and Level
+// Component: The broad component of the offload runtime emitting the message.
+// Type: A cross-component classification of messages
+// Level: The verbosity level of the message
+//
+// The component is pulled from the TARGET_NAME macro, Type and Level can be
+// defined for each debug message but by default they are "default" and "1"
+// respectively.
+//
+// For liboffload and plugins, use OFFLOAD_DEBUG(...)
+// For libomptarget, use OPENMP_DEBUG(...)
+// Constructing messages should be done using C++ stream style syntax.
+//
+// Usage examples:
+// OFFLOAD_DEBUG("type1", 2, "This is a level 2 message of type1");
+// OFFLOAD_DEBUG("Init", "This is a default level of the init type");
+// OPENMP_DEBUG("This is a level 1 message of the default type");
+// OFFLOAD_DEBUG("Init", 3, NumDevices << " were initialized\n");
+// OFFLOAD_DEBUG("Kernel", "Starting kernel " << KernelName << " on device " <<
+// DeviceId);
+//
+// Message output can be controlled by setting LIBOMPTARGET_DEBUG or
+// LIBOFFLOAD_DEBUG environment variables. Their syntax is as follows:
+// [integer]|all|<type1>[:<level1>][,<type2>[:<level2>],...]
+//
+// 0 : Disable all debug messages
+// all : Enable all debug messages
+// integer : Set the default level for all messages
+// <type> : Enable only messages of the specified type and level (more than one
+// can be specified). Components are also supported as
+// types.
+// <level> : Set the verbosity level for the specified type (default is 1)
+//
+// For very specific cases where more control is needed, use OFFLOAD_DEBUG_RAW
+// or OFFLOAD_DEBUG_BASE. See below for details.
+
+namespace llvm::offload::debug {
+
+#ifdef OMPTARGET_DEBUG
+
+struct DebugFilter {
+ StringRef Type;
+ uint32_t Level;
+};
+
+struct DebugSettings {
+ bool Enabled = false;
+ uint32_t DefaultLevel = 1;
+ llvm::SmallVector<DebugFilter> Filters;
+};
+
+/// dbgs - Return a circular-buffered debug stream.
+inline llvm::raw_ostream &dbgs() {
+ // Do one-time initialization in a thread-safe way.
+ static struct dbgstream {
+ llvm::circular_raw_ostream strm;
+
+ dbgstream() : strm(llvm::errs(), "*** Debug Log Output ***\n", 0) {}
+ } thestrm;
+
+ return thestrm.strm;
+}
+
+inline DebugFilter parseDebugFilter(StringRef Filter) {
+ size_t Pos = Filter.find(':');
+ if (Pos == StringRef::npos)
+ return {Filter, 1};
+
+ StringRef Type = Filter.slice(0, Pos);
+ uint32_t Level = 1;
+ if (Filter.slice(Pos + 1, Filter.size()).getAsInteger(10, Level))
+ Level = 1;
+
+ return {Type, Level};
+}
+
+inline DebugSettings &getDebugSettings() {
+ static DebugSettings Settings;
+ static std::once_flag Flag{};
+ std::call_once(Flag, []() {
+ printf("Configuring debug settings\n");
+ // Eventually, we probably should allow for the upper layers to set
+ // the debug settings directly according to their own env var
+ // (or other methods) settings.
+ // For now mantain compatibility with existing libomptarget env var
+ // and add a liboffload independent one.
+ char *Env = getenv("LIBOMPTARGET_DEBUG");
+ if (!Env) {
+ Env = getenv("LIBOFFLOAD_DEBUG");
+ if (!Env)
+ return;
+ }
+
+ StringRef EnvRef(Env);
+ if (EnvRef == "0")
+ return;
+
+ Settings.Enabled = true;
+ if (EnvRef.equals_insensitive("all"))
+ return;
+
+ if (!EnvRef.getAsInteger(10, Settings.DefaultLevel))
+ return;
+
+ Settings.DefaultLevel = 1;
+
+ SmallVector<StringRef> DbgTypes;
+ EnvRef.split(DbgTypes, ',', -1, false);
+
+ for (auto &DT : DbgTypes)
+ Settings.Filters.push_back(parseDebugFilter(DT));
+ });
+
+ return Settings;
+}
+
+inline bool isDebugEnabled() {
+ return getDebugSettings().Enabled;
+}
+
+inline bool shouldPrintDebug(const char *Component, const char *Type, uint32_t Level) {
+ const auto &Settings = getDebugSettings();
+ if (!Settings.Enabled)
+ return false;
+
+ if (Settings.Filters.empty())
+ return Level <= Settings.DefaultLevel;
+
+ for (const auto &DT : Settings.Filters) {
+ if (DT.Level < Level)
+ continue;
+ if (DT.Type.equals_insensitive(Type))
+ return true;
+ if (DT.Type.equals_insensitive(Component))
+ return true;
+ }
+
+ return false;
+}
+
+#define OFFLOAD_DEBUG_BASE(Component, Type, Level, ...) \
+ do { \
+ if (llvm::offload::debug::isDebugEnabled() && \
+ llvm::offload::debug::shouldPrintDebug(Component, Type, Level)) \
+ __VA_ARGS__; \
+ } while (0)
+
+#define OFFLOAD_DEBUG_RAW(Type, Level, X) \
+ OFFLOAD_DEBUG_BASE(GETNAME(TARGET_NAME), Type, Level, X)
+
+#define OFFLOAD_DEBUG_1(X) \
+ OFFLOAD_DEBUG_BASE(GETNAME(TARGET_NAME), "default", 1, \
+ llvm::offload::debug::dbgs() \
+ << DEBUG_PREFIX << " --> " << X)
+
+#define OFFLOAD_DEBUG_2(Type, X) \
+ OFFLOAD_DEBUG_BASE(GETNAME(TARGET_NAME), Type, 1, \
+ llvm::offload::debug::dbgs() \
+ << DEBUG_PREFIX << " --> " << X)
+
+#define OFFLOAD_DEBUG_3(Type, Level, X) \
+ OFFLOAD_DEBUG_BASE(GETNAME(TARGET_NAME), Type, Level, \
+ llvm::offload::debug::dbgs() \
+ << DEBUG_PREFIX << " --> " << X)
+
+#define OFFLOAD_SELECT(Type, Level, X, NArgs, ...) OFFLOAD_DEBUG_##NArgs
+
+// To be used in liboffload and plugins
+#define OFFLOAD_DEBUG(...) OFFLOAD_SELECT(__VA_ARGS__, 3, 2, 1)(__VA_ARGS__)
+
+// To be used in libomptarget only
+#define OPENMP_DEBUG(...) OFFLOAD_DEBUG(__VA_ARGS__)
+
+#else
+
+// Don't print anything if debugging is disabled
+#define OFFLOAD_DEBUG_BASE(Component, Type, Level, ...)
+#define OFFLOAD_DEBUG_RAW(Type, Level, X)
+#define OFFLOAD_DEBUG(...)
+#define OPENMP_DEBUG(...)
+
+#endif
+
+} // namespace llvm::offload::debug
+
#endif // OMPTARGET_SHARED_DEBUG_H
diff --git a/offload/libomptarget/OffloadRTL.cpp b/offload/libomptarget/OffloadRTL.cpp
index 04bd21ec91a49..9f9ec5c8bfabe 100644
--- a/offload/libomptarget/OffloadRTL.cpp
+++ b/offload/libomptarget/OffloadRTL.cpp
@@ -35,7 +35,7 @@ void initRuntime() {
RefCount++;
if (RefCount == 1) {
- DP("Init offload library!\n");
+ OPENMP_DEBUG("Init offload library!\n");
#ifdef OMPT_SUPPORT
// Initialize OMPT first
llvm::omp::target::ompt::connectLibrary();
diff --git a/offload/libomptarget/PluginManager.cpp b/offload/libomptarget/PluginManager.cpp
index c8d6b42114d0f..915fd8df80eb7 100644
--- a/offload/libomptarget/PluginManager.cpp
+++ b/offload/libomptarget/PluginManager.cpp
@@ -36,7 +36,7 @@ void PluginManager::init() {
return;
}
- DP("Loading RTLs...\n");
+ OPENMP_DEBUG("Init", "Loading RTLs\n");
// Attempt to create an instance of each supported plugin.
#define PLUGIN_TARGET(Name) \
diff --git a/offload/plugins-nextgen/host/src/rtl.cpp b/offload/plugins-nextgen/host/src/rtl.cpp
index eb4ecac9907a1..3baadfebc541c 100644
--- a/offload/plugins-nextgen/host/src/rtl.cpp
+++ b/offload/plugins-nextgen/host/src/rtl.cpp
@@ -451,6 +451,8 @@ struct GenELF64PluginTy final : public GenericPluginTy {
if (auto Err = Plugin::check(ffi_init(), "failed to initialize libffi"))
return std::move(Err);
#endif
+ OFFLOAD_DEBUG("Init", 2,
+ "GenELF64 plugin detected" << NUM_DEVICES << " devices\n");
return NUM_DEVICES;
}
>From 7bc7ce8b69a1e3b1fb4602b2ae3477d7fa3748a0 Mon Sep 17 00:00:00 2001
From: Alex Duran <alejandro.duran at intel.com>
Date: Tue, 28 Oct 2025 16:04:18 +0100
Subject: [PATCH 2/5] formatting
---
offload/include/Shared/Debug.h | 15 +++++++--------
1 file changed, 7 insertions(+), 8 deletions(-)
diff --git a/offload/include/Shared/Debug.h b/offload/include/Shared/Debug.h
index 25922d190d20e..85e1c0e19445d 100644
--- a/offload/include/Shared/Debug.h
+++ b/offload/include/Shared/Debug.h
@@ -282,10 +282,10 @@ inline DebugSettings &getDebugSettings() {
static std::once_flag Flag{};
std::call_once(Flag, []() {
printf("Configuring debug settings\n");
- // Eventually, we probably should allow for the upper layers to set
- // the debug settings directly according to their own env var
- // (or other methods) settings.
- // For now mantain compatibility with existing libomptarget env var
+ // Eventually, we probably should allow the upper layers to set
+ // debug settings directly according to their own env var or
+ // other methods.
+ // For now, mantain compatibility with existing libomptarget env var
// and add a liboffload independent one.
char *Env = getenv("LIBOMPTARGET_DEBUG");
if (!Env) {
@@ -317,11 +317,10 @@ inline DebugSettings &getDebugSettings() {
return Settings;
}
-inline bool isDebugEnabled() {
- return getDebugSettings().Enabled;
-}
+inline bool isDebugEnabled() { return getDebugSettings().Enabled; }
-inline bool shouldPrintDebug(const char *Component, const char *Type, uint32_t Level) {
+inline bool shouldPrintDebug(const char *Component, const char *Type,
+ uint32_t Level) {
const auto &Settings = getDebugSettings();
if (!Settings.Enabled)
return false;
>From c9fc54a3c8d07b34c6be74ef1e579bf1b8ffb2a5 Mon Sep 17 00:00:00 2001
From: Alex Duran <alejandro.duran at intel.com>
Date: Wed, 29 Oct 2025 16:04:32 +0100
Subject: [PATCH 3/5] add some env var examples
---
offload/include/Shared/Debug.h | 13 ++++++++++++-
1 file changed, 12 insertions(+), 1 deletion(-)
diff --git a/offload/include/Shared/Debug.h b/offload/include/Shared/Debug.h
index 85e1c0e19445d..3af4bb4abdd93 100644
--- a/offload/include/Shared/Debug.h
+++ b/offload/include/Shared/Debug.h
@@ -227,13 +227,24 @@ inline uint32_t getDebugLevel() {
// [integer]|all|<type1>[:<level1>][,<type2>[:<level2>],...]
//
// 0 : Disable all debug messages
-// all : Enable all debug messages
+// all : Enable all level 1 debug messages
// integer : Set the default level for all messages
// <type> : Enable only messages of the specified type and level (more than one
// can be specified). Components are also supported as
// types.
// <level> : Set the verbosity level for the specified type (default is 1)
//
+// Some examples:
+// LIBOFFLOAD_DEBUG=1 (Print all messages of level 1 or lower)
+// LIBOFFLOAD_DEBUG=5 (Print all messages of level 5 or lower)
+// LIBOFFLOAD_DEBUG=init (Print messages of type "init" of level 1 or lower)
+// LIBOFFLOAD_DEBUG=init:3,mapping:2 (Print messages of type "init" of level 3
+// or lower and messages of type "mapping" of
+// level 2 or lower)
+// LIBOFFLOAD_DEBUG=omptarget:4, init (Print messages from component "omptarget" of
+// level 4 or lower and messages of type
+// "init" of level 1 or lower)
+//
// For very specific cases where more control is needed, use OFFLOAD_DEBUG_RAW
// or OFFLOAD_DEBUG_BASE. See below for details.
>From da323afd1959320804fefcc77cdaffa4f92a0864 Mon Sep 17 00:00:00 2001
From: Alex Duran <alejandro.duran at intel.com>
Date: Tue, 4 Nov 2025 21:31:42 +0100
Subject: [PATCH 4/5] remove forgotten printf
---
offload/include/Shared/Debug.h | 1 -
1 file changed, 1 deletion(-)
diff --git a/offload/include/Shared/Debug.h b/offload/include/Shared/Debug.h
index 3af4bb4abdd93..1fbf1c2a2645b 100644
--- a/offload/include/Shared/Debug.h
+++ b/offload/include/Shared/Debug.h
@@ -292,7 +292,6 @@ inline DebugSettings &getDebugSettings() {
static DebugSettings Settings;
static std::once_flag Flag{};
std::call_once(Flag, []() {
- printf("Configuring debug settings\n");
// Eventually, we probably should allow the upper layers to set
// debug settings directly according to their own env var or
// other methods.
>From 562c93ec63e046b0a16ac96e8b58446ce5af81af Mon Sep 17 00:00:00 2001
From: Alex Duran <alejandro.duran at intel.com>
Date: Tue, 4 Nov 2025 21:49:04 +0100
Subject: [PATCH 5/5] minor comment format fix
---
offload/include/Shared/Debug.h | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/offload/include/Shared/Debug.h b/offload/include/Shared/Debug.h
index 1fbf1c2a2645b..5d918f9afef91 100644
--- a/offload/include/Shared/Debug.h
+++ b/offload/include/Shared/Debug.h
@@ -241,8 +241,8 @@ inline uint32_t getDebugLevel() {
// LIBOFFLOAD_DEBUG=init:3,mapping:2 (Print messages of type "init" of level 3
// or lower and messages of type "mapping" of
// level 2 or lower)
-// LIBOFFLOAD_DEBUG=omptarget:4, init (Print messages from component "omptarget" of
-// level 4 or lower and messages of type
+// LIBOFFLOAD_DEBUG=omptarget:4, init (Print messages from component "omptarget"
+// of level 4 or lower and messages of type
// "init" of level 1 or lower)
//
// For very specific cases where more control is needed, use OFFLOAD_DEBUG_RAW
More information about the llvm-commits
mailing list