class_docstr: Represents the resource configuration passed to a raylet.
  
  All fields can be None. Before starting services, resolve() should be
  called to return a ResourceSpec with unknown values filled in with
  defaults based on the local machine specifications.
  
  Attributes:
      num_cpus: The CPUs allocated for this raylet.
      num_gpus: The GPUs allocated for this raylet.
      memory: The memory allocated for this raylet.
      object_store_memory: The object store memory allocated for this raylet.
          Note that when calling to_resource_dict(), this will be scaled down
          by 30% to account for the global plasma LRU reserve.
      resources: The custom resources allocated for this raylet.
      redis_max_memory: The max amount of memory (in bytes) to allow each
          redis shard to use. Once the limit is exceeded, redis will start
          LRU eviction of entries. This only applies to the sharded redis
          tables (task, object, and profile tables). By default, this is
          capped at 10GB but can be set higher.
docstr: Returns a copy with values filled out with system defaults.
  
  Args:
      is_head: Whether this is the head node.
      node_ip_address: The IP address of the node that we are on.
          This is used to automatically create a node id resource.
code: def resolve(
      self, is_head: bool, node_ip_address: Optional[str] = None
  ):
      """Returns a copy with values filled out with system defaults.
  
      Args:
          is_head: Whether this is the head node.
          node_ip_address: The IP address of the node that we are on.
              This is used to automatically create a node id resource.
      """
  
      resources = (self.resources or {}).copy()
      assert "CPU" not in resources, resources
      assert "GPU" not in resources, resources
      assert "memory" not in resources, resources
      assert "object_store_memory" not in resources, resources
  
      if node_ip_address is None:
          node_ip_address = ray.util.get_node_ip_address()
  
      # Automatically create a node id resource on each node. This is
      # queryable with ray._private.state.node_ids() and
      # ray._private.state.current_node_id().
      resources[NODE_ID_PREFIX + node_ip_address] = 1.0
  
      # Automatically create a head node resource.
      if HEAD_NODE_RESOURCE_NAME in resources:
          raise ValueError(
              f"{HEAD_NODE_RESOURCE_NAME}"
              " is a reserved resource name, use another name instead."
          )
      if is_head:
          resources[HEAD_NODE_RESOURCE_NAME] = 1.0
  
      num_cpus = self.num_cpus
      if num_cpus is None:
          num_cpus = ray._private.utils.get_num_cpus()
  
      num_gpus = 0
      for (
          accelerator_resource_name
      ) in (
          ray._private.accelerators.get_all_accelerator_resource_names()
      ):
          accelerator_manager = ray._private.accelerators.get_accelerator_manager_for_resource(
              accelerator_resource_name
          )
          num_accelerators = None
          if accelerator_resource_name == "GPU":
              num_accelerators = self.num_gpus
          else:
              num_accelerators = resources.get(
                  accelerator_resource_name, None
              )
          visible_accelerator_ids = (
              accelerator_manager.get_current_process_visible_accelerator_ids()
          )
          # Check that the number of accelerators that the raylet wants doesn't
          # exceed the amount allowed by visible accelerator ids.
          if (
              num_accelerators is not None
              and visible_accelerator_ids is not None
              and num_accelerators > len(visible_accelerator_ids)
          ):
              raise ValueError(
                  f"Attempting to start raylet with {num_accelerators} "
                  f"{accelerator_resource_name}, "
                  f"but {accelerator_manager.get_visible_accelerator_ids_env_var()} "
                  f"contains {visible_accelerator_ids}."
              )
          if num_accelerators is None:
              # Try to automatically detect the number of accelerators.
              num_accelerators = (
                  accelerator_manager.get_current_node_num_accelerators()
              )
              # Don't use more accelerators than allowed by visible accelerator ids.
              if visible_accelerator_ids is not None:
                  num_accelerators = min(
                      num_accelerators, len(visible_accelerator_ids)
                  )
  
          if num_accelerators:
              if accelerator_resource_name == "GPU":
                  num_gpus = num_accelerators
              else:
                  resources[
                      accelerator_resource_name
                  ] = num_accelerators
  
              accelerator_type = (
                  accelerator_manager.get_current_node_accelerator_type()
              )
              if accelerator_type:
                  resources[
                      f"{ray_constants.RESOURCE_CONSTRAINT_PREFIX}{accelerator_type}"
                  ] = 1
  
                  from ray._private.usage import usage_lib
  
                  usage_lib.record_hardware_usage(accelerator_type)
              additional_resources = (
                  accelerator_manager.get_current_node_additional_resources()
              )
              if additional_resources:
                  resources.update(additional_resources)
      # Choose a default object store size.
      system_memory = ray._private.utils.get_system_memory()
      avail_memory = ray._private.utils.estimate_available_memory()
      object_store_memory = self.object_store_memory
      if object_store_memory is None:
          object_store_memory = int(
              avail_memory
              * ray_constants.DEFAULT_OBJECT_STORE_MEMORY_PROPORTION
          )
  
          # Set the object_store_memory size to 2GB on Mac
          # to avoid degraded performance.
          # (https://github.com/ray-project/ray/issues/20388)
          if sys.platform == "darwin":
              object_store_memory = min(
                  object_store_memory,
                  ray_constants.MAC_DEGRADED_PERF_MMAP_SIZE_LIMIT,
              )
  
          max_cap = ray_constants.DEFAULT_OBJECT_STORE_MAX_MEMORY_BYTES
          # Cap by shm size by default to avoid low performance, but don't
          # go lower than REQUIRE_SHM_SIZE_THRESHOLD.
          if sys.platform == "linux" or sys.platform == "linux2":
              # Multiple by 0.95 to give a bit of wiggle-room.
              # https://github.com/ray-project/ray/pull/23034/files
              shm_avail = (
                  ray._private.utils.get_shared_memory_bytes() * 0.95
              )
              max_cap = min(
                  max(
                      ray_constants.REQUIRE_SHM_SIZE_THRESHOLD,
                      shm_avail,
                  ),
                  max_cap,
              )
          # Cap memory to avoid memory waste and perf issues on large nodes
          if object_store_memory > max_cap:
              logger.debug(
                  "Warning: Capping object memory store to {}GB. ".format(
                      max_cap // 1e9
                  )
                  + "To increase this further, specify `object_store_memory` "
                  "when calling ray.init() or ray start."
              )
              object_store_memory = max_cap
  
      redis_max_memory = self.redis_max_memory
      if redis_max_memory is None:
          redis_max_memory = min(
              ray_constants.DEFAULT_REDIS_MAX_MEMORY_BYTES,
              max(
                  int(avail_memory * 0.1),
                  ray_constants.REDIS_MINIMUM_MEMORY_BYTES,
              ),
          )
      if redis_max_memory < ray_constants.REDIS_MINIMUM_MEMORY_BYTES:
          raise ValueError(
              "Attempting to cap Redis memory usage at {} bytes, "
              "but the minimum allowed is {} bytes.".format(
                  redis_max_memory,
                  ray_constants.REDIS_MINIMUM_MEMORY_BYTES,
              )
          )
  
      memory = self.memory
      if memory is None:
          memory = (
              avail_memory
              - object_store_memory
              - (redis_max_memory if is_head else 0)
          )
          if memory < 100e6 and memory < 0.05 * system_memory:
              raise ValueError(
                  "After taking into account object store and redis memory "
                  "usage, the amount of memory on this node available for "
                  "tasks and actors ({} GB) is less than {}% of total. "
                  "You can adjust these settings with "
                  "ray.init(memory=<bytes>, "
                  "object_store_memory=<bytes>).".format(
                      round(memory / 1e9, 2),
                      int(100 * (memory / system_memory)),
                  )
              )
  
      spec = ResourceSpec(
          num_cpus,
          num_gpus,
          memory,
          object_store_memory,
          resources,
          redis_max_memory,
      )
      assert spec.resolved()
      return spec
  
file_path: ray/python/ray/_private/resource_spec.py
imports: import logging
  import sys
  from collections import namedtuple
  from typing import Optional
  import ray
  import ray._private.ray_constants
label_desc: Use image node_id 4 for calling the ResourceSpec obj's underlying member method code with example usage: obj.resolve(is_head, node_ip_address) and returns: spec