{ "cells": [ { "cell_type": "markdown", "id": "3d7ca1dc-76d4-413f-bd16-64ce315fdaec", "metadata": {}, "source": [ "# Module 1. Practice 1" ] }, { "cell_type": "markdown", "id": "61782860-0b2a-4477-8fd4-c0c620fd5b6b", "metadata": {}, "source": [ "# Introduction to HPC Clusters and SLURM\n", "\n", "This notebook is designed to help you understand what an HPC (High-Performance Computing) cluster is, how to use SLURM for job scheduling, and how to compile and run a simple C program on the cluster.\n", "\n", "## Learning Objectives\n", "- Understand the architecture of HPC clusters.\n", "- Learn the basics of SLURM and its main commands.\n", "- Compile and run a simple C program using SLURM.\n", "- Perform practical exercises to reinforce the learned concepts." ] }, { "cell_type": "markdown", "id": "3ddf1c42-e976-4273-b5ba-f0e31c5ab23c", "metadata": {}, "source": [ "## What is an HPC Cluster?\n", "An HPC cluster is a collection of interconnected computers (or nodes) that work together to perform complex computations. These clusters can handle computational tasks that require a lot of processing power and memory, far beyond what a single machine could manage.\\\n", "\n", "![Meluxina HPC Architecture](https://hpc.uni.lu/old/images/overview/meluxina_overview.png)\n", "\n", "\n", "### Architecture of HPC Clusters\n", "1. **Management Node**: Controls the overall operation of the cluster.\n", "2. **Login Node**: Provides an interface for users to submit jobs and interact with the cluster.\n", "3. **Compute Nodes**: Perform the actual computations.\n", "\n" ] }, { "cell_type": "markdown", "id": "c63a1bf0-627c-422e-972d-14a1f1e4d56b", "metadata": {}, "source": [ "## II. Why is HPC important?\n", "High performance computing opens the door to large scale data analysis, computational science, and research computing. It is useful in a number of scenarios, including where software is too time-critical, too performance critical, or simply too big to run on a traditional system.\n", "\n", "![HPC Applications](https://ec.europa.eu/information_society/newsroom/image/document/2021-5/hpc_applications_3D20F502-F32E-357F-31E23744FC4EE2C3_73074.jpg \"\")\n", "\n", "\n", "Let's take a look at a few examples of scenarios where you would need an HPC System or an HPC System drastically changes your process.\n", "\n", "\n", "- **Scenario 1: Predicting Natural Disasters and Understanding Climate Change :** A key field where HPC has delivered a transformational impact is Earth sciences. Supercomputing is frequently used to study climate change and its impact. Research organizations around the world rely on HPC to predict weather phenomena and enable highly accurate hyperlocalized forecasts. A crucial broader application area of these foundational domains is emergency preparedness, where HPC models are used to predict aspects of natural disasters such as intensity and impact of earthquakes, path and ferocity of hurricanes, direction and impact of tsunamis, and more. The climate is ever changing, with increasing threats of intense hurricanes, heatwaves, and other extreme events necessitating the need for higher-fidelity computational models and more supercomputing capabilities\n", "\n", "\n", "![Weather Models](https://smd-prod.s3.amazonaws.com/science-red/s3fs-public/styles/large/public/mnt/medialibrary/2015/08/03/WeatherFocusGPM.png?itok=0duoMhY0 \"\")\n", "\n", "\n", "- **Scenario 2: Designing a New Car or Plane:** You're a brand new aerospace engineer working for the Mercedes-Benz Formula One team. You have the off season (usually between December and May, or about five months) to design a new car which is better than all the cars that beat you last year. Traditionally, the way to do this is start with a small model, put it in a wind tunnel, evaluate it, and repeat this process. Then, you slowly scale up to bigger models and eventually start building concept cars. However, you only have five months, and each model may take a month to design and produce. You simply don't have time. Instead, you get started with your HPC system and start creating some [Computational Fluid Dynamics](https://en.wikipedia.org/wiki/Computational_fluid_dynamics) models which you can then use to create your new car with plenty of time to spare. The image below is the output of a CFD model. \n", "\n", "\n", "![CFD model of car](https://upload.wikimedia.org/wikipedia/commons/f/fa/Verus_Engineering_Porsche_987.2_Ventus_2_Package.png)\n", "\n", "\n", "- **Scenario 3: Personalized Medicine and Drug Discovery:** Life sciences are another major vertical segment that relies on HPC technologies in various application areas. Supercomputing is used by researchers and enterprises for genome sequencing and drug discovery. Pharmaceutical companies often deploy supercomputers to accelerate the process of drug discovery using various molecular dynamic simulation methodologies. Using HPC and molecular dynamics simulations researchers are able to design new drugs and virtually test effectiveness, enabling significant optimization of the research process while resulting in safer and more effective drugs. HPC is also used to develop virtual models of human physiology (e.g., heart, brain, etc.), which enable scientists and researchers to understand ailments and potential treatments better. Increasingly life sciences researchers and companies are engineering new methodologies combining genome sequencing and drug discovery to enable new and more effective forms of personalized medicine that could cure some of the most challenging diseases.\n", "\n", "\n", "![computational climate research](https://www.cbkscicon.com/wp-content/uploads/2019/09/small_crop_Screen-Shot-2018-03-08-at-17.17.33-1-300x300.png)" ] }, { "cell_type": "code", "execution_count": 7, "id": "9e34d620-c618-4b44-a8d1-b81697933205", "metadata": {}, "outputs": [], "source": [ "# Enable oversubcription in the cluster\n", "import os\n", "os.environ[\"OMPI_MCA_rmaps_base_oversubscribe\"] = \"1\"\n", "def run_srun(command):\n", " os.system(f\"srun --oversubscribe {command}\")" ] }, { "cell_type": "markdown", "id": "smart-kennedy", "metadata": {}, "source": [ "If you want to change the code you can do it in the filesystem. To access from Jupyter you can do it from the left panel. Select your file inside folder openmp and modify it (do not forget to save it with File/save). \n", "Do not forget that you will need to compile it. You can reuse the previous code above or run the same commands directlyl in the terminal.\n", "\n", "You can launch a terminal directly from jupyter launcher or just from docker (if from docker you can sue the `bash` command from docker to get a proper bash terminal). \n", "\n", "To do it from jupyter, start a Terminal in the Launcher tab. You can use the terminal to launchany command, including slurm jobs via commands.\n", "\n", "\n", "# Compiling and Running Programs on an HPC System\n", "\n", "This notebook will guide you through the steps necessary to compile and run a computationally intensive C program on a High-Performance Computing (HPC) system. We will cover both basic and advanced topics, focusing on using specific compilers and modules available on the HPC.\n", "\n", "## Why Use an HPC for Compiling?\n", "\n", "Compiling and running programs on an HPC system can significantly enhance performance for compute-intensive tasks. This is due to several advantages that HPC systems provide:\n", "- **Access to specialized compilers and libraries:** Optimized to exploit the hardware capabilities like multiple cores, high-performance GPUs, and fast interconnects.\n", "- **Module systems for easy software management:** Allows users to easily load and switch between different software environments and libraries needed for different applications.\n", "- **Enhanced computational power:** With more processors, memory, and storage than a typical desktop or laptop, HPC systems can handle much larger computations.\n", "\n", "## Example Program: `calculate_pi.c`\n", "\n", "Instead of a simple hello world program, we will use a more complex C program that calculates the value of Pi using the Monte Carlo method. This method involves simulating random points and assessing how many fall within a quarter circle inscribed in a unit square. The ratio of points inside the circle to the total points approximates Pi/4.\n", "\n", "Here's the source code for `calculate_pi.c`:\n" ] }, { "cell_type": "code", "execution_count": 8, "id": "straight-lighter", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Complex C program written to calculate_pi.c with command-line argument support.\n" ] } ], "source": [ "import os\n", "\n", "# Define the path for the C program file\n", "c_program_path = \"calculate_pi.c\"\n", "\n", "# Remove the existing file if it exists\n", "if os.path.exists(c_program_path):\n", " os.remove(c_program_path)\n", "\n", "# Create and write the C program\n", "c_program = \"\"\"\n", "#include \n", "#include \n", "#include \n", "\n", "int main(int argc, char *argv[]) {\n", " if (argc < 2) {\n", " fprintf(stderr, \"Usage: %s \\\\n\", argv[0]);\n", " return 1;\n", " }\n", " \n", " int iterations = atoi(argv[1]);\n", " if (iterations <= 0) {\n", " fprintf(stderr, \"Please provide a positive integer for iterations.\\\\n\");\n", " return 1;\n", " }\n", "\n", " int inside = 0;\n", " double x, y, pi;\n", "\n", " srand(time(NULL)); // Seed the random number generator\n", "\n", " for (int i = 0; i < iterations; i++) {\n", " x = (double)rand() / RAND_MAX;\n", " y = (double)rand() / RAND_MAX;\n", " if (x * x + y * y <= 1) {\n", " inside++;\n", " }\n", " }\n", "\n", " pi = (double)inside / iterations * 4;\n", " printf(\"Approximation of Pi: %f\\\\n\", pi);\n", "\n", " return 0;\n", "}\n", "\"\"\"\n", "\n", "# Write the C program to a file\n", "with open(c_program_path, \"w\") as file:\n", " file.write(c_program)\n", "\n", "print(f\"Complex C program written to {c_program_path} with command-line argument support.\")\n" ] }, { "cell_type": "markdown", "id": "corrected-federation", "metadata": {}, "source": [ "### 2. Compile the Program\n", "\n", "Use the `gcc` command to compile `calculate_pi.c` and generate an executable named `calculate_pi`:\n", "\n", "1. Load the Necessary Modules\n", "HPC systems use module systems to manage software environments. Before compiling, load the appropriate compiler module. Here, we'll use the GCC compiler:" ] }, { "cell_type": "code", "execution_count": 9, "id": "fluid-supplement", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Compiling the C program...\n", "Compilation successful, executable 'calculate_pi' created.\n" ] } ], "source": [ "import subprocess\n", "import os\n", "\n", "# Compile the C program using gcc\n", "compile_command = \"gcc calculate_pi.c -o calculate_pi\" # Corrected output file name\n", "compile_process = subprocess.run(compile_command, shell=True, capture_output=True, text=True)\n", "\n", "# Print the output and error (if any) after compilation attempt\n", "print(\"Compiling the C program...\")\n", "if compile_process.stdout:\n", " print(\"Output:\", compile_process.stdout)\n", "if compile_process.stderr:\n", " print(\"Error:\", compile_process.stderr)\n", "\n", "# Check if the executable was created\n", "if os.path.exists(\"calculate_pi\"): # Corrected executable file name\n", " print(\"Compilation successful, executable 'calculate_pi' created.\")\n", "else:\n", " print(\"Compilation failed.\")\n" ] }, { "cell_type": "markdown", "id": "loaded-turner", "metadata": {}, "source": [ "### Run the Program\n", "\n", "Now we will execute the program. \n", "\n", "**As it is doing 100000000 ITERATIONS it will take time, Be patient!** \n", "\n", "Execute the program with the following command to see the output:\n" ] }, { "cell_type": "code", "execution_count": 10, "id": "perceived-soundtrack", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Approximation of Pi: 3.141777\n", "\n", "\n" ] } ], "source": [ "import subprocess\n", "\n", "# Compile the C program first if it hasn't been compiled\n", "compile_command = [\"gcc\", \"calculate_pi.c\", \"-o\", \"calculate_pi\"]\n", "subprocess.run(compile_command)\n", "\n", "# Run the compiled program\n", "run_program = subprocess.run([\"./calculate_pi\", \"100000000\"], capture_output=True, text=True)\n", "\n", "# Print the output of the program\n", "print(run_program.stdout)\n", "print(run_program.stderr)\n" ] }, { "cell_type": "markdown", "id": "oriented-aircraft", "metadata": {}, "source": [ "# Resource managers and Slurm\n", "## What is a Resource Manager?\n", "An HPC system is made up of smaller constituent systems all working together. Normally, all of our interactions are with one computer, which is the login node of a cluster. This is because we have not yet learned to use a _resource manager_. A _resource manager_ is a program that contains both a server, running on a head node, and any number of clients, running on worker nodes. The client allows worker nodes to ask the head node for work, and the server provides jobs to carry out. Almost all clusters have some form of resource manager on them which allows users to submit and monitor jobs to be run on the worker nodes. Most resource managers also have scheduling systems which allow them to run jobs in different orders based on a number of parameters. \n", "\n", "\n" ] }, { "cell_type": "markdown", "id": "fatal-holder", "metadata": {}, "source": [ "## Introduction to SLURM\n", "\n", "SLURM (Simple Linux Utility for Resource Management) is a powerful scheduler that helps manage resources and schedule jobs on an HPC cluster.\n", "\n", "The following image describes the job flow of Slurm, a commonly used resource manager:\n", "\n", "![SLURM architecture](https://slurm.schedmd.com/arch.gif)\n", "\n", "### Main SLURM Commands\n", "- `srun`: Run parallel jobs.\n", "- `sbatch`: Submit a batch job script to the scheduler.\n", "- `squeue`: View the job queue.\n", "- `scancel`: Cancel a job.\n", "- `sinfo`: View information about the nodes and partitions.\n", "\n", "In this notebook, we will create, compile, and run a simple C program using SLURM.\n" ] }, { "cell_type": "markdown", "id": "separate-brunei", "metadata": {}, "source": [ "# Understanding Cluster Configuration with `sinfo`\n", "\n", "The `sinfo` command in SLURM provides detailed information about the current state of the nodes and partitions within the HPC cluster. This command is essential for users to understand the availability and status of resources before submitting jobs.\n", "\n", "## Key Outputs of `sinfo`\n", "\n", "- **PARTITION**: Shows the partition names.\n", "- **AVAIL**: Indicates if the partition is available (`up`) or not (`down`).\n", "- **TIMELIMIT**: Lists the maximum time that jobs are allowed to run in the partition.\n", "- **NODES**: Shows the number of nodes in each state.\n", "- **STATE**: Indicates the state of the nodes (e.g., `idle`, `alloc` for allocated, etc.).\n", "- **NODELIST**: Provides the specific names or identifiers of the nodes.\n", "\n", "By default, `sinfo` displays a brief summary. To get more detailed information, you can use various flags with this command.\n", "\n", "## Example Commands\n", "\n", "- `sinfo`: Provides a basic overview of the cluster.\n", "- `sinfo -l`: Provides a detailed view.\n", "- `sinfo -N`: Lists information node by node.\n", "- `sinfo -s`: Displays a short format.\n", "\n", "Let's run a basic `sinfo` command to see the current state of the cluster.\n" ] }, { "cell_type": "code", "execution_count": 11, "id": "hidden-space", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "PARTITION AVAIL TIMELIMIT NODES STATE NODELIST\n", "cpubase_bycore_b1* up infinite 1 mix node1\n", "cpubase_bycore_b1* up infinite 1 alloc node2\n", "cpubase_bycore_b1* up infinite 2 idle node[3-4]\n", "node up infinite 1 mix node1\n", "node up infinite 1 alloc node2\n", "node up infinite 2 idle node[3-4]\n" ] } ], "source": [ "!sinfo" ] }, { "cell_type": "markdown", "id": "69d4023c-0b6c-4472-8a05-f346e6d2f584", "metadata": {}, "source": [ "## Understanding Cluster Control with `scontrol`\n", "The `scontrol` command in SLURM is a powerful tool used to display and modify the configuration and state of various cluster components, such as nodes, partitions, jobs, and more. This command is especially useful for administrators or advanced users who need to view detailed cluster information or modify resource settings.\n", "\n", "### Key Functionalities of `scontrol`\n", "- **Show Node Information:** Displays detailed information about individual nodes in the cluster, such as their CPU count, memory, state, and more.\n", "- **Show Partition Information:** Retrieves detailed information about the partitions in the cluster, including their resource limits and node assignments.\n", "- **Show Job Information:** Displays information about specific jobs, including their current state, resources used, and associated nodes.\n", "- **Modify Jobs/Nodes:** Allows administrators to update the state of nodes or jobs (e.g., draining a node or cancelling a job).\n", "\n", "### Example Commands\n", "\n", "#### 1. **Display Partition Information**\n", "```bash\n", "scontrol show partition\n" ] }, { "cell_type": "code", "execution_count": 14, "id": "f3795aa6-aa27-4665-a1fd-547af424f930", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "PartitionName=cpubase_bycore_b1\n", " AllowGroups=ALL AllowAccounts=ALL AllowQos=ALL\n", " AllocNodes=ALL Default=YES QoS=N/A\n", " DefaultTime=01:00:00 DisableRootJobs=YES ExclusiveUser=NO GraceTime=0 Hidden=NO\n", " MaxNodes=UNLIMITED MaxTime=UNLIMITED MinNodes=0 LLN=NO MaxCPUsPerNode=UNLIMITED MaxCPUsPerSocket=UNLIMITED\n", " Nodes=node[1-4]\n", " PriorityJobFactor=1 PriorityTier=1 RootOnly=NO ReqResv=NO OverSubscribe=YES:4\n", " OverTimeLimit=NONE PreemptMode=OFF\n", " State=UP TotalCPUs=8 TotalNodes=4 SelectTypeParameters=NONE\n", " JobDefaults=(null)\n", " DefMemPerCPU=256 MaxMemPerNode=UNLIMITED\n", " TRES=cpu=8,mem=16000M,node=4,billing=8\n", " ResumeTimeout=GLOBAL SuspendTimeout=GLOBAL SuspendTime=GLOBAL PowerDownOnIdle=NO\n", "\n", "PartitionName=node\n", " AllowGroups=ALL AllowAccounts=ALL AllowQos=ALL\n", " AllocNodes=ALL Default=NO QoS=N/A\n", " DefaultTime=01:00:00 DisableRootJobs=YES ExclusiveUser=NO GraceTime=0 Hidden=NO\n", " MaxNodes=UNLIMITED MaxTime=UNLIMITED MinNodes=0 LLN=NO MaxCPUsPerNode=UNLIMITED MaxCPUsPerSocket=UNLIMITED\n", " Nodes=node[1-4]\n", " PriorityJobFactor=1 PriorityTier=1 RootOnly=NO ReqResv=NO OverSubscribe=YES:4\n", " OverTimeLimit=NONE PreemptMode=OFF\n", " State=UP TotalCPUs=8 TotalNodes=4 SelectTypeParameters=NONE\n", " JobDefaults=(null)\n", " DefMemPerCPU=256 MaxMemPerNode=UNLIMITED\n", " TRES=cpu=8,mem=16000M,node=4,billing=8\n", " ResumeTimeout=GLOBAL SuspendTimeout=GLOBAL SuspendTime=GLOBAL PowerDownOnIdle=NO\n", "\n" ] } ], "source": [ "!scontrol show partition\n" ] }, { "cell_type": "code", "execution_count": 15, "id": "e40632d5-3ddb-4475-adfb-d3cef6edee19", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "NodeName=node1 Arch=x86_64 CoresPerSocket=1 \n", " CPUAlloc=1 CPUEfctv=2 CPUTot=2 CPULoad=0.06\n", " AvailableFeatures=(null)\n", " ActiveFeatures=(null)\n", " Gres=gpu:0\n", " NodeAddr=node1 NodeHostName=node1 Version=23.02.7\n", " OS=Linux 5.14.0-427.13.1.el9_4.x86_64 #1 SMP PREEMPT_DYNAMIC Tue Apr 30 18:22:29 EDT 2024 \n", " RealMemory=4000 AllocMem=1024 FreeMem=2358 Sockets=2 Boards=1\n", " MemSpecLimit=512\n", " State=MIXED+CLOUD ThreadsPerCore=1 TmpDisk=0 Weight=1 Owner=N/A MCS_label=N/A\n", " Partitions=cpubase_bycore_b1,node \n", " BootTime=2024-09-07T09:45:18 SlurmdStartTime=2024-09-07T10:03:44\n", " LastBusyTime=2024-09-07T11:14:18 ResumeAfterTime=None\n", " CfgTRES=cpu=2,mem=4000M,billing=2\n", " AllocTRES=cpu=1,mem=1G\n", " CapWatts=n/a\n", " CurrentWatts=0 AveWatts=0\n", " ExtSensorsJoules=n/s ExtSensorsWatts=0 ExtSensorsTemp=n/s\n", "\n", "NodeName=node2 Arch=x86_64 CoresPerSocket=1 \n", " CPUAlloc=2 CPUEfctv=2 CPUTot=2 CPULoad=0.00\n", " AvailableFeatures=(null)\n", " ActiveFeatures=(null)\n", " Gres=gpu:0\n", " NodeAddr=node2 NodeHostName=node2 Version=23.02.7\n", " OS=Linux 5.14.0-427.31.1.el9_4.x86_64 #1 SMP PREEMPT_DYNAMIC Thu Aug 15 14:47:52 EDT 2024 \n", " RealMemory=4000 AllocMem=2048 FreeMem=2339 Sockets=2 Boards=1\n", " MemSpecLimit=512\n", " State=ALLOCATED+CLOUD ThreadsPerCore=1 TmpDisk=0 Weight=1 Owner=N/A MCS_label=N/A\n", " Partitions=cpubase_bycore_b1,node \n", " BootTime=2024-09-07T09:46:20 SlurmdStartTime=2024-09-07T10:03:46\n", " LastBusyTime=2024-09-07T11:03:55 ResumeAfterTime=None\n", " CfgTRES=cpu=2,mem=4000M,billing=2\n", " AllocTRES=cpu=2,mem=2G\n", " CapWatts=n/a\n", " CurrentWatts=0 AveWatts=0\n", " ExtSensorsJoules=n/s ExtSensorsWatts=0 ExtSensorsTemp=n/s\n", "\n", "NodeName=node3 Arch=x86_64 CoresPerSocket=1 \n", " CPUAlloc=0 CPUEfctv=2 CPUTot=2 CPULoad=0.02\n", " AvailableFeatures=(null)\n", " ActiveFeatures=(null)\n", " Gres=gpu:0\n", " NodeAddr=node3 NodeHostName=node3 Version=23.02.8\n", " OS=Linux 5.14.0-427.33.1.el9_4.x86_64 #1 SMP PREEMPT_DYNAMIC Fri Aug 30 09:45:56 EDT 2024 \n", " RealMemory=4000 AllocMem=0 FreeMem=2606 Sockets=2 Boards=1\n", " MemSpecLimit=512\n", " State=IDLE+CLOUD ThreadsPerCore=1 TmpDisk=0 Weight=1 Owner=N/A MCS_label=N/A\n", " Partitions=cpubase_bycore_b1,node \n", " BootTime=2024-09-07T09:45:12 SlurmdStartTime=2024-09-07T10:03:45\n", " LastBusyTime=2024-09-07T11:45:53 ResumeAfterTime=None\n", " CfgTRES=cpu=2,mem=4000M,billing=2\n", " AllocTRES=\n", " CapWatts=n/a\n", " CurrentWatts=0 AveWatts=0\n", " ExtSensorsJoules=n/s ExtSensorsWatts=0 ExtSensorsTemp=n/s\n", "\n", "NodeName=node4 Arch=x86_64 CoresPerSocket=1 \n", " CPUAlloc=0 CPUEfctv=2 CPUTot=2 CPULoad=0.00\n", " AvailableFeatures=(null)\n", " ActiveFeatures=(null)\n", " Gres=gpu:0\n", " NodeAddr=node4 NodeHostName=node4 Version=23.02.8\n", " OS=Linux 5.14.0-427.33.1.el9_4.x86_64 #1 SMP PREEMPT_DYNAMIC Fri Aug 30 09:45:56 EDT 2024 \n", " RealMemory=4000 AllocMem=0 FreeMem=328 Sockets=2 Boards=1\n", " MemSpecLimit=512\n", " State=IDLE+CLOUD ThreadsPerCore=1 TmpDisk=0 Weight=1 Owner=N/A MCS_label=N/A\n", " Partitions=cpubase_bycore_b1,node \n", " BootTime=2024-09-07T10:07:45 SlurmdStartTime=2024-09-07T10:14:22\n", " LastBusyTime=2024-09-07T11:45:53 ResumeAfterTime=None\n", " CfgTRES=cpu=2,mem=4000M,billing=2\n", " AllocTRES=\n", " CapWatts=n/a\n", " CurrentWatts=0 AveWatts=0\n", " ExtSensorsJoules=n/s ExtSensorsWatts=0 ExtSensorsTemp=n/s\n", "\n" ] } ], "source": [ "!scontrol show node" ] }, { "cell_type": "markdown", "id": "chinese-moral", "metadata": {}, "source": [ "## Creating and Submitting a SLURM Job\n", "\n", "Users submit tasks to a queue, which are then ordered by priority rules set by administrators, and those jobs get run on any available backend resources.\n", "\n", "\n", "**srun** is used to submit a job for execution in real time\n", "\n", "while\n", "\n", "**sbatch** is used to submit a job script for later execution.\n", "\n", "They both accept practically the same set of parameters. The main difference is that srun is interactive and blocking (you get the result in your terminal and you cannot write other commands until it is finished), while sbatch is batch processing and non-blocking (results are written to a file and you can submit other commands right away).\n", "\n", "If you use **srun** in the background with the & sign, then you remove the 'blocking' feature of srun, which becomes interactive but non-blocking. It is still interactive though, meaning that the output will clutter your terminal, and the srun processes are linked to your terminal. If you disconnect, you will loose control over them, or they might be killed (depending on whether they use stdout or not basically). And they will be killed if the machine to which you connect to submit jobs is rebooted.\n", "To run our compiled program on the HPC cluster, we need to create a SLURM job script. This script specifies the resources required and the commands to execute.\n", "\n", "### SLURM Job Script Example\n", "Below is a simple SLURM script that requests 1 compute node for 5 minutes and runs our `hello_hpc` executable.\n", "\n", "```bash\n", "#!/bin/bash\n", "#SBATCH --job-name=calculate_pi\n", "#SBATCH --output=calculate_pi.out\n", "#SBATCH --error=calculate_pi.err\n", "#SBATCH --time=00:05:00\n", "#SBATCH --nodes=1\n", "#SBATCH --mem=1G # Allocates 1 GB of total memory to the job\n", "\n", "# Load necessary modules\n", "module load gcc\n", "\n", "# Run the executable\n", "srun ./calculate_pi 1000000000\n" ] }, { "cell_type": "code", "execution_count": 22, "id": "fantastic-lithuania", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "SLURM job script written to calculate_pi.slurm.\n", "\n", "Contents of the SLURM job script:\n", "----------------------------------\n", "#!/bin/bash\n", "#SBATCH --job-name=calculate_pi\n", "#SBATCH --output=calculate_pi.out\n", "#SBATCH --error=calculate_pi.err\n", "#SBATCH --time=00:05:00\n", "#SBATCH --nodes=1\n", "#SBATCH --mem=500M # Allocates 500MB of total memory to the job\n", "\n", "# Load necessary modules\n", "module load gcc\n", "\n", "# Run the executable\n", "srun ./calculate_pi 1000000000\n", "\n" ] } ], "source": [ "import os\n", "\n", "# Define the SLURM job script path\n", "slurm_script_path = \"calculate_pi.slurm\"\n", "\n", "# Remove existing SLURM script if it exists\n", "if os.path.exists(slurm_script_path):\n", " os.remove(slurm_script_path)\n", "\n", "# Create the SLURM job script with explicit path to bash\n", "slurm_script = \"\"\"#!/bin/bash\n", "#SBATCH --job-name=calculate_pi\n", "#SBATCH --output=calculate_pi.out\n", "#SBATCH --error=calculate_pi.err\n", "#SBATCH --time=00:05:00\n", "#SBATCH --nodes=1\n", "#SBATCH --mem=500M # Allocates 500MB of total memory to the job\n", "\n", "# Load necessary modules\n", "module load gcc\n", "\n", "# Run the executable\n", "srun ./calculate_pi 1000000000\n", "\"\"\"\n", "\n", "# Write the SLURM job script to a file\n", "with open(slurm_script_path, \"w\") as file:\n", " file.write(slurm_script)\n", "\n", "# Confirm the file has been written\n", "print(f\"SLURM job script written to {slurm_script_path}.\")\n", "\n", "# Make the script executable\n", "os.chmod(slurm_script_path, 0o755)\n", "\n", "# Read and print the contents of the SLURM job script\n", "with open(slurm_script_path, \"r\") as file:\n", " script_content = file.read()\n", "\n", "print(\"\\nContents of the SLURM job script:\")\n", "print(\"----------------------------------\")\n", "print(script_content)\n", "\n", "\n" ] }, { "cell_type": "markdown", "id": "frozen-feelings", "metadata": {}, "source": [ "### Submitting and Monitoring a SLURM Job in Jupyter Notebook\n", "\n", "This section of the notebook demonstrates how to submit a SLURM job using the `sbatch` command and monitor its status using the `squeue` command. We will execute these commands directly from the Jupyter Notebook using the `!` syntax, which allows us to run shell commands in a more interactive manner.\n", "\n", "#### Submitting the SLURM Job\n", "\n", "We use the `sbatch` command to submit a job to the SLURM scheduler. The job script `calculate_pi.slurm` contains instructions for the SLURM workload manager on how to execute the task. This script specifies the resources needed and the executable to run.\n", "\n", "#### Allowing Time for Job Queueing\n", "To ensure that the job is queued before we check its status, we include a short delay using Python's time.sleep() function. This is crucial as SLURM may take a few moments to update the queue, especially in busy environments.\n", "\n", "#### Checking the Job Status\n", "After submitting the job, we use the squeue command to check the status of jobs in the queue. This command lists all jobs that are currently queued or running, allowing us to monitor the status of our job.\n" ] }, { "cell_type": "code", "execution_count": 23, "id": "medium-atmosphere", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Submitted batch job 68\n", " JOBID PARTITION NAME USER ST TIME NODES NODELIST(REASON)\n", " 63 cpubase_b spawner- user002 R 45:38 1 node2\n", " 64 cpubase_b spawner- user001 R 15:12 1 node1\n", " 68 cpubase_b calculat user001 R 0:03 1 node1\n" ] } ], "source": [ "import time\n", "import subprocess\n", "\n", "# Submit the SLURM job using the `!` syntax for direct shell command execution\n", "!sbatch {\"calculate_pi.slurm\"}\n", "\n", "# Wait for a few seconds to ensure the job is queued\n", "time.sleep(3)\n", "\n", "# Check the status of the job queue\n", "!squeue" ] }, { "cell_type": "markdown", "id": "54c1a5aa-4359-49be-8e58-a14e23d0d140", "metadata": {}, "source": [ "Wait until the job has finished. You can check it running multiple times the command below:" ] }, { "cell_type": "code", "execution_count": 32, "id": "homeless-enough", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ " JOBID PARTITION NAME USER ST TIME NODES NODELIST(REASON)\n", " 63 cpubase_b spawner- user002 R 46:03 1 node2\n", " 64 cpubase_b spawner- user001 R 15:37 1 node1\n" ] } ], "source": [ "!squeue" ] }, { "cell_type": "markdown", "id": "falling-lodging", "metadata": {}, "source": [ "### Examining SLURM Job Output and Error Files\n", "\n", "Once a SLURM job is submitted and executed, it generates output and error files specified in the job script. These files contain valuable information about the execution of the program, including any results printed to the console and any error messages that occurred during execution.\n", "\n", "#### Understanding Output and Error Files\n", "\n", "##### Output File (`calculate_pi.out`) **\n", "\n", "The output file contains the standard output from the program execution. This includes any `printf` statements or other console outputs generated by the C program. In our case, this file will contain the approximate value of Pi calculated by our program.\n", "\n", "##### Error File (`calculate_pi.err`)\n", "\n", "The error file captures any standard error messages produced by the program. This includes any compilation or runtime errors, warnings, or other messages that are sent to the error stream.\n", "\n", "#### Code to Display the Contents of Output and Error Files\n", "\n", "Let's write code to read and display the contents of these files, allowing us to verify the results and diagnose any potential issues.\n" ] }, { "cell_type": "code", "execution_count": 33, "id": "together-iceland", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\n", "Contents of calculate_pi.out:\n", "----------------------------------\n", "Approximation of Pi: 3.141614\n", "\n", "\n", "Contents of calculate_pi.err:\n", "----------------------------------\n", "\n" ] } ], "source": [ "import os\n", "\n", "# Paths to the output and error files\n", "output_file = \"calculate_pi.out\"\n", "error_file = \"calculate_pi.err\"\n", "\n", "# Check and display the contents of the output file\n", "if os.path.exists(output_file):\n", " print(f\"\\nContents of {output_file}:\")\n", " print(\"----------------------------------\")\n", " with open(output_file, \"r\") as file:\n", " output_content = file.read()\n", " print(output_content)\n", "else:\n", " print(f\"\\n{output_file} does not exist.\")\n", "\n", "# Check and display the contents of the error file\n", "if os.path.exists(error_file):\n", " print(f\"\\nContents of {error_file}:\")\n", " print(\"----------------------------------\")\n", " with open(error_file, \"r\") as file:\n", " error_content = file.read()\n", " print(error_content)\n", "else:\n", " print(f\"\\n{error_file} does not exist.\")\n" ] }, { "cell_type": "code", "execution_count": null, "id": "cordless-shame", "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "markdown", "id": "sporting-attachment", "metadata": {}, "source": [ "# Understanding `srun` in SLURM\n", "\n", "In SLURM, both `sbatch` and `srun` are used to execute jobs on an HPC cluster, but they serve different purposes and are used in distinct scenarios. Understanding when to use each command is essential for effective job management and resource utilization.\n", "\n", "## `sbatch` vs. `srun`\n", "\n", "### `sbatch`\n", "\n", "- **Purpose**: Submits a batch job script to the scheduler to be executed at a later time when resources become available.\n", "- **Usage**: Primarily used for batch processing of non-interactive tasks, where you write a script with job specifications and submit it to the queue.\n", "- **Execution**: The job runs according to the specified resources and constraints in the SLURM script without user interaction during execution.\n", "\n", "### `srun`\n", "\n", "- **Purpose**: Launches parallel tasks and can be used for both interactive and non-interactive job execution.\n", "- **Usage**: Often used for interactive jobs or to launch parallel tasks within an already scheduled job.\n", "- **Execution**: `srun` can be used to run tasks interactively on compute nodes or to start tasks within a running job environment, providing more flexibility for dynamic task execution.\n", "\n", "## When to Use `srun`\n", "\n", "- **Interactive Jobs**: Use `srun` to start an interactive session on a compute node for testing, debugging, or running tasks interactively.\n", "- **Within Scripts**: Use `srun` within an `sbatch` script to launch parallel tasks that require coordination across multiple CPUs or nodes.\n", "- **Dynamic Execution**: Use `srun` to dynamically allocate resources and run tasks without needing to pre-write a batch script.\n", "\n", "## Example Usage\n", "\n", "We will demonstrate how to use `srun` to run a simple interactive job and a parallel computation task.\n", "\n" ] }, { "cell_type": "code", "execution_count": 34, "id": "vietnamese-lightning", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "node1.int.hpcie.labs.faculty.ie.edu\n" ] } ], "source": [ "# Use srun to start an interactive session on a compute node\n", "# Note: This command is typically run in a terminal, not directly executable in a Jupyter Notebook.\n", "\n", "!srun hostname\n", "\n", "# Explanation:\n", "# --pty: Allocates a pseudo-terminal from the compute node allocated, allowing interactive command execution.\n", "# bash -i: Starts an interactive bash shell session.\n" ] }, { "cell_type": "markdown", "id": "parental-irrigation", "metadata": {}, "source": [ "## Interactive SLURM Usage in Jupyter Terminal\n", "\n", "This guide will help you explore SLURM commands interactively within a Jupyter terminal. By practicing these commands, you'll gain familiarity with job scheduling, monitoring, and resource management on an HPC cluster.\n", "\n", "### 1. Access the Shell in Jupyter\n", "\n", "#### Open a New Terminal\n", "\n", "- **Open a Launcher**: Click on the `+` icon or `New Launcher` to open the launcher.\n", "- **Select Terminal**: From the launcher, click on `Terminal` to open a new shell session. This terminal acts like a login node interface.\n", "\n", "### 2. Run Basic Linux Commands\n", "\n", "Before diving into SLURM, familiarize yourself with some basic Linux commands to navigate and manage your files.\n", "\n", "- **List Files and Directories**: \n", " - Run the command `ls` to show the content of the current folder.\n", " \n", "- **Print Current Directory**:\n", " - Run the command `pwd` to display the current directory path.\n", "\n", "### 3. SLURM Commands for Job Management\n", "\n", "Learn how to interact with SLURM to manage and monitor your computational jobs.\n", "\n", "- **Check Available Partitions**:\n", " - Run the command `sinfo` to display available partitions and their status. This is useful for determining resource availability and node types.\n", "\n", "- **View Job Queue**:\n", " - Run the command `squeue` to show the current job queue. This command displays jobs currently running or waiting, along with their IDs, user names, and statuses.\n", "\n", "- **Submit a Job Script**:\n", " - Use the command `sbatch calculate_pi.slurm` to submit a batch job to the SLURM scheduler for execution when resources are available. Replace `calculate_pi.slurm` with the name of your actual job script.\n", "\n", "- **Check Your Job Status**:\n", " - Use `squeue -u $USER` to list all jobs submitted by the current user, allowing you to monitor their progress and status.\n", "\n", "- **Cancel a Job**:\n", " - Run `scancel ` to cancel a job specified by its job ID. Replace `` with the actual job ID you wish to cancel.\n", "\n", "### 4. Running Interactive Jobs\n", "\n", "Explore interactive job sessions to dynamically test and run tasks on compute nodes.\n", "\n", "- **Start an Interactive Session**:\n", " - Use `srun --pty bash -i` to allocate resources and start an interactive bash session on a compute node. This is ideal for debugging and interactive computations.\n", "\n", " **What You Can Do**:\n", " - Run commands interactively.\n", " - Test scripts with immediate feedback.\n", " - Explore resource usage in real-time.\n", "\n", "### 5. Analyze Job Performance with `sacct`\n", "\n", "After jobs have completed, use `sacct` to gather detailed information about their execution.\n", "\n", "- **View Completed Job Details**:\n", " - Run `sacct --format=JobID,JobName,User,State,Elapsed,CPUTime,MaxRSS` to provide detailed statistics for completed jobs, such as CPU time, memory usage, and job state. This helps in understanding job performance and resource utilization.\n", "\n", "## Discussion and Reflection\n", "\n", "- **Efficiency**: Reflect on how interactive SLURM commands enhance your ability to manage computational workloads effectively.\n", "- **Troubleshooting**: Consider how interactive sessions can assist in diagnosing job issues and refining scripts.\n", "- **Further Exploration**: Explore additional SLURM commands and options to optimize job scheduling and resource allocation.\n", "\n", "By following this guide, you will gain hands-on experience with SLURM and Linux shell commands, equipping you with the skills needed to navigate and utilize HPC resources effectively.\n" ] }, { "cell_type": "markdown", "id": "streaming-terrorism", "metadata": {}, "source": [ "## Understanding `sacct` in SLURM\n", "\n", "The `sacct` command in SLURM is used to report accounting information about jobs and job steps that are managed by the SLURM workload manager. It provides detailed information about the jobs, such as resource usage, runtime statistics, and job states, which are crucial for performance analysis and optimization.\n", "\n", "### Key Features of `sacct`\n", "\n", "- **Job and Step Information**: `sacct` provides data on both jobs and individual job steps, offering insights into how resources were utilized at each stage of execution.\n", "- **Comprehensive Metrics**: Reports on CPU time, memory usage, job states, exit codes, and more, helping users identify bottlenecks or inefficiencies.\n", "- **Historical Data**: Accesses records of past jobs, allowing users to review previous job performances and resource consumption.\n", "\n", "### Common `sacct` Options\n", "\n", "- `-j `: Specifies a particular job ID to retrieve information for that job.\n", "- `--format`: Customizes the output format by specifying the fields to display.\n", "- `--starttime`: Limits the report to jobs that started after a specified time.\n", "- `-a` or `--allusers`: Displays information for all users (requires admin privileges).\n", "\n", "### Example Usage\n", "\n", "In this environmnet we do not have activated the DB for the sacc so it is not possible to use it here. I include some examples:\n" ] }, { "cell_type": "markdown", "id": "29b65156-3d37-4e01-9ff1-2d8e7a2ce307", "metadata": {}, "source": [ "## HPC Job Submission with Multiple Nodes in SLURM\n", "\n", "### Overview\n", "\n", "In high-performance computing (HPC) environments, jobs often need to be distributed across multiple nodes to fully utilize the available resources. SLURM (Simple Linux Utility for Resource Management) is a job scheduling system that efficiently manages the distribution of these jobs across a cluster. By submitting a job that utilizes multiple nodes, users can parallelize tasks and significantly reduce computation time.\n", "\n", "### Running a Job on Multiple Nodes\n", "\n", "To run a job on multiple nodes using SLURM, you must create a SLURM batch script. This script specifies the resources your job requires, such as the number of nodes, CPUs per task, and the commands to be executed. When you submit this script to SLURM, the scheduler allocates the requested resources, executes the job, and handles output and error logging.\n", "\n", "### What Happens When You Submit the Job\n", "\n", "1. **Resource Allocation:**\n", " - When the job is submitted via the `sbatch` command, SLURM schedules the job based on the requested resources and current availability within the cluster. If the script requests multiple nodes, SLURM will allocate the specified number of nodes.\n", "\n", "2. **Task Distribution:**\n", " - SLURM uses the `srun` command within the script to distribute tasks across the allocated nodes. Each node executes the specified command or program. For example, if the command is `hostname`, each node will execute it, and the hostname of each node will be returned.\n", "\n", "3. **Execution and Output:**\n", " - The tasks are executed in parallel on the different nodes. The output from these tasks is captured and saved to files specified in the script (e.g., `output.out` for standard output and `error.err` for errors). This allows you to review the results and any potential issues after the job has completed.\n", "\n", "4. **Completion and Monitoring:**\n", " - Once the tasks are completed, SLURM releases the resources, making them available for other jobs. You can monitor the job's progress using the `squeue` command, which shows the job status and other details.\n", "\n", "### Explanation of the Process\n", "\n", "- **Parallel Execution:** By distributing the job across multiple nodes, SLURM allows tasks to be executed in parallel, leveraging the full computational power of the cluster. This is particularly beneficial for large-scale computations that would be time-prohibitive on a single node.\n", "\n", "- **Efficiency and Scalability:** SLURM efficiently manages resource allocation and job scheduling, ensuring that resources are not wasted and that the cluster operates at optimal efficiency. This scalability is key to handling the complex workloads typical in HPC environments.\n", "\n", "- **Output Management:** The output and error management features of SLURM make it easy to track and debug jobs. By directing output to specific files, users can review results and diagnose issues without interfering with ongoing tasks.\n", "\n", "This overview provides a clear understanding of how to utilize SLURM for submitting jobs across multiple nodes in an HPC environment and what happens during the execution of such jobs.\n" ] }, { "cell_type": "code", "execution_count": 55, "id": "informed-recipe", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\n", "Contents of the SLURM job script:\n", "----------------------------------\n", "#!/bin/bash\n", "#SBATCH --job-name=simple_multi_task # Job name\n", "#SBATCH --output=simple_multi_task.out # Standard output\n", "#SBATCH --error=simple_multi_task.err # Standard error\n", "#SBATCH --time=00:05:00 # Time limit of 5 minutes\n", "#SBATCH --nodes=2 # Number of nodes\n", "#SBATCH --ntasks-per-node=1 # Run one task per node\n", "#SBATCH --cpus-per-task=1 # Number of CPU cores per task\n", "#SBATCH --oversubscribe # Allow oversubscription\n", "#SBATCH --mem=1024M # Allocate 1GB of memory per node\n", "\n", "# Run hostname on each allocated node\n", "srun /bin/hostname\n", " \n" ] } ], "source": [ "import os\n", "\n", "try:\n", " # Define the SLURM job script path\n", " slurm_script_path = \"simple_multi_task.slurm\"\n", "\n", " # Remove existing SLURM script if it exists\n", " if os.path.exists(slurm_script_path):\n", " os.remove(slurm_script_path)\n", "\n", " # Create a SLURM job script to run `hostname` on multiple nodes\n", " slurm_script = \"\"\"#!/bin/bash\n", "#SBATCH --job-name=simple_multi_task # Job name\n", "#SBATCH --output=simple_multi_task.out # Standard output\n", "#SBATCH --error=simple_multi_task.err # Standard error\n", "#SBATCH --time=00:05:00 # Time limit of 5 minutes\n", "#SBATCH --nodes=2 # Number of nodes\n", "#SBATCH --ntasks-per-node=1 # Run one task per node\n", "#SBATCH --cpus-per-task=1 # Number of CPU cores per task\n", "#SBATCH --oversubscribe # Allow oversubscription\n", "#SBATCH --mem=1024M # Allocate 1GB of memory per node\n", "\n", "# Run hostname on each allocated node\n", "srun /bin/hostname\n", " \"\"\"\n", "\n", " # Write the SLURM job script to a file\n", " with open(slurm_script_path, \"w\") as file:\n", " file.write(slurm_script)\n", "\n", " # Make the script executable\n", " os.chmod(slurm_script_path, 0o755)\n", "\n", " # Read and print the contents of the SLURM job script\n", " with open(slurm_script_path, \"r\") as file:\n", " script_content = file.read()\n", "\n", " print(\"\\nContents of the SLURM job script:\")\n", " print(\"----------------------------------\")\n", " print(script_content)\n", "\n", "except Exception as e:\n", " print(f\"An error occurred: {e}\")\n" ] }, { "cell_type": "code", "execution_count": 56, "id": "grateful-consistency", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Submitted batch job 74\n", " JOBID PARTITION NAME USER ST TIME NODES NODELIST(REASON)\n", " 63 cpubase_b spawner- user002 R 53:02 1 node2\n", " 64 cpubase_b spawner- user001 R 22:36 1 node1\n", " 74 cpubase_b simple_m user001 R 0:02 2 node[3-4]\n" ] } ], "source": [ "import time\n", "import subprocess\n", "\n", "# Submit the SLURM job using the `!` syntax for direct shell command execution\n", "!sbatch {\"simple_multi_task.slurm\"}\n", "\n", "# Wait for a few seconds to ensure the job is queued\n", "time.sleep(2)\n", "\n", "# Check the status of the job queue\n", "!squeue" ] }, { "cell_type": "code", "execution_count": 58, "id": "eb12a8f2-a60c-429d-a397-cb8e356d7b03", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ " JOBID PARTITION NAME USER ST TIME NODES NODELIST(REASON)\n", " 63 cpubase_b spawner- user002 R 53:06 1 node2\n", " 64 cpubase_b spawner- user001 R 22:40 1 node1\n" ] } ], "source": [ "# Check the status of the job queue\n", "!squeue" ] }, { "cell_type": "markdown", "id": "53052d97-a016-4700-81e3-41d6f9c95021", "metadata": {}, "source": [ "Wait until the job has finished or if there is a problem cancel it. " ] }, { "cell_type": "code", "execution_count": 59, "id": "duplicate-scott", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\n", "Contents of simple_multi_task.out:\n", "----------------------------------\n", "node3.int.hpcie.labs.faculty.ie.edu\n", "node4.int.hpcie.labs.faculty.ie.edu\n", "\n", "\n", "Contents of simple_multi_task.err:\n", "----------------------------------\n", "\n" ] } ], "source": [ "import os\n", "\n", "# Paths to the output and error files\n", "output_file = \"simple_multi_task.out\"\n", "error_file = \"simple_multi_task.err\"\n", "\n", "# Check and display the contents of the output file\n", "if os.path.exists(output_file):\n", " print(f\"\\nContents of {output_file}:\")\n", " print(\"----------------------------------\")\n", " with open(output_file, \"r\") as file:\n", " output_content = file.read()\n", " print(output_content)\n", "else:\n", " print(f\"\\n{output_file} does not exist.\")\n", "\n", "# Check and display the contents of the error file\n", "if os.path.exists(error_file):\n", " print(f\"\\nContents of {error_file}:\")\n", " print(\"----------------------------------\")\n", " with open(error_file, \"r\") as file:\n", " error_content = file.read()\n", " print(error_content)\n", "else:\n", " print(f\"\\n{error_file} does not exist.\")\n" ] }, { "cell_type": "markdown", "id": "f3de0f74-881f-4c50-ae6c-f348f83a818e", "metadata": {}, "source": [ "## Using JupyterLab Terminal for HPC Practice\n", "\n", "Now that you've learned about HPC clusters and how to submit jobs using SLURM, it's time to practice these skills interactively. You can use the terminal in JupyterLab to mimic the process of working on a supercomputer, allowing you to gain hands-on experience with the commands and workflows you'll use in an actual HPC environment.\n", "\n", "### 1. Access the JupyterLab Terminal\n", "\n", "- **Open a New Terminal**: In JupyterLab, click on the `+` icon or `File > New > Terminal` to open a new terminal window. This terminal session simulates a login node, where you can interact with the system as you would on an HPC cluster.\n", "\n", "### 2. Basic Commands to Try\n", "\n", "Before diving into SLURM, familiarize yourself with a few basic Linux commands:\n", "- **List Files and Directories**: Use `ls` to display the contents of the current directory.\n", "- **Print Working Directory**: Use `pwd` to see the full path of the current directory.\n", "- **Create a Directory**: Use `mkdir test_directory` to create a new directory named `test_directory`.\n", "- **Change Directory**: Use `cd test_directory` to move into the newly created directory.\n", "\n", "### 3. SLURM Commands to Practice\n", "\n", "With the terminal open, try the following SLURM commands to practice managing jobs:\n", "\n", "- **Check Available Partitions**: Run `sinfo` to see the available partitions and their statuses.\n", "- **Submit a Job Script**: Create a simple SLURM job script, then submit it using `sbatch script_name.slurm`. For example:\n", " ```bash\n", " #!/bin/bash\n", " #SBATCH --job-name=test_job\n", " #SBATCH --output=test_job.out\n", " #SBATCH --time=00:01:00\n", " #SBATCH --nodes=1\n", " #SBATCH --mem=500M\n", "\n", " echo \"Running on $(hostname)\"\n" ] }, { "cell_type": "markdown", "id": "ba19bcc3-c07a-4d7a-8392-9041f9b895ad", "metadata": {}, "source": [ "## Using JupyterLab Terminal for HPC Practice\n", "\n", "Now that you've learned about HPC clusters and how to submit jobs using SLURM, it's time to practice these skills interactively. You can use the terminal in JupyterLab to mimic the process of working on a supercomputer, allowing you to gain hands-on experience with the commands and workflows you'll use in an actual HPC environment.\n", "\n", "### 1. Access the JupyterLab Terminal\n", "\n", "- **Open a New Terminal**: In JupyterLab, click on the `+` icon or `File > New > Terminal` to open a new terminal window. This terminal session simulates a login node, where you can interact with the system as you would on an HPC cluster.\n", "\n", "### 2. Basic Commands to Try\n", "\n", "Before diving into SLURM, familiarize yourself with a few basic Linux commands:\n", "- **List Files and Directories**: Use `ls` to display the contents of the current directory.\n", "- **Print Working Directory**: Use `pwd` to see the full path of the current directory.\n", "- **Create a Directory**: Use `mkdir test_directory` to create a new directory named `test_directory`.\n", "- **Change Directory**: Use `cd test_directory` to move into the newly created directory.\n", "- **View File Contents**: Use `cat` followed by a filename to view the contents of a file.\n", "\n", "### 3. SLURM Commands to Practice\n", "\n", "With the terminal open, try the following SLURM commands to practice managing jobs:\n", "\n", "- **Check Available Partitions**: Run `sinfo` to see the available partitions and their statuses.\n", "- **Submit a Job Script**: Create a simple SLURM job script, then submit it using `sbatch script_name.slurm`. For example:\n", " ```bash\n", " #!/bin/bash\n", " #SBATCH --job-name=test_job\n", " #SBATCH --output=test_job.out\n", " #SBATCH --time=00:01:00\n", " #SBATCH --nodes=1\n", " #SBATCH --mem=500M\n", "\n", " echo \"Running on $(hostname)\"\n" ] }, { "cell_type": "markdown", "id": "3e7cf752-7cb2-47df-8efe-73446aab113e", "metadata": {}, "source": [ "This is the end of this part of the practice. " ] }, { "cell_type": "code", "execution_count": null, "id": "3722bf7e-0f25-4f5b-a8b8-d0cde34b7d2b", "metadata": {}, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.9.6" } }, "nbformat": 4, "nbformat_minor": 5 }