.. _core-resources:

Resources
=========

Ray allows you to seamlessly scale your applications from a laptop to a cluster without code change.
**Ray resources** are key to this capability.
They abstract away physical machines and let you express your computation in terms of resources,
while the system manages scheduling and autoscaling based on resource requests.

A resource in Ray is a key-value pair where the key denotes a resource name, and the value is a float quantity.
For convenience, Ray has native support for CPU, GPU, and memory resource types; CPU, GPU and memory are called **pre-defined resources**.
Besides those, Ray also supports :ref:`custom resources <custom-resources>`.

.. _logical-resources:

Physical Resources and Logical Resources
----------------------------------------

Physical resources are resources that a machine physically has such as physical CPUs and GPUs
and logical resources are virtual resources defined by a system.

Ray resources are **logical** and don’t need to have 1-to-1 mapping with physical resources.
For example, you can start a Ray head node with 0 logical CPUs via ``ray start --head --num-cpus=0``
even if it physically has eight
(This signals the Ray scheduler to not schedule any tasks or actors that require logical CPU resources
on the head node, mainly to reserve the head node for running Ray system processes.).
They are mainly used for admission control during scheduling.

The fact that resources are logical has several implications:

- Resource requirements of tasks or actors do NOT impose limits on actual physical resource usage.
  For example, Ray doesn't prevent a ``num_cpus=1`` task from launching multiple threads and using multiple physical CPUs.
  It's your responsibility to make sure tasks or actors use no more resources than specified via resource requirements.
- Ray doesn't provide CPU isolation for tasks or actors.
  For example, Ray won't reserve a physical CPU exclusively and pin a ``num_cpus=1`` task to it.
  Ray will let the operating system schedule and run the task instead.
  If needed, you can use operating system APIs like ``sched_setaffinity`` to pin a task to a physical CPU.
- Ray does provide :ref:`GPU <gpu-support>` isolation in the form of *visible devices* by automatically setting the ``CUDA_VISIBLE_DEVICES`` environment variable,
  which most ML frameworks will respect for purposes of GPU assignment.

.. _omp-num-thread-note:

