CUDA Event:GPU 时间线上的事件、同步原理与实战

CUDA kernel launch 通常是异步的:CPU 把 kernel、内存拷贝等操作提交到 stream 后便继续执行。由此产生两个常见问题:如何准确测量 GPU 工作耗时,以及如何让不同 stream 在不阻塞 CPU 的情况下建立依赖? CUDA Event 就是解决这类问题的基础设施。它可以理解为插入 GPU stream 时间线中的一个标记:当 event 之前的工作全部完成,event 才进入完成状态。借助这个状态,我们可以做 GPU 计时、CPU 等待、跨 stream 同步和异步资源回收。 1. Event 不是 CPU 事件,而是 GPU 时间线标记 一个 CUDA stream 是按序执行的 GPU 工作队列: CPU 提交: Kernel A → memcpy → Event E → Kernel B 异步提交 GPU 执行: Kernel A ── memcpy ── E 完成 ── Kernel B 调用 cudaEventRecord(event, stream) 时,CPU 通常只是向 stream 提交一个 event 记录操作,并不会等待 GPU 执行到该位置。只有当这个 stream 中排在 event 前面的操作完成后,event 才会被标记为完成。 ...

2026年8月31日 · 6 分钟 · Hellokitty

Mooncake 中的协程:从 coro_rpc 到同步接口桥接

Mooncake 确实使用了协程,但它并不是把整个系统改造成“全异步架构”。截至本文分析的主分支提交 3d1665a,协程主要出现在控制面 RPC、连接管理和阻塞任务卸载等 I/O 密集路径;对外接口仍大量保留同步调用形式。 这形成了一个很实用的分层:内部用 C++20 协程组织异步流程,边界处再按需要转换成同步返回值或回调。 技术栈 Mooncake 的协程代码主要建立在两层库之上: async_simple::coro::Lazy<T> 表示一个惰性异步任务; yalantinglibs 的 coro_rpc 和 coro_io 提供异步 RPC、网络连接与线程池调度。 典型代码形态如下: async_simple::coro::Lazy<Result> request() { auto response = co_await client.send_request(...); co_return response; } Lazy<T> 创建后通常不会立刻执行。它需要被另一个协程 co_await,通过 .start(...) 启动,或者由 syncAwait(...) 驱动至完成。 路径一:Mooncake Store 的 Master RPC mooncake-store/src/master_client.cpp 中的 MasterClient::invoke_rpc 是最清晰的例子。它的外部签名是同步的: tl::expected<ReturnType, ErrorCode> MasterClient::invoke_rpc(Args&&... args); 函数内部却先构造 Lazy,再连续等待两个异步阶段: return async_simple::coro::syncAwait( [&]() -> async_simple::coro::Lazy< tl::expected<ReturnType, ErrorCode>> { auto pending = co_await pool->send_request( [&](coro_io::client_reuse_hint, coro_rpc::coro_rpc_client& client) { return client.send_request<ServiceMethod>(...); }); if (!pending.has_value()) { co_return tl::make_unexpected(ErrorCode::RPC_FAIL); } auto result = co_await std::move(pending.value()); co_return result->result(); }()); 这里有两次 co_await: ...

2026年8月28日 · 2 分钟 · Hellokitty