Skip to content

Commit 9431376

Browse files
committed
Next 200 lines
1 parent bab91cd commit 9431376

File tree

1 file changed

+211
-0
lines changed

1 file changed

+211
-0
lines changed

docs/navigating_the_cluster/hpc_foundations.md

Lines changed: 211 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -759,3 +759,214 @@ srun: job 56142474 has been allocated resources
759759
> - `--label` labels standard output of tasks based on task ID from 0 to N.
760760
761761
762+
So far we understood that slurm chooses '_on which nodes our programs should run on_' based on it's scheduling decisions, however it also provides more control like specifying explicitly on which `partition` we can run our programs on.
763+
764+
Here partitions are similar nodes grouped together as a list. For example H100 nodes are grouped together as a partition named `H100_Partition`. Whenever we submit a job request for H100s then nodes sequentially along this partition are reserved and our job is scheduled on them.
765+
766+
You can check the list of **_all partitions_** and their **_compute node list_** with the `sinfo` command. This will provide you with more information about the partitions, and their statuses:
767+
768+
```sh
769+
sinfo
770+
```
771+
772+
To specify a particular partition, you can use the `--partition` option as shown below:
773+
774+
```sh
775+
srun --partition=cs --nodes=2 --tasks-per-node=1 --cpus-per-task=4 --mem=4GB --time=05:00 lua hello.lua
776+
```
777+
778+
779+
780+
> **_(A) SLURM OVERVIEW_**
781+
>
782+
> - Users submit jobs on the cluster.
783+
>
784+
> - Slurm ( or also called slurm controller ) that runs exclusively on it's own node, `queues` up these submitted jobs based on `priority` and schedules them across compute nodes based on the jobs' `compute requirements` and expected `execution time` (Priority, and Backfill scheduling).
785+
>
786+
> - Once a job has been `scheduled` on a compute node(s) it runs without interruption. The slurm controller continously monitors the job's status throughout it's life cycle and manages a `database` ( i.e. MySQL ) where it temporarily maintains the `status` of all running jobs across the cluster.
787+
>
788+
> - Whenever users make a slurm query such as the `squeue` command, to check on the status of their jobs ( or anyother slurm commands ). Such commands invoke a `Remote Procedure Call` (RPC for short) to the slurm controller, that fetches the job's status from it's database for the user.
789+
>
790+
> - **Too many RPCs** to the slurm controller in a short span of time may result in overloading of operations on the slurm's database. **_Resulting in slurm's poor performance_** ( RPCs are usually not rate limited for various reasons )
791+
>
792+
> - Hence it is **recommended** to _takecare_ Or **limit invoking slurm commands very frequently** in case of invoking them within a bash script or a python script
793+
>
794+
> - **_Failing_** to follow may result in the user account being **_suspended_**
795+
796+
797+
> **_(B) IMPORTANT NOTE !_**
798+
>
799+
> It is **_crucial_** to understand everything until this point, this builds your foundations in understanding further topics covered from this point onwards.
800+
> Please make sure to cover all the topics until this point in case you may have missed anything. It gets easier from here.
801+
802+
803+
> **_RECAP:_**
804+
>
805+
> - So far we have learn what compute clusters are ...
806+
> - How srun works ...
807+
> - squeue ...
808+
> - scancel ...
809+
> - And more ...
810+
811+
812+
## Submitting `Batch jobs`
813+
814+
Previously we have seen how we could submit individual `interactive jobs` mostly to run individual programs, however there is an issue with this method :
815+
816+
> **_What happens if we get disconnected from our ssh session while running our jobs ?_**
817+
>
818+
> - To understand this we need to understand how `ssh sessions` and `bash shells` are setup in our case
819+
>
820+
> - First, when we ssh to `greene.hpc.nyu.edu`, we land on a `login node` running a `bash shell`, the console is our shell where we execute the linux commands
821+
>
822+
> - Then when we submit a job with `srun`, our program runs **_within_** a `new bash sub-shell` belonging to this particular **_srun_** within which slurm sets the necessary environment variables accordingly, like the `SLURM_PROCID` environment variable as we have seen before
823+
>
824+
> - Therefore, "hello, world" `output(s)` printed by this program executing on `compute node(s)` are `buffered` all the way from their `sub-shell(s)` to our `bash shell` running on the login node, and are displayed line after line on console
825+
>
826+
> - Hence, if our `ssh gets disconnected` for any reason, the `current bash shell is destroyed`, and the job currently being executed within this `sub-shell` is `cancelled`
827+
828+
Therefore, we make use of `slurm batch` scripts also called `sbatch` instead of interactive jobs. Basically they are simple bash scripts `with special directives` that we **_submit to slurm_** instead of running them interactively.
829+
830+
Within a `sbatch` script we either specify a single job by invoking `srun` or **_batch multiple jobs_** by invoking multiple `srun` and **_submit it to slurm_** under a single job id hence called a `batch job`.
831+
832+
Once we submit a `batch job`, they are independently scheduled regardless of what happens to our shell. We can safely disconnect from our ssh session, and return later on to check on the status of our submitted batch job.
833+
834+
> **_NOTE_**:
835+
>
836+
> **_Submitting Batch jobs is the preferred way of submitting jobs to slurm_**
837+
838+
A simple batch job can be written as :
839+
840+
```sh
841+
#!/bin/bash
842+
843+
#SBATCH --nodes=1
844+
#SBATCH --tasks-per-node=1
845+
#SBATCH --cpus-per-task=1
846+
#SBATCH --mem=1GB
847+
#SBATCH --time=00:05:00
848+
849+
srun /bin/bash -c "sleep 60; echo 'hello, world' "
850+
```
851+
852+
As you can see, we provide the familiar slurm options in a format that is `#SBATCH`, these are called slurm `directives` in our bash script.
853+
854+
Create a batch script like the above named `hello.sbatch` and submit it using the `sbatch` command:
855+
856+
```sh
857+
sbatch hello.sbatch
858+
```
859+
860+
Check the status of this job with:
861+
862+
```sh
863+
squeue --me
864+
```
865+
866+
Once done, notice that in the same directory from where you submitted this job, there is a new file created `slurm-55815161.out`, where the number `55815161` is the **_job id_** in this example.
867+
868+
Check the contents of this file:
869+
870+
```sh
871+
cat slurm-<Job_ID>.out
872+
```
873+
```sh
874+
[pp2959@log-1 slurm_hello_world]$ cat slurm-55815161.out
875+
hello, world
876+
[pp2959@log-1 slurm_hello_world]$
877+
```
878+
879+
This is the output of your job. A new file is created by default named `slurm-<Job_ID>.out` and the outputs are written to it.
880+
881+
You can write the outputs to a custom file name for example `hello.out` using the directive `#SBATCH --output=hello.out`. Add this directive to your `hello.sbatch` file as shown below:
882+
883+
```sh
884+
#!/bin/bash
885+
886+
#SBATCH --nodes=1
887+
#SBATCH --tasks-per-node=1
888+
#SBATCH --cpus-per-task=1
889+
#SBATCH --mem=1GB
890+
#SBATCH --time=00:05:00
891+
892+
#SBATCH --output=hello.out
893+
894+
srun /bin/bash -c "echo 'hello, world' "
895+
```
896+
897+
And re-submit your batch job:
898+
899+
```sh
900+
sbatch hello.sbatch
901+
```
902+
903+
You should notice a new file `hello.out` gets created, and your `hello, world` message output is redirected to this file.
904+
905+
```sh
906+
[pp2959@log-1 slurm_hello_world]$ cat hello.out
907+
hello, world
908+
[pp2959@log-1 slurm_hello_world]$
909+
```
910+
911+
By default **_error messages_** that gets generated by your programs are redirected to the same output file, but you can also specify an exclusive file just for writing error messages at, using the directive `#SBATCH --error=hello.err` in this example.
912+
913+
Modify `hello.sbatch` to include this directive and also a modified program that prints `hello, world` then throws an **_error_** with exit code `1`:
914+
915+
```sh
916+
#!/bin/bash
917+
918+
#SBATCH --nodes=1
919+
#SBATCH --tasks-per-node=1
920+
#SBATCH --cpus-per-task=1
921+
#SBATCH --mem=1GB
922+
923+
#SBATCH --output=hello.out
924+
#SBATCH --error=hello.err
925+
926+
srun /bin/bash -c "echo 'hello, world'; exit 1"
927+
```
928+
929+
Submit this job:
930+
931+
```sh
932+
sbatch hello.sbatch
933+
```
934+
935+
Once done check both, output and error outputs of your program:
936+
937+
```sh
938+
[pp2959@log-3 slurm_hello_world]$ cat hello.err
939+
srun: error: cm013: task 0: Exited with exit code 1
940+
srun: Terminating StepId=55815589.0
941+
[pp2959@log-3 slurm_hello_world]$ cat hello.out
942+
hello, world
943+
[pp2959@log-3 slurm_hello_world]$
944+
```
945+
946+
> The error messages are redirected to a seperate file `hello.err`
947+
948+
In this example the error message states as follows,
949+
950+
- In the first line, slurm tells us that the program running on host `cm013`, which is a compute node, with task 0, for this particular `srun` exited with an error message of exit code 1, since we used `exit 1` in our bash script. You may use any error codes from 1 to 255 for debugging purposes, where code 0 is to exit with no errors.
951+
- Also we have a `StepId` in this error message as `StepId=55815589.0`. Here this particular `srun` is assigned a step id of 0.
952+
- Invoking a `srun` is also called a `job step` in a `batch job`.
953+
954+
We can invoke multiple `job steps` within our `batch job` as shown below:
955+
956+
```sh
957+
#!/bin/bash
958+
959+
#SBATCH --nodes=1
960+
#SBATCH --tasks-per-node=1
961+
#SBATCH --cpus-per-task=1
962+
#SBATCH --mem=1GB
963+
964+
#SBATCH --output=hello.out
965+
#SBATCH --error=hello.err
966+
967+
srun --time=02:00 /bin/bash -c "echo '(step 0): hello, world'; "
968+
srun --time=02:00 /bin/bash -c "echo '(step 1): hello, world'; "
969+
```
970+
971+
Every `srun` declared in the `batch script` is called a `job step` that will get it's own `step id` from 0 to N.
972+

0 commit comments

Comments
 (0)