From a7321d394c86feac1626398e8c167419dbc30265 Mon Sep 17 00:00:00 2001 From: Huaiwei Sun Date: Tue, 29 Aug 2023 11:07:00 -0700 Subject: [PATCH 1/9] polish o11y docs Signed-off-by: Huaiwei Sun --- doc/source/_toc.yml | 1 + .../cluster/configure-manage-dashboard.md | 3 + doc/source/images/profile.png | Bin 28715 -> 67422 bytes .../ray-observability/getting-started.rst | 6 ++ doc/source/ray-observability/key-concepts.rst | 7 ++- .../user-guides/debug-apps/debug-hangs.rst | 9 ++- .../user-guides/debug-apps/debug-memory.rst | 1 - .../user-guides/profiling.md | 56 ++++++++++++++++++ 8 files changed, 74 insertions(+), 9 deletions(-) create mode 100644 doc/source/ray-observability/user-guides/profiling.md diff --git a/doc/source/_toc.yml b/doc/source/_toc.yml index a6bebfb2022f4..b6e510a58d251 100644 --- a/doc/source/_toc.yml +++ b/doc/source/_toc.yml @@ -371,6 +371,7 @@ parts: - file: ray-observability/user-guides/debug-apps/ray-debugging - file: ray-observability/user-guides/cli-sdk - file: ray-observability/user-guides/configure-logging + - file: ray-observability/user-guides/profiling - file: ray-observability/user-guides/add-app-metrics - file: ray-observability/user-guides/ray-tracing - file: ray-observability/reference/index diff --git a/doc/source/cluster/configure-manage-dashboard.md b/doc/source/cluster/configure-manage-dashboard.md index a2f76de91e926..7a9ecbb50ae5d 100644 --- a/doc/source/cluster/configure-manage-dashboard.md +++ b/doc/source/cluster/configure-manage-dashboard.md @@ -204,6 +204,9 @@ Configure these settings using the `RAY_GRAFANA_HOST`, `RAY_PROMETHEUS_HOST`, `R * Set `RAY_GRAFANA_IFRAME_HOST` to an address that the user's browsers can use to access Grafana and embed visualizations. If `RAY_GRAFANA_IFRAME_HOST` is not set, Ray Dashboard uses the value of `RAY_GRAFANA_HOST`. For example, if the IP of the head node is 55.66.77.88 and Grafana is hosted on port 3000. Set the value to `RAY_GRAFANA_HOST=http://55.66.77.88:3000`. +* If you start a single-node Ray Cluster manually, make sure these environment variables are set and accessible before you start the cluster or as a prefix to the `ray start ...` command. +* If you start a Ray Cluster with {ref}`VM Cluster Launcher `, the environment variables should be set under `head_start_ray_commands` as a prefix to the `ray start ...` command. +* If you start a Ray Cluster with {ref}`KubeRay `, refer to this {ref}`tutorial `. If all the environment variables are set properly, you should see time-series metrics in {ref}`Ray Dashboard `. diff --git a/doc/source/images/profile.png b/doc/source/images/profile.png index bdefdd1c30c4fcabf6e02ca793526fe2b9267833..4389f8bf48c35c823fa9e9fd7c53bce951e73797 100644 GIT binary patch literal 67422 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˛H$Ka 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%0DBkv&_+c!N(wSAo0WO>7p>gAt|S{1L}%Sbfk# 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 deo(dR+&h#o_x7Q@!-upZE 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, :ref:`KubeRay operator `, or manual configuration, Ray Dashboard launches on the head node but the dashboard port may not be publicly exposed. View :ref:`configuring the dashboard ` for how to view Dashboard from outside the Head Node. .. note:: diff --git a/doc/source/ray-observability/key-concepts.rst b/doc/source/ray-observability/key-concepts.rst index 3ea0728c4afd6..3a1b384e47831 100644 --- a/doc/source/ray-observability/key-concepts.rst +++ b/doc/source/ray-observability/key-concepts.rst @@ -75,11 +75,12 @@ Profiling --------- Profiling is way of analyzing the performance of an application by sampling the resource usage of it. Ray supports various profiling tools: -- CPU profiling for Worker processes, including integration with :ref:`py-spy ` and :ref:`cProfile ` -- Memory profiling for Worker processes with :ref:`memray ` +- CPU profiling for Driver and Worker processes, including integration with :ref:`py-spy ` and :ref:`cProfile ` +- Memory profiling for Driver and Worker processes with :ref:`memray ` - Built in Task and Actor profiling tool called :ref:`ray timeline ` +- GPU profiling with `Pytorch Profiler`_ -Ray doesn't provide native integration with GPU profiling tools. Try running GPU profilers like `Pytorch Profiler`_ without Ray to identify the issues. +View :ref:`Profiling ` for more details. Note that this list is not comprehensive and feel free to contribute to it if you find other useful tools. .. _`Pytorch Profiler`: https://pytorch.org/tutorials/recipes/recipes/profiler_recipe.html diff --git a/doc/source/ray-observability/user-guides/debug-apps/debug-hangs.rst b/doc/source/ray-observability/user-guides/debug-apps/debug-hangs.rst index ca3cb66ae1941..9c702cbccc2f0 100644 --- a/doc/source/ray-observability/user-guides/debug-apps/debug-hangs.rst +++ b/doc/source/ray-observability/user-guides/debug-apps/debug-hangs.rst @@ -4,8 +4,7 @@ Debugging Hangs =============== View stack traces in Ray Dashboard ----------------------------------- -The :ref:`Ray dashboard ` lets you profile Ray worker processes by clicking on the "Stack Trace" -actions for active worker processes, actors, and job's driver process. +The :ref:`Ray dashboard ` lets you profile Ray Driver or Worker processes, by clicking on the "CPU profiling" or "Stack Trace" actions for active Worker processes, Tasks, Actors, and Job's driver process. .. image:: /images/profile.png :align: center @@ -19,7 +18,7 @@ trace is shown. To show native code frames, set the URL parameter ``native=1`` ( :width: 60% .. note:: - If you run Ray in a Docker container, you may run into permission errors when viewing the stack traces. Follow the `py-spy documentation`_ to resolve it. + If you run Ray in a Docker container, you may run into permission errors when viewing the stack traces. Follow the `py-spy documentation`_ to resolve it. If you are a KubeRay user, here is the guide for how to :ref:`configure KubeRay and apply the solution `. .. _`py-spy documentation`: https://github.com/benfred/py-spy#how-do-i-run-py-spy-in-docker @@ -27,8 +26,8 @@ trace is shown. To show native code frames, set the URL parameter ``native=1`` ( Use ``ray stack`` CLI command ------------------------------ -You can run ``ray stack`` to dump the stack traces of all Ray Worker processes on -the current node. This requires ``py-spy`` to be installed. +Once ``py-spy`` is installed, you can run ``ray stack`` to dump the stack traces of all Ray Worker processes on +the current node. This document discusses some common problems that people run into when using Ray as well as some known problems. If you encounter other problems, please diff --git a/doc/source/ray-observability/user-guides/debug-apps/debug-memory.rst b/doc/source/ray-observability/user-guides/debug-apps/debug-memory.rst index 0fb6c97aec999..f6b8b84f5fd7e 100644 --- a/doc/source/ray-observability/user-guides/debug-apps/debug-memory.rst +++ b/doc/source/ray-observability/user-guides/debug-apps/debug-memory.rst @@ -173,7 +173,6 @@ It is also possible tasks and actors use more memory than you expect. For exampl View the instructions below to learn how to memory profile individual actors and tasks. - .. _memray-profiling: Memory Profiling Ray tasks and actors diff --git a/doc/source/ray-observability/user-guides/profiling.md b/doc/source/ray-observability/user-guides/profiling.md new file mode 100644 index 0000000000000..6086ecbc8ed97 --- /dev/null +++ b/doc/source/ray-observability/user-guides/profiling.md @@ -0,0 +1,56 @@ +(profiling)= +# Profiling +Profiling is one of the most important debugging tools to diagnose performance, out of memory, hanging, or other application issues. +Here is a list of common profiling tools you may use when debugging Ray applications. +- CPU profiling + - py-spy +- Memory profiling + - memray +- GPU profiling + - PyTorch Profiler +- Ray Task / Actor profiling + - Ray Timeline + +If Ray doesn't work with certain profiling tools, try running them without Ray to debug the issues. + +## CPU profiling +CPU profiling for Driver and Worker processes. This helps you understand the CPU usage by different processes and debug unexpectedly high or low usage. + +### py-spy +[py-spy](https://github.com/benfred/py-spy/tree/master) is a sampling profiler for Python programs. It lets you visualize what your Python program is spending time on without restarting the program or modifying the code in any way. + +:::{note} + If you run Ray in a Docker container, you may run into permission errors when viewing the stack traces. Follow the [solution in the py-spy documentation](https://github.com/benfred/py-spy#how-do-i-run-py-spy-in-docker) to resolve it. If you are a KubeRay user, here is the guide for how to {ref}`configure KubeRay and apply the solution `. +::: + +Here are the {ref}`steps to use py-spy with Ray `. + + +## Memory profiling +Memory profiling for Driver and Worker processes. This helps you analyze memory allocations in applications, trace memory leaks, and debug high/low memory or out of memory issues. + +### memray +memray is a memory profiler for Python. It can track memory allocations in Python code, in native extension modules, and in the Python interpreter itself. + +Here are the {ref}`steps to profile the memory usage of Ray Tasks and Actors `. + + +## GPU profiling +GPU and GRAM profiling for your GPU workloads like distributed training. This helps you analyze performance and debug memory issues. +- PyTorch profiler is supported out of box when used with Ray Train +- NVIDIA Nsight System is not natively supported yet. Leave your comments in this [feature request for Nisght System support](https://github.com/ray-project/ray/issues/19631). + +### PyTorch Profiler +Here are the steps to use PyTorch Profiler with Ray Train: +- Follow the [PyTorch Profiler documentation]( https://pytorch.org/tutorials/intermediate/tensorboard_profiler_tutorial.html) to record events in your PyTorch code. +- {ref}`Convert your PyTorch script to a Ray Train script `. (no change to your profiler-related code) +- Run your Ray Train script +- Collect the profiling results from all the nodes (compared to 1 node in a non-distributed setting) + - You may want to upload results on each Node to NFS or object storage like S3 so that you don't have to fetch results from each Node. +- Visualize the results with tools like Tensorboard. + +## Ray Task / Actor profiling +Profiling the execution time of Ray Tasks and Actors. This helps you analyze performance, identify the stragglers, and understand the distribution of workloads. + +### Ray Timeline +Open your Ray Job in Ray Dashboard and follow the {ref}`instructions to download and visualize the trace files ` generated by Ray Timeline. \ No newline at end of file From fc4d3dbadf4d4e1ee7d25fc63f9c59e45fb72af2 Mon Sep 17 00:00:00 2001 From: Huaiwei Sun Date: Wed, 30 Aug 2023 13:18:56 -0700 Subject: [PATCH 2/9] address comments Signed-off-by: Huaiwei Sun --- .../cluster/configure-manage-dashboard.md | 2 +- doc/source/ray-observability/key-concepts.rst | 9 +++-- .../user-guides/debug-apps/debug-hangs.rst | 6 ++-- .../debug-apps/optimize-performance.rst | 21 +++++++++--- .../user-guides/profiling.md | 33 ++++++++++++------- 5 files changed, 47 insertions(+), 24 deletions(-) diff --git a/doc/source/cluster/configure-manage-dashboard.md b/doc/source/cluster/configure-manage-dashboard.md index 7a9ecbb50ae5d..7e992dc82abcb 100644 --- a/doc/source/cluster/configure-manage-dashboard.md +++ b/doc/source/cluster/configure-manage-dashboard.md @@ -204,7 +204,7 @@ Configure these settings using the `RAY_GRAFANA_HOST`, `RAY_PROMETHEUS_HOST`, `R * Set `RAY_GRAFANA_IFRAME_HOST` to an address that the user's browsers can use to access Grafana and embed visualizations. If `RAY_GRAFANA_IFRAME_HOST` is not set, Ray Dashboard uses the value of `RAY_GRAFANA_HOST`. For example, if the IP of the head node is 55.66.77.88 and Grafana is hosted on port 3000. Set the value to `RAY_GRAFANA_HOST=http://55.66.77.88:3000`. -* If you start a single-node Ray Cluster manually, make sure these environment variables are set and accessible before you start the cluster or as a prefix to the `ray start ...` command. +* If you start a single-node Ray Cluster manually, make sure these environment variables are set and accessible before you start the cluster or as a prefix to the `ray start ...` command, e.g., `RAY_GRAFANA_HOST=http://55.66.77.88:3000 ray start ...` * If you start a Ray Cluster with {ref}`VM Cluster Launcher `, the environment variables should be set under `head_start_ray_commands` as a prefix to the `ray start ...` command. * If you start a Ray Cluster with {ref}`KubeRay `, refer to this {ref}`tutorial `. diff --git a/doc/source/ray-observability/key-concepts.rst b/doc/source/ray-observability/key-concepts.rst index 3a1b384e47831..57ea93f5bbcd6 100644 --- a/doc/source/ray-observability/key-concepts.rst +++ b/doc/source/ray-observability/key-concepts.rst @@ -75,14 +75,13 @@ Profiling --------- Profiling is way of analyzing the performance of an application by sampling the resource usage of it. Ray supports various profiling tools: -- CPU profiling for Driver and Worker processes, including integration with :ref:`py-spy ` and :ref:`cProfile ` -- Memory profiling for Driver and Worker processes with :ref:`memray ` -- Built in Task and Actor profiling tool called :ref:`ray timeline ` -- GPU profiling with `Pytorch Profiler`_ +- CPU profiling for Driver and Worker processes, including integration with :ref:`py-spy ` and :ref:`cProfile ` +- Memory profiling for Driver and Worker processes with :ref:`memray ` +- GPU profiling with :ref:`Pytorch Profiler ` +- Built in Task and Actor profiling tool called :ref:`Ray Timeline ` View :ref:`Profiling ` for more details. Note that this list is not comprehensive and feel free to contribute to it if you find other useful tools. -.. _`Pytorch Profiler`: https://pytorch.org/tutorials/recipes/recipes/profiler_recipe.html Tracing ------- diff --git a/doc/source/ray-observability/user-guides/debug-apps/debug-hangs.rst b/doc/source/ray-observability/user-guides/debug-apps/debug-hangs.rst index 9c702cbccc2f0..073bd890041a3 100644 --- a/doc/source/ray-observability/user-guides/debug-apps/debug-hangs.rst +++ b/doc/source/ray-observability/user-guides/debug-apps/debug-hangs.rst @@ -18,7 +18,9 @@ trace is shown. To show native code frames, set the URL parameter ``native=1`` ( :width: 60% .. note:: - If you run Ray in a Docker container, you may run into permission errors when viewing the stack traces. Follow the `py-spy documentation`_ to resolve it. If you are a KubeRay user, here is the guide for how to :ref:`configure KubeRay and apply the solution `. + You may run into permission errors when using pyspy in the docker containers. To fix the issue: + - if you start Ray manually in a Docker container, follow the `py-spy documentation`_ to resolve it. + - if you are a KubeRay user, follow the :ref:`guide to configure KubeRay ` and resolve it. .. _`py-spy documentation`: https://github.com/benfred/py-spy#how-do-i-run-py-spy-in-docker @@ -26,7 +28,7 @@ trace is shown. To show native code frames, set the URL parameter ``native=1`` ( Use ``ray stack`` CLI command ------------------------------ -Once ``py-spy`` is installed, you can run ``ray stack`` to dump the stack traces of all Ray Worker processes on +Once ``py-spy`` is installed (it is automatically installed if "Ray Dashboard" component is included when :ref:`installing Ray `), you can run ``ray stack`` to dump the stack traces of all Ray Worker processes on the current node. This document discusses some common problems that people run into when using Ray diff --git a/doc/source/ray-observability/user-guides/debug-apps/optimize-performance.rst b/doc/source/ray-observability/user-guides/debug-apps/optimize-performance.rst index 48bd1990f97f8..7dca45ed4f4d7 100644 --- a/doc/source/ray-observability/user-guides/debug-apps/optimize-performance.rst +++ b/doc/source/ray-observability/user-guides/debug-apps/optimize-performance.rst @@ -324,14 +324,25 @@ Our example in total now takes only 1.5 seconds to run: 20 0.001 0.000 0.001 0.000 worker.py:514(submit_task) ... -GPU Profiling + +.. _performance-debugging-gpu-profiling: + +GPU Profiling with PyTorch Profiler ------------------------ -Ray doesn't provide native integration with GPU profiling tools. Try running GPU profilers like `Pytorch Profiler`_ without Ray to identify the issues. +Here are the steps to use PyTorch Profiler with Ray Train: -If you have related feature requests, `let us know`_. +* Follow the `PyTorch Profiler documentation `_ to record events in your PyTorch code. + +* :ref:`Convert your PyTorch script to a Ray Train script `. (no change to your profiler-related code) + +* Run your Ray Train script + +* Collect the profiling results from all the nodes (compared to 1 node in a non-distributed setting) + + * You may want to upload results on each Node to NFS or object storage like S3 so that you don't have to fetch results from each Node. + +* Visualize the results with tools like Tensorboard. -.. _`let us know`: https://github.com/ray-project/ray/issues -.. _`Pytorch Profiler`: https://pytorch.org/tutorials/recipes/recipes/profiler_recipe.html Profiling for Developers ------------------------ diff --git a/doc/source/ray-observability/user-guides/profiling.md b/doc/source/ray-observability/user-guides/profiling.md index 6086ecbc8ed97..38f34527bbb70 100644 --- a/doc/source/ray-observability/user-guides/profiling.md +++ b/doc/source/ray-observability/user-guides/profiling.md @@ -13,44 +13,55 @@ Here is a list of common profiling tools you may use when debugging Ray applicat If Ray doesn't work with certain profiling tools, try running them without Ray to debug the issues. +(profiling-cpu)= ## CPU profiling CPU profiling for Driver and Worker processes. This helps you understand the CPU usage by different processes and debug unexpectedly high or low usage. +(profiling-pyspy)= ### py-spy -[py-spy](https://github.com/benfred/py-spy/tree/master) is a sampling profiler for Python programs. It lets you visualize what your Python program is spending time on without restarting the program or modifying the code in any way. +[py-spy](https://github.com/benfred/py-spy/tree/master) is a sampling profiler for Python programs. Ray Dashboard has native integration with pyspy: + +- It lets you visualize what your Python program is spending time on without restarting the program or modifying the code in any way. +- It dumps the stacktrace of the running process so that you can see what the process is doing at a certain time. It is useful when programs hangs. :::{note} If you run Ray in a Docker container, you may run into permission errors when viewing the stack traces. Follow the [solution in the py-spy documentation](https://github.com/benfred/py-spy#how-do-i-run-py-spy-in-docker) to resolve it. If you are a KubeRay user, here is the guide for how to {ref}`configure KubeRay and apply the solution `. ::: -Here are the {ref}`steps to use py-spy with Ray `. +Here are the {ref}`steps to use py-spy with Ray and Ray Dashboard `. + +(profiling-cprofile)= +### cProfile +cProfile is Python’s native profiling module to profile the performance of your Ray application. +Here are the {ref}`steps to use cProfile `. +(profiling-memory)= ## Memory profiling Memory profiling for Driver and Worker processes. This helps you analyze memory allocations in applications, trace memory leaks, and debug high/low memory or out of memory issues. +(profiling-memray)= ### memray memray is a memory profiler for Python. It can track memory allocations in Python code, in native extension modules, and in the Python interpreter itself. Here are the {ref}`steps to profile the memory usage of Ray Tasks and Actors `. - +(profiling-gpu)= ## GPU profiling GPU and GRAM profiling for your GPU workloads like distributed training. This helps you analyze performance and debug memory issues. - PyTorch profiler is supported out of box when used with Ray Train - NVIDIA Nsight System is not natively supported yet. Leave your comments in this [feature request for Nisght System support](https://github.com/ray-project/ray/issues/19631). +(profiling-pytoch-profiler)= ### PyTorch Profiler -Here are the steps to use PyTorch Profiler with Ray Train: -- Follow the [PyTorch Profiler documentation]( https://pytorch.org/tutorials/intermediate/tensorboard_profiler_tutorial.html) to record events in your PyTorch code. -- {ref}`Convert your PyTorch script to a Ray Train script `. (no change to your profiler-related code) -- Run your Ray Train script -- Collect the profiling results from all the nodes (compared to 1 node in a non-distributed setting) - - You may want to upload results on each Node to NFS or object storage like S3 so that you don't have to fetch results from each Node. -- Visualize the results with tools like Tensorboard. +PyTorch Profiler is a tool that allows the collection of performance metrics (especially GPU metrics) during training and inference. + +Here are the {ref}`steps to use PyTorch Profiler with Ray Train `. +(profiling-task_actor)= ## Ray Task / Actor profiling Profiling the execution time of Ray Tasks and Actors. This helps you analyze performance, identify the stragglers, and understand the distribution of workloads. +(profiling-timeline)= ### Ray Timeline -Open your Ray Job in Ray Dashboard and follow the {ref}`instructions to download and visualize the trace files ` generated by Ray Timeline. \ No newline at end of file +Open your Ray Job in Ray Dashboard and follow the {ref}`instructions to download and visualize the trace files ` generated by Ray Timeline. From 7dc13780385143b4e3227ff004f5bb34c722d73a Mon Sep 17 00:00:00 2001 From: Huaiwei Sun Date: Wed, 30 Aug 2023 13:52:23 -0700 Subject: [PATCH 3/9] fix test Signed-off-by: Huaiwei Sun --- .../user-guides/debug-apps/debug-hangs.rst | 7 ++++--- .../debug-apps/optimize-performance.rst | 17 ++++++++++------- .../ray-observability/user-guides/profiling.md | 2 +- 3 files changed, 15 insertions(+), 11 deletions(-) diff --git a/doc/source/ray-observability/user-guides/debug-apps/debug-hangs.rst b/doc/source/ray-observability/user-guides/debug-apps/debug-hangs.rst index 073bd890041a3..4298e297678bd 100644 --- a/doc/source/ray-observability/user-guides/debug-apps/debug-hangs.rst +++ b/doc/source/ray-observability/user-guides/debug-apps/debug-hangs.rst @@ -18,9 +18,10 @@ trace is shown. To show native code frames, set the URL parameter ``native=1`` ( :width: 60% .. note:: - You may run into permission errors when using pyspy in the docker containers. To fix the issue: - - if you start Ray manually in a Docker container, follow the `py-spy documentation`_ to resolve it. - - if you are a KubeRay user, follow the :ref:`guide to configure KubeRay ` and resolve it. + You may run into permission errors when using py-spy in the docker containers. To fix the issue: + * if you start Ray manually in a Docker container, follow the `py-spy documentation`_ to resolve it. + + * if you are a KubeRay user, follow the :ref:`guide to configure KubeRay ` and resolve it. .. _`py-spy documentation`: https://github.com/benfred/py-spy#how-do-i-run-py-spy-in-docker diff --git a/doc/source/ray-observability/user-guides/debug-apps/optimize-performance.rst b/doc/source/ray-observability/user-guides/debug-apps/optimize-performance.rst index 7dca45ed4f4d7..cf4ad07fb4b2d 100644 --- a/doc/source/ray-observability/user-guides/debug-apps/optimize-performance.rst +++ b/doc/source/ray-observability/user-guides/debug-apps/optimize-performance.rst @@ -115,8 +115,11 @@ not have root permissions, the Dashboard prompts with instructions on how to set Alternatively, you can start Ray with passwordless sudo / root permissions. .. note:: - If you run Ray in a Docker container, you may run into permission errors when using py-spy. Follow the `py-spy documentation`_ to resolve it. + You may run into permission errors when using py-spy in the docker containers. To fix the issue: + * if you start Ray manually in a Docker container, follow the `py-spy documentation`_ to resolve it. + * if you are a KubeRay user, follow the :ref:`guide to configure KubeRay ` and resolve it. + .. _`py-spy documentation`: https://github.com/benfred/py-spy#how-do-i-run-py-spy-in-docker @@ -328,18 +331,18 @@ Our example in total now takes only 1.5 seconds to run: .. _performance-debugging-gpu-profiling: GPU Profiling with PyTorch Profiler ------------------------- -Here are the steps to use PyTorch Profiler with Ray Train: +----------------------------------- +Here are the steps to use PyTorch Profiler during training with Ray Train or batch inference with Ray Data: * Follow the `PyTorch Profiler documentation `_ to record events in your PyTorch code. -* :ref:`Convert your PyTorch script to a Ray Train script `. (no change to your profiler-related code) +* Convert your PyTorch script to a :ref:`Ray Train training script ` or a :ref:`Ray Data batch inference script `. (no change to your profiler-related code) -* Run your Ray Train script +* Run your training or batch inference script. -* Collect the profiling results from all the nodes (compared to 1 node in a non-distributed setting) +* Collect the profiling results from all the nodes (compared to 1 node in a non-distributed setting). - * You may want to upload results on each Node to NFS or object storage like S3 so that you don't have to fetch results from each Node. + * You may want to upload results on each Node to NFS or object storage like S3 so that you don't have to fetch results from each Node respectively. * Visualize the results with tools like Tensorboard. diff --git a/doc/source/ray-observability/user-guides/profiling.md b/doc/source/ray-observability/user-guides/profiling.md index 38f34527bbb70..3f7aeb1a794ee 100644 --- a/doc/source/ray-observability/user-guides/profiling.md +++ b/doc/source/ray-observability/user-guides/profiling.md @@ -56,7 +56,7 @@ GPU and GRAM profiling for your GPU workloads like distributed training. This he ### PyTorch Profiler PyTorch Profiler is a tool that allows the collection of performance metrics (especially GPU metrics) during training and inference. -Here are the {ref}`steps to use PyTorch Profiler with Ray Train `. +Here are the {ref}`steps to use PyTorch Profiler with Ray Train or Ray Data `. (profiling-task_actor)= ## Ray Task / Actor profiling From d0c197f547087d4f0a0c7c08300b39bd4ee8be44 Mon Sep 17 00:00:00 2001 From: Huaiwei Sun Date: Wed, 30 Aug 2023 15:29:45 -0700 Subject: [PATCH 4/9] fixups Signed-off-by: Huaiwei Sun --- .../ray-observability/user-guides/debug-apps/debug-hangs.rst | 2 +- .../user-guides/debug-apps/optimize-performance.rst | 2 +- doc/source/ray-observability/user-guides/profiling.md | 5 ++++- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/doc/source/ray-observability/user-guides/debug-apps/debug-hangs.rst b/doc/source/ray-observability/user-guides/debug-apps/debug-hangs.rst index 4298e297678bd..762fca65ac8e0 100644 --- a/doc/source/ray-observability/user-guides/debug-apps/debug-hangs.rst +++ b/doc/source/ray-observability/user-guides/debug-apps/debug-hangs.rst @@ -19,8 +19,8 @@ trace is shown. To show native code frames, set the URL parameter ``native=1`` ( .. note:: You may run into permission errors when using py-spy in the docker containers. To fix the issue: + * if you start Ray manually in a Docker container, follow the `py-spy documentation`_ to resolve it. - * if you are a KubeRay user, follow the :ref:`guide to configure KubeRay ` and resolve it. .. _`py-spy documentation`: https://github.com/benfred/py-spy#how-do-i-run-py-spy-in-docker diff --git a/doc/source/ray-observability/user-guides/debug-apps/optimize-performance.rst b/doc/source/ray-observability/user-guides/debug-apps/optimize-performance.rst index cf4ad07fb4b2d..163bb36a599c6 100644 --- a/doc/source/ray-observability/user-guides/debug-apps/optimize-performance.rst +++ b/doc/source/ray-observability/user-guides/debug-apps/optimize-performance.rst @@ -116,8 +116,8 @@ not have root permissions, the Dashboard prompts with instructions on how to set .. note:: You may run into permission errors when using py-spy in the docker containers. To fix the issue: + * if you start Ray manually in a Docker container, follow the `py-spy documentation`_ to resolve it. - * if you are a KubeRay user, follow the :ref:`guide to configure KubeRay ` and resolve it. .. _`py-spy documentation`: https://github.com/benfred/py-spy#how-do-i-run-py-spy-in-docker diff --git a/doc/source/ray-observability/user-guides/profiling.md b/doc/source/ray-observability/user-guides/profiling.md index 3f7aeb1a794ee..0f6b6ff3ac7f1 100644 --- a/doc/source/ray-observability/user-guides/profiling.md +++ b/doc/source/ray-observability/user-guides/profiling.md @@ -25,7 +25,10 @@ CPU profiling for Driver and Worker processes. This helps you understand the CPU - It dumps the stacktrace of the running process so that you can see what the process is doing at a certain time. It is useful when programs hangs. :::{note} - If you run Ray in a Docker container, you may run into permission errors when viewing the stack traces. Follow the [solution in the py-spy documentation](https://github.com/benfred/py-spy#how-do-i-run-py-spy-in-docker) to resolve it. If you are a KubeRay user, here is the guide for how to {ref}`configure KubeRay and apply the solution `. +You may run into permission errors when using py-spy in the docker containers. To fix the issue: + +- if you start Ray manually in a Docker container, follow the `py-spy documentation`_ to resolve it. +- if you are a KubeRay user, follow the :ref:`guide to configure KubeRay ` and resolve it. ::: Here are the {ref}`steps to use py-spy with Ray and Ray Dashboard `. From 1500ac6c4671192af1a6298014f4ab48edd9d744 Mon Sep 17 00:00:00 2001 From: Huaiwei Sun Date: Wed, 6 Sep 2023 10:25:56 -0700 Subject: [PATCH 5/9] address comments Signed-off-by: Huaiwei Sun --- doc/source/ray-observability/key-concepts.rst | 2 +- doc/source/ray-observability/user-guides/profiling.md | 9 +++------ 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/doc/source/ray-observability/key-concepts.rst b/doc/source/ray-observability/key-concepts.rst index 57ea93f5bbcd6..962c08705f818 100644 --- a/doc/source/ray-observability/key-concepts.rst +++ b/doc/source/ray-observability/key-concepts.rst @@ -80,7 +80,7 @@ Profiling is way of analyzing the performance of an application by sampling the - GPU profiling with :ref:`Pytorch Profiler ` - Built in Task and Actor profiling tool called :ref:`Ray Timeline ` -View :ref:`Profiling ` for more details. Note that this list is not comprehensive and feel free to contribute to it if you find other useful tools. +View :ref:`Profiling ` for more details. Note that this list isn't comprehensive and feel free to contribute to it if you find other useful tools. Tracing diff --git a/doc/source/ray-observability/user-guides/profiling.md b/doc/source/ray-observability/user-guides/profiling.md index 0f6b6ff3ac7f1..eb1e3d169d800 100644 --- a/doc/source/ray-observability/user-guides/profiling.md +++ b/doc/source/ray-observability/user-guides/profiling.md @@ -8,8 +8,7 @@ Here is a list of common profiling tools you may use when debugging Ray applicat - memray - GPU profiling - PyTorch Profiler -- Ray Task / Actor profiling - - Ray Timeline +- Ray Task / Actor timeline If Ray doesn't work with certain profiling tools, try running them without Ray to debug the issues. @@ -61,10 +60,8 @@ PyTorch Profiler is a tool that allows the collection of performance metrics (es Here are the {ref}`steps to use PyTorch Profiler with Ray Train or Ray Data `. -(profiling-task_actor)= -## Ray Task / Actor profiling +(profiling-timeline)= +## Ray Task / Actor Timeline Profiling the execution time of Ray Tasks and Actors. This helps you analyze performance, identify the stragglers, and understand the distribution of workloads. -(profiling-timeline)= -### Ray Timeline Open your Ray Job in Ray Dashboard and follow the {ref}`instructions to download and visualize the trace files ` generated by Ray Timeline. From 5f79c233034580966402456a5635d2a052b4c697 Mon Sep 17 00:00:00 2001 From: Huaiwei Sun Date: Wed, 6 Sep 2023 10:28:15 -0700 Subject: [PATCH 6/9] fixups Signed-off-by: Huaiwei Sun --- doc/source/ray-observability/user-guides/profiling.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/source/ray-observability/user-guides/profiling.md b/doc/source/ray-observability/user-guides/profiling.md index eb1e3d169d800..efe58daf92941 100644 --- a/doc/source/ray-observability/user-guides/profiling.md +++ b/doc/source/ray-observability/user-guides/profiling.md @@ -61,7 +61,7 @@ PyTorch Profiler is a tool that allows the collection of performance metrics (es Here are the {ref}`steps to use PyTorch Profiler with Ray Train or Ray Data `. (profiling-timeline)= -## Ray Task / Actor Timeline -Profiling the execution time of Ray Tasks and Actors. This helps you analyze performance, identify the stragglers, and understand the distribution of workloads. +## Ray Task / Actor timeline +Profiling the execution time of Ray Tasks and Actors with Ray Timeline. This helps you analyze performance, identify the stragglers, and understand the distribution of workloads. Open your Ray Job in Ray Dashboard and follow the {ref}`instructions to download and visualize the trace files ` generated by Ray Timeline. From e079fabd83c6a1250f58df96dd0c082309bbbc32 Mon Sep 17 00:00:00 2001 From: Huaiwei Sun Date: Wed, 6 Sep 2023 13:27:58 -0700 Subject: [PATCH 7/9] fix link Signed-off-by: Huaiwei Sun --- doc/source/cluster/configure-manage-dashboard.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/source/cluster/configure-manage-dashboard.md b/doc/source/cluster/configure-manage-dashboard.md index 7e992dc82abcb..1655f295c596e 100644 --- a/doc/source/cluster/configure-manage-dashboard.md +++ b/doc/source/cluster/configure-manage-dashboard.md @@ -235,7 +235,7 @@ When both Grafana and the Ray Cluster are on the same Kubernetes cluster, set `R #### User authentication for Grafana -When the Grafana instance requires user authentication, the following settings have to be in its `configuration file `_ to correctly embed in Ray Dashboard: +When the Grafana instance requires user authentication, the following settings have to be in its [configuration file](https://grafana.com/docs/grafana/latest/setup-grafana/configure-grafana/) to correctly embed in Ray Dashboard: ```ini [security] From 3a27ec684c032873c8aad0257762ee4cc303ad69 Mon Sep 17 00:00:00 2001 From: Huaiwei Sun Date: Wed, 6 Sep 2023 19:19:36 -0700 Subject: [PATCH 8/9] address comments and add one troubleshooting tip Signed-off-by: Huaiwei Sun --- doc/source/cluster/configure-manage-dashboard.md | 11 +++++++++-- doc/source/ray-observability/user-guides/profiling.md | 6 +++--- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/doc/source/cluster/configure-manage-dashboard.md b/doc/source/cluster/configure-manage-dashboard.md index 1655f295c596e..dde5128e9d953 100644 --- a/doc/source/cluster/configure-manage-dashboard.md +++ b/doc/source/cluster/configure-manage-dashboard.md @@ -246,8 +246,15 @@ When the Grafana instance requires user authentication, the following settings h #### Troubleshooting -##### Grafana dashboards are not embedded in the Ray dashboard -If you're getting an error that says `RAY_GRAFANA_HOST` is not setup despite having set it up, check that: +##### Dashboard message: either Prometheus or Grafana server is not deteced +If you have followed the instructions above to set up everything, run the connection checks below in your browser: +* check Head Node connection to Prometheus server: add `api/prometheus_health` to the end of Ray Dashboard URL (for example: http://127.0.0.1:8265/api/prometheus_health)and visit it. +* check Head Node connection to Grafana server: add `api/grafana_health` to the end of Ray Dashboard URL (for example: http://127.0.0.1:8265/api/grafana_health) and visit it. +* check browser connection to Grafana server: visit the URL used in `RAY_GRAFANA_IFRAME_HOST`. + + +##### Getting an error that says `RAY_GRAFANA_HOST` is not setup +If you have set up Grafana , check that: * You've included the protocol in the URL (e.g., `http://your-grafana-url.com` instead of `your-grafana-url.com`). * The URL doesn't have a trailing slash (e.g., `http://your-grafana-url.com` instead of `http://your-grafana-url.com/`). diff --git a/doc/source/ray-observability/user-guides/profiling.md b/doc/source/ray-observability/user-guides/profiling.md index efe58daf92941..fe22a33311937 100644 --- a/doc/source/ray-observability/user-guides/profiling.md +++ b/doc/source/ray-observability/user-guides/profiling.md @@ -14,7 +14,7 @@ If Ray doesn't work with certain profiling tools, try running them without Ray t (profiling-cpu)= ## CPU profiling -CPU profiling for Driver and Worker processes. This helps you understand the CPU usage by different processes and debug unexpectedly high or low usage. +Profile the CPU usage for Driver and Worker processes. This helps you understand the CPU usage by different processes and debug unexpectedly high or low usage. (profiling-pyspy)= ### py-spy @@ -40,7 +40,7 @@ Here are the {ref}`steps to use cProfile `. (profiling-memory)= ## Memory profiling -Memory profiling for Driver and Worker processes. This helps you analyze memory allocations in applications, trace memory leaks, and debug high/low memory or out of memory issues. +Profile the memory usage for Driver and Worker processes. This helps you analyze memory allocations in applications, trace memory leaks, and debug high/low memory or out of memory issues. (profiling-memray)= ### memray @@ -62,6 +62,6 @@ Here are the {ref}`steps to use PyTorch Profiler with Ray Train or Ray Data ` generated by Ray Timeline. From 7d28da56fffe2b181540152f97597e3eb8a0fe7f Mon Sep 17 00:00:00 2001 From: Huaiwei Sun Date: Wed, 6 Sep 2023 19:20:56 -0700 Subject: [PATCH 9/9] Update doc/source/ray-observability/user-guides/debug-apps/optimize-performance.rst Co-authored-by: angelinalg <122562471+angelinalg@users.noreply.github.com> Signed-off-by: Huaiwei Sun --- .../user-guides/debug-apps/optimize-performance.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/source/ray-observability/user-guides/debug-apps/optimize-performance.rst b/doc/source/ray-observability/user-guides/debug-apps/optimize-performance.rst index 163bb36a599c6..223fc85dba993 100644 --- a/doc/source/ray-observability/user-guides/debug-apps/optimize-performance.rst +++ b/doc/source/ray-observability/user-guides/debug-apps/optimize-performance.rst @@ -117,7 +117,7 @@ not have root permissions, the Dashboard prompts with instructions on how to set .. note:: You may run into permission errors when using py-spy in the docker containers. To fix the issue: - * if you start Ray manually in a Docker container, follow the `py-spy documentation`_ to resolve it. + * If you start Ray manually in a Docker container, follow the `py-spy documentation`_ to resolve it. * if you are a KubeRay user, follow the :ref:`guide to configure KubeRay ` and resolve it. .. _`py-spy documentation`: https://github.com/benfred/py-spy#how-do-i-run-py-spy-in-docker