Jump to content

Connect SuperML | Leeroopedia MCP: Equip your AI agents with best practices, code verification, and debugging knowledge. Powered by Leeroo — building Organizational Superintelligence. Contact us at founders@leeroo.com.

Implementation:NVIDIA DALI CUDAEventPool

From Leeroopedia


Knowledge Sources
Domains Core, CUDA
Last Updated 2026-02-08 16:00 GMT

Overview

This file implements the CUDAEventPool class, a thread-safe pool for reusing CUDA event objects across devices to reduce allocation overhead.

Description

CUDA events are used extensively in DALI for stream synchronization (e.g., in AccessOrder::wait). Creating and destroying CUDA events has non-trivial overhead, so the CUDAEventPool maintains per-device linked lists of reusable event objects. When an event is requested via Get, the pool first attempts to recycle a previously returned event; if none is available, a new event is created with the configured flags (default: cudaEventDisableTiming). When an event is returned via Put, it is placed back into the appropriate per-device list.

The pool uses a spinlock for thread safety and maintains a separate unused_ free list for EventEntry node objects, avoiding repeated heap allocations for the intrusive linked list nodes. The constructor queries the CUDA device count to size the per-device event array. The Purge method destroys all pooled events and releases auxiliary memory. A singleton accessor (instance()) provides a process-wide shared pool.

The implementation uses intrusive singly-linked lists with manual Pop/Push operations for minimal overhead and cache-friendly traversal.

Usage

Use CUDAEventPool::instance() to obtain the global pool, then call Get(device_id) to lease an event and Put(event, device_id) to return it. This pattern is used internally by AccessOrder::wait for cross-stream synchronization. Application code should prefer using AccessOrder directly rather than interacting with the event pool.

Code Reference

Source Location

Signature

class DLL_PUBLIC CUDAEventPool {
 public:
  ~CUDAEventPool();
  explicit CUDAEventPool(unsigned event_flags = cudaEventDisableTiming);

  CUDAEvent Get(int device_id = -1);
  void Put(CUDAEvent &&event, int device_id = -1);
  void Purge();

  static CUDAEventPool &instance();

 private:
  CUDAEvent GetFromPool(int device_id);
  unsigned event_flags_;

  struct EventEntry {
    EventEntry() = default;
    explicit EventEntry(CUDAEvent event, EventEntry *next = nullptr);
    CUDAEvent event;
    EventEntry *next = nullptr;
  };

  EventEntry *unused_ = nullptr;
  std::vector<EventEntry *> dev_events_;
  spinlock lock_;

  static EventEntry *Pop(EventEntry *&head);
  static void Push(EventEntry *&head, EventEntry *new_entry);
  void DeleteList(EventEntry *&head);
};

Import

#include "dali/core/cuda_event_pool.h"

I/O Contract

Inputs

Name Type Required Description
event_flags unsigned No CUDA event creation flags; defaults to cudaEventDisableTiming
device_id int No CUDA device ordinal; defaults to -1 (current device)
event CUDAEvent && Yes (Put) CUDA event wrapper to return to the pool; ownership is transferred

Outputs

Name Type Description
CUDAEvent CUDAEvent A CUDA event wrapper object obtained from the pool or newly created
instance CUDAEventPool & Reference to the process-wide singleton pool

Usage Examples

Getting and returning an event

auto &pool = CUDAEventPool::instance();
int device_id = 0;

// Obtain an event (recycled or newly created)
CUDAEvent event = pool.Get(device_id);

// Use the event for synchronization
cudaEventRecord(event, stream);
cudaStreamWaitEvent(other_stream, event, 0);

// Return the event to the pool
pool.Put(std::move(event), device_id);

Using with default (current) device

auto &pool = CUDAEventPool::instance();
CUDAEvent event = pool.Get();  // uses current device
// ... use event ...
pool.Put(std::move(event));    // returns to current device pool

Related Pages

Page Connections

Double-click a node to navigate. Hold to expand connections.
Principle
Implementation
Heuristic
Environment