[llvm-branch-commits] [llvm] users/jplehr/feat/03 ompt upstream device tracing (PR #229410)

via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Tue Oct 6 05:52:42 PDT 2026


llvmorg-github-actions[bot] wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-offload

Author: Jan Patrick Lehr (jplehr)

<details>
<summary>Changes</summary>

Adds the OMPT profiler implementation without wiring it up into the
whole plugins infrastructure yet.

The individual commits do a bit of cleanup from the original port and
to keep up with the changes to `main` in the meantime.

---

<sub>Stack created with <a href="https://github.com/github/gh-stack">GitHub Stacks CLI</a> • <a href="https://gh.io/stacks-feedback">Give Feedback 💬</a></sub>

---

Patch is 29.98 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/229410.diff


7 Files Affected:

- (added) offload/include/OpenMP/OMPT/OmptCommonDefs.h (+128) 
- (added) offload/include/OpenMP/OMPT/OmptEventInfoTy.h (+39) 
- (modified) offload/plugins-nextgen/common/CMakeLists.txt (+5) 
- (added) offload/plugins-nextgen/common/OMPT/OmptDeviceTracing.h (+100) 
- (added) offload/plugins-nextgen/common/OMPT/OmptProfiler.cpp (+110) 
- (added) offload/plugins-nextgen/common/OMPT/OmptProfiler.h (+122) 
- (added) offload/plugins-nextgen/common/OMPT/OmptTracing.cpp (+256) 


``````````diff
diff --git a/offload/include/OpenMP/OMPT/OmptCommonDefs.h b/offload/include/OpenMP/OMPT/OmptCommonDefs.h
new file mode 100644
index 000000000000000..8ab2ba10a869337
--- /dev/null
+++ b/offload/include/OpenMP/OMPT/OmptCommonDefs.h
@@ -0,0 +1,128 @@
+//===------ OmptCommonDefs.h - Common definitions for OMPT --*- C++ -*-----===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Common defines and typedefs for OMPT callback and tracing functionality.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef OFFLOAD_INCLUDE_OMPTCOMMONDEFS_H
+#define OFFLOAD_INCLUDE_OMPTCOMMONDEFS_H
+
+#ifdef OMPT_SUPPORT
+
+#include "omp-tools.h"
+
+#pragma push_macro("DEBUG_PREFIX")
+#undef DEBUG_PREFIX
+#define DEBUG_PREFIX "OMPT"
+
+#define FUNCPTR_TO_PTR(x) ((void *)(uint64_t)x)
+
+#define FOREACH_OMPT_TARGET_CALLBACK(macro)                                    \
+  FOREACH_OMPT_DEVICE_EVENT(macro)                                             \
+  FOREACH_OMPT_NOEMI_EVENT(macro)                                              \
+  FOREACH_OMPT_EMI_EVENT(macro)
+
+// Common device tracing functions
+#define FOREACH_OMPT_DEVICE_TRACING_FN_COMMON(macro)                           \
+  macro(ompt_set_trace_ompt) macro(ompt_start_trace) macro(ompt_flush_trace)   \
+      macro(ompt_stop_trace) macro(ompt_advance_buffer_cursor)                 \
+          macro(ompt_get_record_type)
+
+// Supported device tracing entry points
+#define FOREACH_OMPT_DEVICE_TRACING_FN(macro)                                  \
+  FOREACH_OMPT_DEVICE_TRACING_FN_COMMON(macro)                                 \
+  macro(ompt_get_record_ompt) macro(ompt_get_device_time)                      \
+      macro(ompt_translate_time)
+
+// Device tracing functionalities, which are also e.g. coupled to mutexes
+#define FOREACH_OMPT_DEVICE_TRACING_FN_IMPLEMENTAIONS(macro)                   \
+  FOREACH_OMPT_DEVICE_TRACING_FN_COMMON(macro)                                 \
+  macro(ompt_set_timestamp) macro(ompt_set_granted_teams)
+
+#define OMPT_API_ROUTINE static
+
+#define OMPT_CALLBACK_AVAILABLE(fn) (llvm::omp::target::ompt::Initialized && fn)
+
+#define OMPT_IF_BUILT(stmt) stmt
+
+#define OMPT_IF_ENABLED(stmts)                                                 \
+  do {                                                                         \
+    if (llvm::omp::target::ompt::Initialized) {                                \
+      stmts                                                                    \
+    }                                                                          \
+  } while (0)
+
+#define OMPT_IF_TRACING_ENABLED(stmts)                                         \
+  do {                                                                         \
+    if (llvm::omp::target::ompt::TracingActive) {                              \
+      stmts                                                                    \
+    }                                                                          \
+  } while (0)
+
+#define OMPT_FRAME_FLAGS (ompt_frame_runtime | OMPT_FRAME_POSITION_DEFAULT)
+
+#if (__PPC64__ | __arm__)
+#define OMPT_GET_FRAME_ADDRESS(level) __builtin_frame_address(level)
+#define OMPT_FRAME_POSITION_DEFAULT ompt_frame_cfa
+#else
+#define OMPT_GET_FRAME_ADDRESS(level) __builtin_frame_address(level)
+#define OMPT_FRAME_POSITION_DEFAULT ompt_frame_framepointer
+#endif
+
+#define OMPT_PTR_UNKNOWN ((void *)0)
+
+#define performIfOmptInitialized(stmt)                                         \
+  do {                                                                         \
+    if (llvm::omp::target::ompt::Initialized) {                                \
+      stmt;                                                                    \
+    }                                                                          \
+  } while (0)
+
+#define performOmptCallback(CallbackName, ...)                                 \
+  do {                                                                         \
+    if (ompt_callback_##CallbackName##_fn)                                     \
+      ompt_callback_##CallbackName##_fn(__VA_ARGS__);                          \
+  } while (0)
+
+/// Device-independent OMPT tracing entry points, implemented by libomptarget
+/// and linked into the same library as their plugin-side callers.
+extern "C" {
+ompt_set_result_t libomptarget_ompt_set_trace_ompt(int DeviceId,
+                                                   unsigned int Enable,
+                                                   unsigned int EventTy);
+int libomptarget_ompt_start_trace(int DeviceId,
+                                  ompt_callback_buffer_request_t Request,
+                                  ompt_callback_buffer_complete_t Complete);
+int libomptarget_ompt_flush_trace(int DeviceId);
+int libomptarget_ompt_stop_trace(int DeviceId);
+int libomptarget_ompt_advance_buffer_cursor(ompt_device_t *Device,
+                                            ompt_buffer_t *Buffer, size_t Size,
+                                            ompt_buffer_cursor_t CurrentPos,
+                                            ompt_buffer_cursor_t *NextPos);
+ompt_record_t
+libomptarget_ompt_get_record_type(ompt_buffer_t *Buffer,
+                                  ompt_buffer_cursor_t CurrentPos);
+void libomptarget_ompt_set_granted_teams(uint32_t NumTeams);
+void libomptarget_ompt_set_timestamp(uint64_t Start, uint64_t Stop);
+} // extern "C"
+
+/// Function type def used for maintaining unique target region, target
+/// operations ids
+typedef uint64_t (*IdInterfaceTy)();
+
+#pragma pop_macro("DEBUG_PREFIX")
+
+#else
+#define performIfOmptInitialized(stmt)
+#define OMPT_IF_BUILT(stmt)
+#define OMPT_IF_ENABLED(stmts)
+#define OMPT_IF_TRACING_ENABLED(stmts)
+#endif // OMPT_SUPPORT
+
+#endif // OFFLOAD_INCLUDE_OMPTCOMMONDEFS_H
diff --git a/offload/include/OpenMP/OMPT/OmptEventInfoTy.h b/offload/include/OpenMP/OMPT/OmptEventInfoTy.h
new file mode 100644
index 000000000000000..7124b3a3ff501b2
--- /dev/null
+++ b/offload/include/OpenMP/OMPT/OmptEventInfoTy.h
@@ -0,0 +1,39 @@
+//===- OmptEventInfoTy.h - OMPT specific trace record data ------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Data structure used to communicate OMPT specific profiler data from the
+// high-level libomptarget into the vendor-specific plugins
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef OFFLOAD_INCLUDE_OPENMP_OMPT_OMPTEVENTINFOTY_H
+#define OFFLOAD_INCLUDE_OPENMP_OMPT_OMPTEVENTINFOTY_H
+
+#include "Shared/Debug.h"
+
+struct ompt_record_ompt_t;
+
+namespace llvm {
+namespace omp {
+namespace target {
+namespace ompt {
+
+/// Holds info needed to fill asynchronous trace records
+struct OmptEventInfoTy {
+  /// The granted number of teams at runtime
+  uint64_t NumTeams;
+  /// Pointer to the actual buffer storage location
+  ompt_record_ompt_t *TraceRecord;
+};
+
+} // namespace ompt
+} // namespace target
+} // namespace omp
+} // namespace llvm
+
+#endif // OFFLOAD_INCLUDE_OPENMP_OMPT_OMPTEVENTINFOTY_H
diff --git a/offload/plugins-nextgen/common/CMakeLists.txt b/offload/plugins-nextgen/common/CMakeLists.txt
index 19ce102309a7245..556b8ddf3311ca2 100644
--- a/offload/plugins-nextgen/common/CMakeLists.txt
+++ b/offload/plugins-nextgen/common/CMakeLists.txt
@@ -37,6 +37,11 @@ endif()
 include(FindLibcCommonUtils)
 target_link_libraries(PluginCommon PRIVATE llvm-libc-common-utilities)
 
+if (TARGET flang_rt.runtime.static)
+  target_link_libraries(PluginCommon PRIVATE flang_rt.runtime.static)
+  target_compile_definitions(PluginCommon PRIVATE OFFLOAD_HAS_FLANG_RT)
+endif()
+
 # Define the TARGET_NAME and DEBUG_PREFIX.
 target_compile_definitions(PluginCommon PRIVATE
   TARGET_NAME=PluginInterface
diff --git a/offload/plugins-nextgen/common/OMPT/OmptDeviceTracing.h b/offload/plugins-nextgen/common/OMPT/OmptDeviceTracing.h
new file mode 100644
index 000000000000000..adc3695b1398761
--- /dev/null
+++ b/offload/plugins-nextgen/common/OMPT/OmptDeviceTracing.h
@@ -0,0 +1,100 @@
+//===- OmptDeviceTracing.h - Target independent OMPT callbacks --*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Interface used by target-independent runtimes to coordinate registration and
+// invocation of OMPT tracing functionality.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef OPENMP_LIBOMPTARGET_PLUGINS_NEXTGEN_COMMON_OMPTDEVICETRACING_H
+#define OPENMP_LIBOMPTARGET_PLUGINS_NEXTGEN_COMMON_OMPTDEVICETRACING_H
+
+#ifdef OMPT_SUPPORT
+
+#include "OpenMP/OMPT/OmptCommonDefs.h"
+
+#include <map>
+#include <mutex>
+
+#pragma push_macro("DEBUG_PREFIX")
+#undef DEBUG_PREFIX
+#define DEBUG_PREFIX "OMPT"
+
+extern void setOmptAsyncCopyProfile(bool Enable);
+extern void setGlobalOmptKernelProfile(void *Device, int Enable);
+extern uint64_t getSystemTimestampInNs();
+
+namespace llvm {
+namespace omp {
+namespace target {
+namespace ompt {
+
+// Declare OMPT device tracing function mutexes
+#define declareOmptTracingFnMutex(Name) extern std::mutex Name##_mutex;
+FOREACH_OMPT_DEVICE_TRACING_FN_IMPLEMENTAIONS(declareOmptTracingFnMutex)
+#undef declareOmptTracingFnMutex
+
+extern std::mutex DeviceIdWritingMutex;
+
+/// Activate tracing on the given device
+void enableDeviceTracing(int DeviceId);
+
+/// Deactivate tracing on the given device
+void disableDeviceTracing(int DeviceId);
+
+/// Set 'start' and 'stop' in trace records
+void setOmptTimestamp(uint64_t StartTime, uint64_t EndTime);
+
+/// Set the linear function correlation between host and device clocks
+void setOmptHostToDeviceRate(double Slope, double Offset);
+
+/// Set / store the number of granted teams in trace records
+void setOmptGrantedNumTeams(uint64_t NumTeams);
+
+/// Lookup the given device pointer and return its RTL device ID
+int getDeviceId(ompt_device_t *Device);
+
+/// Map the given device pointer to the given DeviceId
+void setDeviceId(ompt_device_t *Device, int32_t DeviceId);
+
+/// Rempve the given device pointer from the current mapping
+void removeDeviceId(ompt_device_t *Device);
+
+/// Check whether the provided device is currently traced.
+bool isTracedDevice(int32_t DeviceId);
+
+/// Provide name based lookup for the device tracing functions
+extern ompt_interface_fn_t
+lookupDeviceTracingFn(const char *InterfaceFunctionName);
+
+/// Host to device linear clock correlation
+extern double HostToDeviceSlope;
+
+/// Host to device constant clock offset
+extern double HostToDeviceOffset;
+
+/// Mapping of device pointers to their corresponding RTL device ID
+extern std::map<ompt_device_t *, int32_t> Devices;
+
+/// Mapping of RTL device IDs to their currently enabled tracing event types.
+/// Note: Event type '0' (bit position) indicates if this device is traced.
+extern std::map<int32_t, uint64_t> TracedDevices;
+
+/// OMPT global tracing status. Indicates if at least one device is traced.
+extern bool TracingActive;
+
+} // namespace ompt
+} // namespace target
+} // namespace omp
+} // namespace llvm
+
+#pragma pop_macro("DEBUG_PREFIX")
+
+#endif // OMPT_SUPPORT
+
+#endif // OPENMP_LIBOMPTARGET_PLUGINS_NEXTGEN_COMMON_OMPTDEVICETRACING_H
diff --git a/offload/plugins-nextgen/common/OMPT/OmptProfiler.cpp b/offload/plugins-nextgen/common/OMPT/OmptProfiler.cpp
new file mode 100644
index 000000000000000..d74e6e3b9b82acf
--- /dev/null
+++ b/offload/plugins-nextgen/common/OMPT/OmptProfiler.cpp
@@ -0,0 +1,110 @@
+//===- OmptProfiler.cpp - OMPT impl of GenericProfilerTy --------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Implementation of OmptProfilerTy
+//
+//===----------------------------------------------------------------------===//
+
+#include "OmptProfiler.h"
+#include "OpenMP/OMPT/Interface.h"
+#include "PluginInterface.h"
+#include "Shared/Debug.h"
+
+#include <memory>
+
+using namespace llvm::omp::target;
+
+void ompt::OmptProfilerTy::handleDataAlloc(uint64_t StartNanos,
+                                           uint64_t EndNanos, void *HostPtr,
+                                           uint64_t Size, void *Data) {
+  ompt::setOmptTimestamp(StartNanos, EndNanos);
+}
+
+void ompt::OmptProfilerTy::handleDataDelete(uint64_t StartNanos,
+                                            uint64_t EndNanos, void *TgtPtr,
+                                            void *Data) {
+  ompt::setOmptTimestamp(StartNanos, EndNanos);
+}
+
+void ompt::OmptProfilerTy::handlePreKernelLaunch(
+    plugin::GenericDeviceTy *Device, uint32_t NumBlocks[3],
+    __tgt_async_info *AI) {
+  if (!ompt::isTracedDevice(
+          ompt::getDeviceId(reinterpret_cast<ompt_device_t *>(Device))))
+    return;
+
+  if (AI->ProfilerData == nullptr)
+    return;
+
+  auto ProfilerSpecificData =
+      reinterpret_cast<ompt::OmptEventInfoTy *>(AI->ProfilerData);
+  assert(ProfilerSpecificData && "Invalid ProfilerSpecificData");
+  // Set number of granted teams for OMPT
+  setOmptGrantedNumTeams(NumBlocks[0]);
+  ProfilerSpecificData->NumTeams = NumBlocks[0];
+}
+
+void ompt::OmptProfilerTy::handleKernelCompletion(uint64_t StartNanos,
+                                                  uint64_t EndNanos,
+                                                  void *Data) {
+
+  if (!isProfilingEnabled())
+    return;
+
+  // Null data means no trace record was assigned for this event, see
+  // TracerInterfaceRAII in OpenMP/OMPT/Interface.h.
+  if (!Data)
+    return;
+
+  ODBG(ODT_Tool) << "OMPT-Async: Time kernel for asynchronous execution: Start "
+                 << StartNanos << " End " << EndNanos;
+
+  auto OmptEventInfo = reinterpret_cast<ompt::OmptEventInfoTy *>(Data);
+  assert(OmptEventInfo && "Invalid OmptEventInfo");
+  assert(OmptEventInfo->TraceRecord && "Invalid TraceRecord");
+
+  ompt::RegionInterface.stopTargetSubmitTraceAsync(OmptEventInfo->TraceRecord,
+                                                   OmptEventInfo->NumTeams,
+                                                   StartNanos, EndNanos);
+
+  // Done processing, our responsibility to free the memory
+  freeProfilerDataEntry(OmptEventInfo);
+}
+
+void ompt::OmptProfilerTy::handleDataTransfer(uint64_t StartNanos,
+                                              uint64_t EndNanos, void *Data) {
+
+  if (!isProfilingEnabled())
+    return;
+
+  // Null data means no trace record was assigned for this event, see
+  // TracerInterfaceRAII in OpenMP/OMPT/Interface.h.
+  if (!Data)
+    return;
+
+  ODBG(ODT_Tool) << "OMPT-Async: Time data for asynchronous execution: Start "
+                 << StartNanos << " End " << EndNanos;
+
+  auto OmptEventInfo = reinterpret_cast<ompt::OmptEventInfoTy *>(Data);
+  assert(OmptEventInfo && "Invalid OmptEventInfo");
+  assert(OmptEventInfo->TraceRecord && "Invalid TraceRecord");
+
+  ompt::RegionInterface.stopTargetDataMovementTraceAsync(
+      OmptEventInfo->TraceRecord, StartNanos, EndNanos);
+
+  // Done processing, our responsibility to free the memory
+  freeProfilerDataEntry(OmptEventInfo);
+}
+
+bool ompt::OmptProfilerTy::isProfilingEnabled() { return ompt::TracingActive; }
+
+void ompt::OmptProfilerTy::setTimeConversionFactorsImpl(double Slope,
+                                                        double Offset) {
+  ODBG(ODT_Tool) << "Using Time Slope: " << Slope << " and Offset: " << Offset;
+  setOmptHostToDeviceRate(Slope, Offset);
+}
diff --git a/offload/plugins-nextgen/common/OMPT/OmptProfiler.h b/offload/plugins-nextgen/common/OMPT/OmptProfiler.h
new file mode 100644
index 000000000000000..4c2c90e3f385add
--- /dev/null
+++ b/offload/plugins-nextgen/common/OMPT/OmptProfiler.h
@@ -0,0 +1,122 @@
+//===- OmptProfiler.h - OMPT specific impl of GenericProfilerTy -*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// OMPT specific implementation of the GenericProfilerTy class.
+// This class uses the already existing implementation of OMPT to invoke
+// callbacks and perform tracing.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef OFFLOAD_PLUGINS_NEXTGEN_COMMON_OMPT_OMPTPROFILERTY_H
+#define OFFLOAD_PLUGINS_NEXTGEN_COMMON_OMPT_OMPTPROFILERTY_H
+
+#include "GenericProfiler.h"
+
+#include "OmptDeviceTracing.h"
+#include "OpenMP/OMPT/Callback.h"
+#include "OpenMP/OMPT/OmptEventInfoTy.h"
+#include "Shared/Debug.h"
+#include "omp-tools.h"
+
+#include <functional>
+#include <memory>
+#include <mutex>
+#include <tuple>
+
+#pragma push_macro("DEBUG_PREFIX")
+#undef DEBUG_PREFIX
+#define DEBUG_PREFIX "OMPT"
+
+extern uint64_t getSystemTimestampInNs();
+
+using namespace llvm::omp::target::debug;
+
+namespace llvm {
+namespace omp {
+namespace target {
+namespace plugin {
+struct GenericDeviceTy;
+class GenericProfilerTy;
+
+} // namespace plugin
+
+namespace ompt {
+
+/**
+ * Implements an OMPT backend for the Profiler interface used in the plugins.
+ *
+ * Forwards / Implements the different generic hooks with OMPT semantics.
+ */
+class OmptProfilerTy : public plugin::GenericProfilerTy {
+public:
+  bool isProfilingEnabled() override;
+
+  void handleDataAlloc(uint64_t StartNanos, uint64_t EndNanos, void *HostPtr,
+                       uint64_t Size, void *Data) override;
+  void handleDataDelete(uint64_t StartNanos, uint64_t EndNanos, void *TgtPtr,
+                        void *Data) override;
+
+  void handlePreKernelLaunch(plugin::GenericDeviceTy *Device,
+                             uint32_t NumBlocks[3],
+                             __tgt_async_info *AI) override;
+
+  void handleKernelCompletion(uint64_t StartNanos, uint64_t EndNanos,
+                              void *Data) override;
+
+  void handleDataTransfer(uint64_t StartNanos, uint64_t EndNanos,
+                          void *Data) override;
+
+  void setTimeConversionFactorsImpl(double Slope, double Offset) override;
+
+  /// Allocate the event info that carries \p Record into the plugins for
+  /// asynchronous completion. The profiler owns the returned object and frees
+  /// it via freeProfilerDataEntry once the plugin completed the record.
+  OmptEventInfoTy *trackAsyncRecord(ompt_record_ompt_t *Record) {
+    // TODO: This is ID is not used currently
+    uint64_t Id = OmptProfDataId.fetch_add(1);
+    std::scoped_lock<std::mutex> Lock(ProfilerDataMutex);
+    auto &Info = ProfilerData[Id];
+    Info = std::make_unique<OmptEventInfoTy>();
+    Info->TraceRecord = Record;
+    Info->NumTeams = 0;
+    return Info.get();
+  }
+
+  void freeProfilerDataEntry(OmptEventInfoTy *DataPtr) {
+    std::scoped_lock<std::mutex> Lock(ProfilerDataMutex);
+
+    for (auto &Entry : ProfilerData)
+      if (Entry.second.get() == DataPtr) {
+        ProfilerData.erase(Entry.first);
+        break;
+      }
+  }
+
+private:
+  /// Holds a unique ID for each allocation of OmptEventInfoTy
+  std::atomic<uint64_t> OmptProfDataId{0};
+
+  /// Holds memory used to store OMPT specific data and pass it down from
+  /// libomptarget into the plugins.
+  std::map<uint64_t, std::unique_ptr<OmptEventInfoTy>> ProfilerData;
+
+  /// Lock to guard STL ProfilerData map
+  std::mutex ProfilerDataMutex;
+};
+
+/// Process-wide OMPT profile...
[truncated]

``````````

</details>


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


More information about the llvm-branch-commits mailing list