Ray Compiled Graph 性能剖析指南:PyTorch Profiler、Nsight 与编译图可视化
【免费下载链接】rayRay is an AI compute engine. Ray consists of a core distributed runtime and a set of AI Libraries for accelerating ML workloads.项目地址: https://gitcode.com/gh_mirrors/ra/ray
导读
Ray Compiled Graph(编译图,CGraph)是 Ray Core 面向 GPU 加速工作负载提供的高性能执行路径,它将一组跨 Actor 的 DAG 预先编译成确定性的调度与通信方案,从而降低每次执行时的任务级与系统级开销。本文以 doc/source/ray-core/compiled-graph/profiling.rst 为核心,完整讲解编译图的两种性能剖析方案——基于 PyTorch Profiler 的 Torch 追踪,以及基于 Nsight Systems + NVTX 的系统级剖析,并附带编译图结构的可视化方法。读完本文,你将能够:通过一行环境变量开启 Torch profiling 并产出每个 Actor 独立的 trace 文件;通过runtime_env为参与编译图的 Actor 挂载 Nsight 剖析并解读/tmp/ray/session_*/logs下的剖析结果;使用 NVTX 对执行循环中的方法调用做细粒度标注;最后用visualize()将编译后的图结构导出为 PNG 以便直观排查调度问题。
为什么需要剖析 Compiled Graph
编译图将 DAG 中每个 Actor 的方法调用与它们之间的数据传输(如 NCCL 张量传输通道)预编译为一份执行计划(schedule),由每个 Actor 内的执行循环按计划顺序执行。性能瓶颈往往来自两类开销:
- 任务级开销:单个 task 从准备、反序列化到实际方法执行的耗时,以及多次执行之间的波动;
- 系统级开销:调度、通信(如 NCCL 通道建立、张量传输)、内存拷贝等不属于用户计算代码的部分。
官方文档(即本主题来源文档)指出,Compiled Graph 提供基于 PyTorch 和基于 Nsight 两套剖析能力,目的是"更好地理解单个任务、系统开销与性能瓶颈",开发者可以按偏好任选其一。从源码看,这两套剖析均由环境变量开关控制,并在 Actor 的执行循环入口统一挂载,见 python/ray/dag/compiled_dag_node.py 中的do_exec_tasks实现。
PyTorch Profiler:一行环境变量开启 Torch 追踪
开启方式
PyTorch 剖析是成本最低的切入方式:运行脚本前设置环境变量RAY_CGRAPH_ENABLE_TORCH_PROFILING=1即可。例如对于编译图脚本example.py:
RAY_CGRAPH_ENABLE_TORCH_PROFILING=1 python3 example.py无需修改任何业务代码。从 python/ray/dag/constants.py 可以看到该开关的定义:
# Feature flag to turn on torch profiling. # This cannot be used together with RAY_CGRAPH_ENABLE_NVTX_PROFILING. RAY_CGRAPH_ENABLE_TORCH_PROFILING = ( os.environ.get("RAY_CGRAPH_ENABLE_TORCH_PROFILING", "0") == "1" )底层实现:执行循环中挂载 torch.profiler
开启后,每个 Actor 的do_exec_tasks执行循环会在进入无限调度循环前启动torch.profiler.profile,并同时采集 CPU 与 CUDA 活动、记录调用栈,通过 TensorBoard trace handler 落盘,见 python/ray/dag/compiled_dag_node.py:
if RAY_CGRAPH_ENABLE_TORCH_PROFILING: assert ( not RAY_CGRAPH_ENABLE_NVTX_PROFILING ), "NVTX and torch profiling cannot be enabled at the same time." import torch torch_profile = torch.profiler.profile( activities=[ torch.profiler.ProfilerActivity.CPU, torch.profiler.ProfilerActivity.CUDA, ], with_stack=True, on_trace_ready=torch.profiler.tensorboard_trace_handler( "compiled_graph_torch_profiles" ), ) torch_profile.start()要点:
- 每个参与编译图的 Actor 都会各自启动一个 profile 实例,因此每个 Actor 生成一份独立的 trace 文件;
- 结果输出到当前工作目录下的
compiled_graph_torch_profiles目录; with_stack=True会记录 Python 调用栈,方便定位到用户方法;- 同时采集 CPU 与 CUDA 活动,可观察 GPU 内核执行与 CPU 侧调度的时间关系。
查看与可视化 trace
运行结束后,用浏览器打开 https://ui.perfetto.dev/(Perfetto UI),将compiled_graph_torch_profiles目录下的 trace 文件拖入即可查看时间线。通过对比各 Actor 的时间线,可以直观发现:
- 某个 Actor 的执行循环是否长时间处于空闲(等待上游数据/通信通道);
- 方法调用与 NCCL 传输在时间轴上的重叠程度;
- 单个 task 在 CPU 与 GPU 上的耗时构成。
Nsight Systems:通过 runtime_env 启用系统级剖析
前置:为 Actor 配置 nsight runtime_env
Compiled Graph 建立在 Ray 既有 profiling 能力之上。要开启 Nsight 剖析,不需要改脚本执行方式,而是为涉及的 Actor 指定runtime_env={"nsight": ...},具体配置方式参考 Ray 的 Nsight 使用说明。nsight配置项可以是字符串"default"(使用默认配置),也可以是 Nsight Systems 选项的字典,参见 doc/source/ray-core/handling-dependencies.rst 对 runtime_envnsight键的说明。
完整示例:构建编译图并执行
以下代码来自仓库示例 doc/source/ray-core/doc_code/cgraph_profiling.py,先创建带 Nsight runtime_env 的 GPU Actor:
import ray import torch from ray.dag import InputNode @ray.remote(num_gpus=1, runtime_env={"nsight": "default"}) class RayActor: def send(self, shape, dtype, value: int): return torch.ones(shape, dtype=dtype, device="cuda") * value def recv(self, tensor): return (tensor[0].item(), tensor.shape, tensor.dtype) sender = RayActor.remote() receiver = RayActor.remote()然后按常规方式构建并编译 DAG,注意这里通过with_tensor_transport(transport="nccl")指定张量走 NCCL 通道传输:
shape = (10,) dtype = torch.float16 # Test normal execution. with InputNode() as inp: dag = sender.send.bind(inp.shape, inp.dtype, inp[0]) dag = dag.with_tensor_transport(transport="nccl") dag = receiver.recv.bind(dag) compiled_dag = dag.experimental_compile() for i in range(3): shape = (10 * (i + 1),) ref = compiled_dag.execute(i, shape=shape, dtype=dtype) assert ray.get(ref) == (i, shape, dtype)最后按常规方式运行脚本:
python3 example.py执行结束后,Compiled Graph 会将剖析结果输出到/tmp/ray/session_*/logs/{profiler_name}目录下(session_*为本次 Ray 会话目录,{profiler_name}为 profiler 名称)。
NVTX:细粒度方法级标注
如果希望对方法调用与系统开销做更细粒度的分析,可额外设置环境变量:
RAY_CGRAPH_ENABLE_NVTX_PROFILING=1 python3 example.py该开关在 python/ray/dag/constants.py 中定义。开启后,Compiled Graph 在底层利用 NVTX(NVIDIA Tools Extension Library)自动为编译图各 Actor 执行循环中调用的所有方法添加标注,使 Nsight Systems 时间线上能清晰地区分每个方法调用的起止,见 python/ray/dag/compiled_dag_node.py:
if RAY_CGRAPH_ENABLE_NVTX_PROFILING: assert ( not RAY_CGRAPH_ENABLE_TORCH_PROFILING ), "NVTX and torch profiling cannot be enabled at the same time." try: import nvtx except ImportError: raise ImportError( "Please install nvtx to enable nsight profiling. " "You can install it by running `pip install nvtx`." ) nvtx_profile = nvtx.Profile() nvtx_profile.enable()需要注意的是:
- 使用 NVTX 剖析前需要安装
nvtx包:pip install nvtx; - NVTX 与 Torch profiling 二者互斥,不能同时开启(源码中通过
assert强制校验); - 剖析结果的查看方式与 Ray 常规的 Nsight 剖析结果相同,即打开 Nsight Systems 分析
/tmp/ray/session_*/logs/{profiler_name}下的结果文件。
三种 profiling 开关小结
| 环境变量 | 作用 | 输出位置 | 依赖 | 备注 |
|---|---|---|---|---|
RAY_CGRAPH_ENABLE_TORCH_PROFILING=1 | 启动 torch.profiler,采集 CPU/CUDA 活动 | 当前目录compiled_graph_torch_profiles/,每个 Actor 一份 trace | torch | 与 NVTX 互斥 |
runtime_envnsight: "default" | 启动 Nsight Systems 系统级剖析 | /tmp/ray/session_*/logs/{profiler_name} | Nsight Systems | 通过 runtime_env 配置 |
RAY_CGRAPH_ENABLE_NVTX_PROFILING=1 | NVTX 自动标注执行循环中的方法调用 | 随 Nsight 结果一起 | pip install nvtx | 与 Torch profiling 互斥 |
可视化编译图结构
基本用法
剖析着眼于"时间",而理解"结构"则需要可视化。在调用experimental_compile()编译图之后,调用CompiledDAG.visualize()即可将图结构导出。来自 doc/source/ray-core/doc_code/cgraph_visualize.py 的完整示例:
import ray from ray.dag import InputNode, MultiOutputNode @ray.remote class Worker: def inc(self, x): return x + 1 def double(self, x): return x * 2 def echo(self, x): return x sender1 = Worker.remote() sender2 = Worker.remote() receiver = Worker.remote() with InputNode() as inp: w1 = sender1.inc.bind(inp) w1 = receiver.echo.bind(w1) w2 = sender2.double.bind(inp) w2 = receiver.echo.bind(w2) dag = MultiOutputNode([w1, w2]) compiled_dag = dag.experimental_compile() compiled_dag.visualize()默认情况下,Ray 会在当前工作目录生成名为compiled_graph.png的 PNG 图片。注意这需要安装graphviz(pip install graphviz),否则会抛出 ImportError,见 python/ray/dag/compiled_dag_node.py。
接口签名与参数
visualize()的完整签名(来自 python/ray/dag/compiled_dag_node.py):
def visualize( self, filename: str = "compiled_graph", format: str = "png", view: bool = False, channel_details: bool = False, ) -> str:| 参数 | 默认值 | 说明 |
|---|---|---|
filename | "compiled_graph" | 输出文件名(不含扩展名);ASCII 格式下该参数被忽略 |
format | "png" | 输出格式,如png、pdf、jpeg;ascii则直接打印到控制台 |
view | False | 非 ASCII 格式下是否用默认查看器打开;ASCII 格式下是否打印并返回 |
channel_details | False | 为True时在边上附加通道类型与细节;与ascii格式不兼容 |
返回值:对 Graphviz 格式(png/pdf/jpeg 等)返回图的 DOT 字符串表示;对 ASCII 格式返回 ASCII 字符串。
读图:节点与边的含义
下面这张图展示了上述示例代码的可视化结果。同一 Actor 的任务使用相同颜色,可以据此快速识别任务所属的 Actor 以及任务间的依赖关系。
结合 python/ray/dag/compiled_dag_node.py 的绘制逻辑,节点标注规则如下:
InputNode(蓝色矩形)与InputAttributeNode(蓝色矩形):图的输入;ClassMethodNode(椭圆,按 Actor 着色):标注为Actor: <类名>、ID: <Actor ID 前 6 位>...、Method: <方法名>,是图中最核心的节点;MultiOutputNode(黄色矩形):图的汇合输出点;- 同色椭圆即属于同一 Actor 的任务,边表示数据流依赖方向;
- 若设置
channel_details=True,边上还会标注通道类型(如 NCCL)与传输细节。
这张图可以帮助你在剖析之前确认:数据流是否如预期地在各 Actor 之间传递、是否存在意外的串行依赖、多个输入分支是否真正并行。
实战建议:如何系统性定位编译图瓶颈
综合以上三套工具,推荐按以下步骤定位 Compiled Graph 的性能瓶颈:
- 先用
visualize()检查结构:确认 DAG 编译结果符合预期(Actor 归属、任务依赖、并行分支),排除结构性问题; - 开启 PyTorch profiling 观察任务级耗时:
RAY_CGRAPH_ENABLE_TORCH_PROFILING=1跑一次,在 Perfetto 中对比各 Actor trace,定位单个 task 的 CPU/GPU 耗时与空闲等待; - 开启 Nsight + NVTX 深入系统开销:为 Actor 配置
runtime_env={"nsight": "default"},配合RAY_CGRAPH_ENABLE_NVTX_PROFILING=1,在 Nsight Systems 中观察调度、通信(NCCL)与用户方法调用的时间线细节; - 交叉验证:注意 NVTX 与 Torch profiling 互斥,两套剖析需要分开运行;剖析本身会引入一定开销,建议用多次运行的平均趋势而非单次结果做结论。
参考路径速查
- 官方文档源文件:doc/source/ray-core/compiled-graph/profiling.rst
- 剖析开关定义:python/ray/dag/constants.py
- 剖析挂载与执行循环实现:python/ray/dag/compiled_dag_node.py
- Nsight 剖析示例:doc/source/ray-core/doc_code/cgraph_profiling.py
- 可视化示例:doc/source/ray-core/doc_code/cgraph_visualize.py
- 可视化输出示例图:doc/source/images/compiled_graph_viz.png
- runtime_env
nsight配置说明:doc/source/ray-core/handling-dependencies.rst
【免费下载链接】rayRay is an AI compute engine. Ray consists of a core distributed runtime and a set of AI Libraries for accelerating ML workloads.项目地址: https://gitcode.com/gh_mirrors/ra/ray
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考