class_docstr: Allocator style helper class to assign individual tasks to a core range.
  
  Pinning tasks to separate cores (or core ranges if `num_threads` > 1)
  serves two purposes. First, it prevents the machine from being overloaded,
  which can result in OOMs or Callgrind crashes. Second, it helps reduce
  noise in the wall times, which are collected as a secondary metric. For
  multi-threaded workloads, adjacency is important. Often pairs of cores
  share silicon (e.g. cache), while far away cores may lie on separate NUMA
  nodes. For this reason, CorePool will only allocate contiguous core ranges.
  This falls short of full architecture awareness, and instead tries to find
  a balance between rigor and engineering complexity.
code: def __init__(self, min_core_id: int, max_core_id: int) -> None:
      assert min_core_id >= 0
      assert max_core_id >= min_core_id
      assert max_core_id < CPU_COUNT
  
      self._min_core_id: int = min_core_id
      self._max_core_id: int = max_core_id
      self._num_cores = max_core_id - min_core_id + 1
      print(
          f"Core pool created: cores {self._min_core_id}-{self._max_core_id}"
      )
  
      self._available: List[bool] = [
          True
          for _ in range(min_core_id, min_core_id + self._num_cores)
      ]
  
      self._reservations: Dict[str, Tuple[int, ...]] = {}
      self._lock = threading.Lock()
  
imports: import math
  import multiprocessing
  import subprocess
  import textwrap
  import threading
  import time
  from typing import Dict, List, Optional, Set, Tuple, Union
  from worker.main import WorkerFailure, WorkerOutput
  from execution.work import InProgress, PYTHON_CMD, SHELL, WorkOrder
label_desc: Use image node_id 1 to create a new CorePool object  with example: obj = CorePool(min_core_id, max_core_id)