.. note::
    Ray sets the environment variable ``OMP_NUM_THREADS=<num_cpus>`` if ``num_cpus`` is set on
    the task/actor via :func:`ray.remote() <ray.remote>` and :meth:`task.options() <ray.remote_function.RemoteFunction.options>`/:meth:`actor.options() <ray.actor.ActorClass.options>`.
    Ray sets ``OMP_NUM_THREADS=1`` if ``num_cpus`` is not specified; this
    is done to avoid performance degradation with many workers (issue #6998). You can
    also override this by explicitly setting ``OMP_NUM_THREADS`` to override anything Ray sets by default.
    ``OMP_NUM_THREADS`` is commonly used in numpy, PyTorch, and Tensorflow to perform multi-threaded
    linear algebra. In multi-worker setting, we want one thread per worker instead of many threads
    per worker to avoid contention. Some other libraries may have their own way to configure
    parallelism. For example, if you're using OpenCV, you should manually set the number of
    threads using cv2.setNumThreads(num_threads) (set to 0 to disable multi-threading).

.. figure:: ../images/physical_resources_vs_logical_resources.svg

  Physical resources vs logical resources

.. _custom-resources:

Custom Resources
----------------

You can specify custom resources for a Ray node and reference them to control scheduling for your tasks or actors.

Use custom resources when you need to manage scheduling using numeric values. If you need simple label-based scheduling, use labels instead. See :doc:`labels`.

.. _specify-node-resources:

Specifying Node Resources
-------------------------

By default, Ray nodes start with pre-defined CPU, GPU, and memory resources. The quantities of these logical resources on each node are set to the physical quantities auto detected by Ray.
By default, logical resources are configured by the following rule.

.. warning::

    Ray **does not permit dynamic updates of resource capacities after Ray has been started on a node**.

- **Number of logical CPUs** (``num_cpus``): Set to the number of CPUs of the machine/container.
- **Number of logical GPUs** (``num_gpus``): Set to the number of GPUs of the machine/container.
- **Memory** (``memory``): Set to 70% of "available memory" when ray runtime starts.
- **Object Store Memory** (``object_store_memory``): Set to 30% of "available memory" when ray runtime starts. Note that the object store memory is not logical resource, and users cannot use it for scheduling.

However, you can always override that by manually specifying the quantities of pre-defined resources and adding custom resources.
There are several ways to do that depending on how you start the Ray cluster:

.. tab-set::

    .. tab-item:: ray.init()

        If you are using :func:`ray.init() <ray.init>` to start a single node Ray cluster, you can do the following to manually specify node resources:

        .. literalinclude:: ../doc_code/resources.py
            :language: python
            :start-after: __specifying_node_resources_start__
            :end-before: __specifying_node_resources_end__

    .. tab-item:: ray start

        If you are using :ref:`ray start <ray-start-doc>` to start a Ray node, you can run:

        .. code-block:: shell

            ray start --head --num-cpus=3 --num-gpus=4 --resources='{"special_hardware": 1, "custom_label": 1}'

    .. tab-item:: ray up

        If you are using :ref:`ray up <ray-up-doc>` to start a Ray cluster, you can set the :ref:`resources field <cluster-configuration-resources-type>` in the yaml file:

        .. code-block:: yaml

            available_node_types:
              head:
                ...
                resources:
                  CPU: 3
                  GPU: 4
                  special_hardware: 1
                  custom_label: 1

    .. tab-item:: KubeRay

        If you are using :ref:`KubeRay <kuberay-index>` to start a Ray cluster, you can set the :ref:`rayStartParams field <rayStartParams>` in the yaml file:

        .. code-block:: yaml

            headGroupSpec:
              rayStartParams:
                num-cpus: "3"
                num-gpus: "4"
                resources: '"{\"special_hardware\": 1, \"custom_label\": 1}"'


.. _resource-requirements:

Specifying Task or Actor Resource Requirements
----------------------------------------------

Ray allows specifying a task or actor's logical resource requirements (e.g., CPU, GPU, and custom resources).
The task or actor will only run on a node if there are enough required logical resources
available to execute the task or actor.

By default, Ray tasks use 1 logical CPU resource and Ray actors use 1 logical CPU for scheduling, and 0 logical CPU for running.
(This means, by default, actors cannot get scheduled on a zero-cpu node, but an infinite number of them can run on any non-zero cpu node.
The default resource requirements for actors was chosen for historical reasons.
It's recommended to always explicitly set ``num_cpus`` for actors to avoid any surprises.
If resources are specified explicitly, they are required both at schedule time and at execution time.)

You can also explicitly specify a task's or actor's logical resource requirements (for example, one task may require a GPU) instead of using default ones via :func:`ray.remote() <ray.remote>`
and :meth:`task.options() <ray.remote_function.RemoteFunction.options>`/:meth:`actor.options() <ray.actor.ActorClass.options>`.

.. tab-set::

    .. tab-item:: Python

        .. literalinclude:: ../doc_code/resources.py
            :language: python
            :start-after: __specifying_resource_requirements_start__
            :end-before: __specifying_resource_requirements_end__

    .. tab-item:: Java

        .. code-block:: java

            // Specify required resources.
            Ray.task(MyRayApp::myFunction).setResource("CPU", 1.0).setResource("GPU", 1.0).setResource("special_hardware", 1.0).remote();

            Ray.actor(Counter::new).setResource("CPU", 2.0).setResource("GPU", 1.0).remote();

    .. tab-item:: C++

        .. code-block:: c++

            // Specify required resources.
            ray::Task(MyFunction).SetResource("CPU", 1.0).SetResource("GPU", 1.0).SetResource("special_hardware", 1.0).Remote();

            ray::Actor(CreateCounter).SetResource("CPU", 2.0).SetResource("GPU", 1.0).Remote();

Task and actor resource requirements have implications for the Ray's scheduling concurrency.
In particular, the sum of the logical resource requirements of all of the
concurrently executing tasks and actors on a given node cannot exceed the node's total logical resources.
This property can be used to :ref:`limit the number of concurrently running tasks or actors to avoid issues like OOM <core-patterns-limit-running-tasks>`.

.. _fractional-resource-requirements:

Fractional Resource Requirements
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Ray supports fractional resource requirements.
For example, if your task or actor is IO bound and has low CPU usage, you can specify fractional CPU ``num_cpus=0.5`` or even zero CPU ``num_cpus=0``.
The precision of the fractional resource requirement is 0.0001 so you should avoid specifying a double that's beyond that precision.

.. literalinclude:: ../doc_code/resources.py
    :language: python
    :start-after: __specifying_fractional_resource_requirements_start__
    :end-before: __specifying_fractional_resource_requirements_end__

.. note::

  GPU, TPU, and neuron_cores resource requirements that are greater than 1, need to be whole numbers. For example, ``num_gpus=1.5`` is invalid.

.. tip::

  Besides resource requirements, you can also specify an environment for a task or actor to run in,
  which can include Python packages, local files, environment variables, and more. See :ref:`Runtime Environments <runtime-environments>` for details.