skills/get-available-resources/references/resource_semantics.md
Research and behavior cut-off: 2026-07-23. See
sources.md for the official documentation used.
Never treat a host-wide count as a promise that the current process can use it. Interpret usable resources as the intersection of independently observed constraints:
Missing evidence means unknown, not unlimited. Scheduler variables can describe an allocation without proving that affinity or cgroup enforcement is enabled. Conversely, a cgroup or affinity mask can be stricter than the scheduler request.
os.cpu_count() and psutil.cpu_count(logical=True) are host/system
inventory. They can exceed the CPUs usable by the process.os.process_cpu_count() (Python 3.13+) is process-aware. On supported
platforms, affinity APIs provide a more explicit process constraint.The detector reports host logical and physical counts separately. It never derives physical cores from a logical count.
cpuset.cpus.effective reports CPUs actually granted after parent
constraints. The requested cpuset.cpus can differ./proc/self/status exposes Cpus_allowed_list, but the detector prefers
affinity APIs and cgroup effective cpusets.cpu.max is $MAX $PERIOD. max means no local bandwidth limit.
A finite ratio is CPU-time capacity, possibly fractional; it is not a core
topology count.For a cpu.max ratio of 1.5, the snapshot reports
capacity_cores: 1.5 and a conservative CPU-bound worker ceiling of 1. A
workload may choose more threads for latency hiding, but it should expect
throttling and must not describe those threads as 1.5 physical cores.
multiprocessing.Pool and ProcessPoolExecutor defaults use
os.process_cpu_count() when available.fork as the default start method on any platform.
Code that depends on a particular start method must request it deliberately.ProcessPoolExecutor has a documented maximum of 61 workers.Use the workload planner's worker and threads-per-worker values as conservative ceilings, then benchmark a real representative workload. Do not run a synthetic stress test merely to discover capacity.
psutil.virtual_memory().total and .available describe system-visible
memory, not necessarily the process limit./proc/meminfo MemAvailable is the standard-library fallback for a
host-availability estimate.memory.current is current cgroup usage.memory.high is a throttle/reclaim pressure boundary. Exceeding it does not
itself invoke the cgroup OOM killer, and the value can be breached.memory.max is the hard cgroup limit. If usage cannot be reduced at that
boundary, the cgroup OOM killer can run.limit - current observed through the ancestor chain.The detector keeps host total/available values, cgroup values, scheduler values, and the conservative effective values distinct. A point-in-time "available" value can change immediately and is not a reservation.
On Apple silicon, CPU and integrated GPU share unified memory. Do not add a
fictional GPU VRAM amount to system RAM. The snapshot marks the memory model as
unified_cpu_gpu and leaves dedicated GPU memory null. Metal framework support
and model/operator support still require application-specific checks.
Accelerator usability has separate layers:
nvidia-smi success confirms NVIDIA management visibility only. It does not
prove that CUDA libraries exist or are compatible. NVIDIA documents driver and
runtime compatibility as a separate requirement.
AMD SMI or ROCm SMI success likewise does not prove HIP/ROCm runtime usability.
New deployments should prefer amd-smi; rocm-smi is retained as a read-only
fallback. On Linux, AMD recommends ROCR_VISIBLE_DEVICES; on Windows it
recommends HIP_VISIBLE_DEVICES.
An Apple integrated GPU is a Metal candidate, not a CUDA GPU. AMD GPUs are ROCm candidates, not CUDA GPUs. Neural engines, TPUs, FPGAs, and other accelerators must also remain distinct from CUDA devices if another inventory source adds them.
The detector reads only these accelerator variable names and redacts their values:
NVIDIA_VISIBLE_DEVICESCUDA_VISIBLE_DEVICESROCR_VISIBLE_DEVICESHIP_VISIBLE_DEVICESCounts derived from those values are only upper bounds. Environment variables are not a security boundary and can be reset by an application; device namespace/cgroup controls are stronger isolation.
The detector allowlists named Slurm variables and never dumps the environment. It records field names, parsed bounded counts, and memory quantities, but not job IDs, GPU UUIDs, node names, submit hosts, or paths.
Important scopes:
SLURM_CPUS_PER_TASK: requested CPUs per task; suitable as a per-process
upper bound for one task process.SLURM_CPUS_ON_NODE: CPUs allocated to the current batch step on the node;
it can be shared among tasks.SLURM_JOB_CPUS_PER_NODE: a per-node allocation list, not a process count.SLURM_MEM_PER_CPU: memory per allocated CPU. It becomes a per-task bound
only when CPUs per task is known.SLURM_MEM_PER_NODE: shared per-node memory upper bound.SLURM_GPUS_PER_TASK: requested GPUs per task.SLURM_GPUS_ON_NODE: GPUs allocated to the batch step on the node.Slurm CPU confinement requires site configuration such as task affinity or
task/cgroup with core constraints. Memory requests are not strictly enforced
unless the site enables an enforcement mechanism. Use affinity and cgroup
observations as enforcement evidence; do not trust visible node inventory.
For other schedulers, use their documented allocation API or variables and the same rule: allocation metadata and kernel enforcement are different facts. Do not guess from generic environment names.
Docker containers have no CPU or memory limit by default. When configured, Docker maps CPU and memory flags to cgroup controls. OCI runtime configuration also defines CPU, memory, and device constraints.
Inside a container:
Always report observed cgroup controls and uncertainty. A container marker without a finite cgroup value does not imply a finite limit.
Capacity, free blocks, user-writable blocks, path permission, filesystem quota, and actual ability to complete a write are different:
f_bavail estimates blocks available to the current user;os.access(..., os.W_OK) is a non-writing permission check, not proof that a
future write will succeed;The detector does not create a probe file. It redacts the absolute working path and labels the scope as the working filesystem.