Multiple concurrent programs on a single node
Using srun to create multiple jobs steps
You can use srun to start multiple job steps concurrently on a single node, e.g. if your job is not big enough to fill a whole node. There are a few details to follow:
- By default, the srun command gets exclusive access to all resources of the job allocation and uses all tasks
- you therefore need to limit srun to only use part of the allocation
- this includes implicitly granted resources, i.e. memory and GPUs
- the –exact flag is needed.
- if running non-mpi programs, use the -c option to denote the number of cores, each process should have access to
- srun waits for the program to finish, so you need to start concurrent processes in the background
- Good default memory per cpu values (without hyperthreading) are usually are:
standard96 | large96 | huge06 | medium40 | large40/gpu | |
---|---|---|---|---|---|
–mem-per-cpu | 3770M | 7781M | 15854M | 4525M | 19075M |
Examples
#!/bin/bash
#SBATCH -p standard96
#SBATCH -t 06:00:00
#SBATCH -N 1
srun --exact -n1 -c 10 --mem-per-cpu 3770M ./program1 &
srun --exact -n1 -c 80 --mem-per-cpu 3770M ./program2 &
srun --exact -n1 -c 6 --mem-per-cpu 3770M ./program3 &
wait
#!/bin/bash
#SBATCH -p gpu
#SBATCH -t 12:00:00
#SBATCH -N 1
srun --exact -n1 -c 10 -G1 --mem-per-cpu 19075M ./single-gpu-program &
srun --exact -n1 -c 10 -G1 --mem-per-cpu 19075M ./single-gpu-program &
srun --exact -n1 -c 10 -G1 --mem-per-cpu 19075M ./single-gpu-program &
srun --exact -n1 -c 10 -G1 --mem-per-cpu 19075M ./single-gpu-program &
wait
Using the Linux parallel command to run a large number of tasks
If you have to run many nearly identical but small tasks (single-core, little memory) you can try to use the Linux parallel command. To use this approach you first need to write a bash-shell script, e.g. task.sh, which executes a single task. As an example we will use the following script:
#!/bin/bash
# parallel task
TASK_ID=$1
PARAMETER=$((10+RANDOM%10)) # determine some parameter unique for this task
# often this will depend on the TASK_ID
echo -n "Task $TASK_ID: sleeping for $PARAMETER seconds ... "
sleep $PARAMETER
echo "done"
This script is simply defining a variable PARAMETER which then used as the input for the actual command, which is sleep in this case. The script also takes one input parameter, which can be interpreted as the TASK_ID and could also be used for determining the PARAMETER. If we make the script executable and run it as follows, we get:
$ chmod u+x task.sh
$ ./task.sh 4
Task 4: sleeping for 11 seconds ... done
To now run this task this task 100 times with different TASK_IDs we can write the following job script:3
|
|
The script use parallel in line 25 to run task.sh 100 times with a parameter taken from the range {1..100}. Because each task is started with srun a separate job step is created and the options used with srun (see line 12) the task is using only a single core. This simple example can be adjusted as needed by modifying the script task.sh and the job script parallel_job.sh. You can adjust the requested resources, for example, you can use more than a single node. Note that depending on the number of tasks you may have to split your job into several to keep the total time needed short enough. Once the setup is done, you can simply submit the job:
$ sbatch parallel_job.sh
Looping over two arrays
You can use parallel to loop over multiple arrays. The –xapply option controls, if all permuatations are used or not:
$ parallel --xapply echo {1} {2} ::: 1 2 3 ::: a b c
1 a
2 b
3 c
$ parallel echo {1} {2} ::: 1 2 3 ::: a b c
1 a
1 b
1 c
2 a
2 b
2 c
3 a
3 b
3 c