Schedulers and containers¶
stream-limits reads the job’s allocation from the places schedulers and containers put it.
python -m stream_limits prints what it found and where each number came from; run it inside
a job (a batch job, or an interactive one) before relying on anything else.
$ python -m stream_limits
{
"cpus": 8,
"cpus_source": "NCPUS",
"memory_gb": 17.18,
"memory_source": "qstat Resource_List.mem",
"env": {"NCPUS": "8", "PBS_JOBID": "123456.pbsserver"}
}
If a number is wrong or comes from machine (no limit found) / physical memory, see
A site that does it differently.
Where each limit comes from¶
First match wins, for each of the two limits.
CPUs (threads)¶
Order |
Source |
Notes |
|---|---|---|
1 |
|
your own setting; never capped |
2 |
variables named in |
for sites with their own variable |
3 |
|
PBS Pro exports the job’s CPU count here |
4 |
|
set by some PBS builds |
5 |
|
Torque: processors per node, total processors |
6 |
|
Slurm |
7 |
the cgroup CPU quota |
|
8 |
|
only if |
9 |
the process’s CPU affinity |
only if it is restricted below the machine’s CPU count |
— |
|
no limit found |
Memory¶
Order |
Source |
Notes |
|---|---|---|
1 |
|
your own setting |
2 |
variables named in |
each holds a size such as |
3 |
the cgroup memory limit |
|
4 |
|
only if |
5 |
|
megabytes |
— |
the machine’s physical memory |
no limit found |
PBS¶
Environment variables differ between PBS versions and between sites. What is known:
PBS Pro exports
NCPUSto the job, and no memory variable. This was checked on one PBS Pro system, whereNCPUSwas set and nothing carried the memory request.Torque exports
PBS_NUM_PPNandPBS_NP. These are taken from Torque’s documentation and have not been checked on a Torque system here.PBS_NODEFILEis not used. It lists hosts, not CPUs: one line per CPU in Torque, but one line per chunk (or per MPI process) in PBS Pro, so counting its lines would silently cap a PBS Pro job at one thread.
qstat as a fallback¶
When the variables above do not settle a limit, and PBS_JOBID is set, stream-limits asks PBS
what it recorded for the job:
qstat -f $PBS_JOBID
and reads the Resource_List attributes:
memory:
Resource_List.mem, elseResource_List.vmem(virtual memory, a looser limit);CPUs:
Resource_List.ncpus, else the first chunk ofselect(1:ncpus=8:mem=16gb) or Torque’snodes(2:ppn=4), elseprocs.
Sizes carry PBS’s suffixes (b, kb, mb, gb, tb, pb, and w words of 8 bytes, all
powers of 1024); a bare number is bytes.
How it is run: with a fixed argument list and no shell, after checking that the job id is made of
the characters a job id has, with a 10 second timeout, once per job (the answer serves both
limits and is cached), and never when a variable or a cgroup already settled the limit. If
qstat is missing, fails or reports nothing, it is skipped without an error.
STREAM_LIMITS_QSTAT=0 turns it off.
Two things to know:
Several chunks. For a job with more than one chunk, PBS reports the total over the chunks, but the Python process runs on one host. The CPU count from
qstatis capped at the CPUs of the machine the process is on, and for memory you can setSTREAM_LIMITS_MEMORY_GBto the chunk’s share.Job arrays and sub-jobs need the id your site’s
qstat -faccepts; if the lookup returns nothing, setSTREAM_LIMITS_MEMORY_GBandSTREAM_LIMITS_MAX_THREADSin the job script.
Slurm¶
SLURM_CPUS_PER_TASK and SLURM_CPUS_ON_NODE give the CPUs; SLURM_MEM_PER_NODE the memory
(in megabytes), or SLURM_MEM_PER_CPU times the CPUs when the job asked per CPU. Slurm sites
that enforce cgroups are also found through the cgroup limits.
cgroups and containers¶
Containers and many schedulers limit a job with cgroups. The limit is usually on a parent group
(the job), not on the group the process sits in, so stream-limits reads the process’s cgroup
from /proc/self/cgroup and takes the lowest limit on the path up to the root. Both cgroup v1
and v2 are supported. A cgroup that sets no limit (max) is skipped.
A site that does it differently¶
Name the variable. Each of these settings is a comma-separated list of variable names, checked before the built-in ones:
export STREAM_LIMITS_CPU_VARS=SITE_NCPUS # holds an integer
export STREAM_LIMITS_MEMORY_VARS=SITE_MEMORY # holds a size: 16gb, 512mb
or set the limit directly in the job script, which beats everything:
export STREAM_LIMITS_MAX_THREADS=$NCPUS
export STREAM_LIMITS_MEMORY_GB=16
If you find a variable that a scheduler sets and stream-limits does not read, please open an
issue with the output of env | grep -i -E 'pbs|ncpus|mem|slurm' from inside a job.
A job script¶
#!/bin/bash
#PBS -l select=1:ncpus=8:mem=16gb
#PBS -l walltime=04:00:00
cd $PBS_O_WORKDIR
python -m stream_limits # shows what the job will be capped at
python my_analysis.py # which starts with: import stream_limits; stream_limits.limit_threads()
With a package built on stream-limits (hdfe-stream, logit-stream, dpd-stream) the script needs no
stream_limits lines: the package applies the limits when it is imported.