[llvm] [OFFLOAD] Add support for more fine grained debug messages control (PR #165416)

Alex Duran via llvm-commits llvm-commits at lists.llvm.org
Wed Nov 19 21:17:22 PST 2025


================
@@ -198,4 +200,319 @@ 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.
+//
+// Constructing messages should be done using C++ stream style syntax.
+//
+// Usage examples:
+// ODBG("type1", 2) << "This is a level 2 message of type1";
+// ODBG("Init") << "This is a default level of the init type";
+// ODBG() << "This is a level 1 message of the default type";
+// ODBG("Init", 3) << NumDevices << " were initialized";
+// ODBG("Kernel") << "Launching " << KernelName << " on device " << DeviceId;
+//
+// Additionally, ODBG_IF_LEVEL can be used to have parts of a stream to provide
+// additional detail at different levels without needing to split the message.
+// Using ODBG_RESET_LEVEL will reset the level back to the original level.
+// E.g.:
+// ODBG("Mapping", 2) << "Function F"
+//   << ODBG_IF_LEVEL(3) << " with argument value=" << Arg
+//   << ODBG_IF_LEVEL(4) << " and address=" << &Arg
+//   << ODBG_RESET_LEVEL() << " called";
+//
+// Similarly the ODBG_ONLY_LEVEL can be used to print parts of a stream only at
+// a specific level, e.g.:
+// ODBG() << "Starting computation "
+//   << ODBG_ONLY_LEVEL(1) << "on a device"
+//   << ODBG_ONLY_LEVEL(2) << "and mapping data on device" << DeviceId;
+//   << ODBG_ONLY_LEVEL(3) << dumpDetailedMappingInfo(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 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 ODBG_STREAM or
+// ODBG_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.
+[[maybe_unused]] static 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;
+}
+
+[[maybe_unused]] static 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};
+}
+
+[[maybe_unused]] static DebugSettings &getDebugSettings() {
+  static DebugSettings Settings;
+  static std::once_flag Flag{};
+  std::call_once(Flag, []() {
+    // 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) {
+      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)
----------------
adurang wrote:

got it. done.

https://github.com/llvm/llvm-project/pull/165416


More information about the llvm-commits mailing list