docstr: Evict tensors from CUDA device.
  
  Args:
      can_evict_chunks (List[StatefulTensor]): the list of tensors that can be evicted.
      cuda_demand (int, optional): the volume of data needed on cuda device. Defaults to 0.
      warmup (bool, optional): a flag indicates whether in the phase of warmup. Defaults to True.
      compute_list (List[StatefulTensor], optional): TODO. Defaults to [].
      compute_idx (int, optional): the idx of computing device. Defaults to 0.
  
  Raises:
      RuntimeError:
  
  Returns:
      int: the volume of memory that is evicted
docstr_tok: ["Evict","tensors","from","CUDA","device",".","Args",":","can_evict_chunks","(","List","[","StatefulTensor","]",")",":","the","list","of","tensors","that","can","be","evicted",".","cuda_demand","(","int",",","optional",")",":","the","volume","of","data","needed","on","cuda","device",".","Defaults","to","0.","warmup","(","bool",",","optional",")",":","a","flag","indicates","whether","in","the","phase","of","warmup",".","Defaults","to","True",".","compute_list","(","List","[","StatefulTensor","]",",","optional",")",":","TODO",".","Defaults","to","[","]",".","compute_idx","(","int",",","optional",")",":","the","idx","of","computing","device",".","Defaults","to","0",".","Raises",":","RuntimeError",":","Returns",":","int",":","the","volume","of","memory","that","is","evicted"]
code: def evict_tensors(
      self,
      can_evict_chunks: List[Chunk],
      cuda_demand: int = 0,
      warmup: bool = True,
      compute_list: Optional[List[Tuple[Chunk, ...]]] = None,
      compute_idx: int = 0,
      **kwargs,
  ) -> Tuple[int, float]:
      """
      Evict tensors from CUDA device.
  
      Args:
          can_evict_chunks (List[StatefulTensor]): the list of tensors that can be evicted.
          cuda_demand (int, optional): the volume of data needed on cuda device. Defaults to 0.
          warmup (bool, optional): a flag indicates whether in the phase of warmup. Defaults to True.
          compute_list (List[StatefulTensor], optional): TODO. Defaults to [].
          compute_idx (int, optional): the idx of computing device. Defaults to 0.
  
      Raises:
          RuntimeError:
  
      Returns:
          int: the volume of memory that is evicted
      """
      start = time()
      cuda_capacity = colo_device_memory_capacity(get_current_device())
      used_cuda_model_data = self.chunk_manager.total_mem["cuda"]
      if warmup:
          # We designate a part of CUDA memory for model data in warmup iterations.
          max_cuda_non_model_data_per_period = (
              cuda_capacity * self._warmup_non_model_data_ratio
          )
      else:
          # max non-model-data cuda memory consumption of this sampling moment and the next sampling moment.
          max_cuda_non_model_data_per_period = (
              self.mem_stats_collector.next_period_non_model_data_usage(
                  "cuda"
              )
          )
          cuda_capacity *= self._steady_cuda_cap_ratio
      total_cuda_model_data = (
          cuda_capacity - max_cuda_non_model_data_per_period
      )
      avail_cuda_model_data = (
          total_cuda_model_data - used_cuda_model_data
      )
      freed_cuda_model_data = 0
  
      if avail_cuda_model_data < cuda_demand:
          # Move cuda_demand - avail_cuda_model_data volume of tensors
          # to_free_cuda_model_data = cuda_demand - avail_cuda_model_data
          to_free_cuda_model_data = cuda_demand - avail_cuda_model_data
          to_free_chunks = can_evict_chunks
          if not warmup:
              to_free_chunks = self._sort_can_evict_chunks(
                  tuple(to_free_chunks),
                  compute_idx,
                  tuple(compute_list),
              )
              # print(self._sort_can_evict_chunks.cache_info())
          for chunk in to_free_chunks:
              if freed_cuda_model_data >= to_free_cuda_model_data:
                  break
  
              self.chunk_manager.release_chunk(chunk)
              self.chunk_manager.move_chunk(chunk, torch.device("cpu"))
              freed_cuda_model_data += chunk.chunk_mem
          if freed_cuda_model_data < to_free_cuda_model_data:
              raise RuntimeError(
                  f"Adjust layout failed! No enough CUDA memory! "
                  f"Need {to_free_cuda_model_data}, freed {freed_cuda_model_data}"
              )
      return freed_cuda_model_data, time() - start
  
imports: import functools
  import warnings
  from abc import ABC, abstractmethod
  from time import time
  from typing import Dict, List, Optional, Tuple, Type
  import torch
  from colossalai.utils import get_current_device
  from colossalai.utils.memory import colo_device_memory_capacity
  from colossalai.zero.gemini.chunk import Chunk
  from .chunk import Chunk, ChunkManager
  from .memory_tracer import ChunkMemStatsCollector
label_desc: Use image node_id 2 for calling the AutoPlacementPolicy obj's underlying member method code with example usage: obj.evict_tensors(can_evict_chunks, cuda_demand, warmup, compute_list, compute_idx) and returns: freed_cuda_model_data,  unknown