{"id":152,"date":"2018-01-18T20:25:57","date_gmt":"2018-01-18T20:25:57","guid":{"rendered":"https:\/\/in.nau.edu\/hpc\/?page_id=152"},"modified":"2022-06-15T15:56:33","modified_gmt":"2022-06-15T22:56:33","slug":"job-arrays-old","status":"publish","type":"page","link":"https:\/\/in.nau.edu\/arc\/overview\/using-the-cluster-advanced\/job-arrays-old\/","title":{"rendered":"Job Arrays"},"content":{"rendered":"<h1>Job arrays<\/h1>\n<p>Job arrays allow you to leverage SLURM\u2019s ability to create multiple jobs from one script. Many of the situations where this is useful include:<\/p>\n<ul>\n<li>Establishing a list of commands to run and have a job created from each command in the list.<\/li>\n<li>Running many parameters against one set of data or analysis program.<\/li>\n<li>Running the same program multiple times with different sets of data.<\/li>\n<\/ul>\n<p>In these cases, as we have learned thus far, we would have to manually rerun the sbatch command multiple times for each of the aforementioned scenarios. Fortunately, SLURM allows us to automate this procedure using job arrays. Each array is considered to be one \u201carray job\u201d that has a specific ID. Each element of the array is one array task, which has it\u2019s own sub-ID. For example, if your \u201carray job\u201d ID was 1212985, your first \u201carray task\u201d that runs would have an ID of 1212985_0.<\/p>\n<!-- shortcode-accordion -->\n<div class=\"shortcode-accordion shortcode-accordion--closed\" style=\"position: relative;\" >\n        <a class=\"shortcode-accordion__trigger\" data-header=\"Example 1_0\" href=\"#\">\n      <div class=\"shortcode-accordion__header\">\n          <h4>Example 1 <span class=\"screen-reader-text\">Accordion Closed<\/span><\/h4>\n          <span class=\"shortcode-accordion__header__arrow\"><\/span>\n      <\/div>\n    <\/a>\n    <div class=\"shortcode-accordion__body\">\n        <!DOCTYPE html PUBLIC \"-\/\/W3C\/\/DTD HTML 4.0 Transitional\/\/EN\" \"http:\/\/www.w3.org\/TR\/REC-html40\/loose.dtd\">\n<html><body>\n<p>In this first simple example, we have several commands that we would like to run as separate jobs. As we have learned so far, we would have to individually run all of these commands, or create a script that runs each command in a different job step. If we did this, the jobs could take a while because they will be run in sequence. If we use a job array we can ensure that the jobs run in parallel.<\/p>\n<p>First, we make a file called &ldquo;commandlist&rdquo; that stores all of the commands we would like slurm to run:<\/p>\n<p><strong>commandlist<\/strong><\/p>\n<p style=\"padding-left: 30px;\">sleep 5<br>\nsleep 4<br>\nsleep 8<br>\nsleep 3<br>\nsleep 6<\/p>\n<p>Next, we create a bash script called &ldquo;command_array.sh&rdquo; that utilizes the SBATCH &ndash;&ndash;array feature (line numbers have been added for readability):<\/p>\n<p><strong>command_array.sh<\/strong><\/p>\n<p style=\"padding-left: 30px;\">1&nbsp; #!\/bin\/sh<br>\n2&nbsp; #SBATCH &ndash;&ndash;job-name=&rdquo;command-array&rdquo;<br>\n4&nbsp; #SBATCH &ndash;&ndash;output=&rdquo;\/scratch\/mkg52\/command_array-%A_%a.out&rdquo;<br>\n5&nbsp; #SBATCH &ndash;&ndash;workdir=&rdquo;\/home\/mkg52&Prime;<br>\n6&nbsp; #SBATCH &ndash;&ndash;array=1-5<br>\n7<br>\n8&nbsp; command=$(sed &ndash;n &ldquo;$SLURM_ARRAY_TASK_ID&rdquo;p commandlist)<br>\n9 srun $command<\/p>\n<p>There are three lines in particular in this script that make use of the job array feature:<\/p>\n<ul>\n<li>Line 6 tells SLURM to create an array of 5 items, numbered 1 through 5. This should be changed to match the number of jobs you need to run. In our case, we want this range to match the number of commands in our &ldquo;commandlist&rdquo; file.<\/li>\n<li>Line 8 utilizes one of SLURM&rsquo;s built in variables, called SLURM_ARRAY_TASK_ID. This accesses the specific task ID of the current task in the job array (e.g. 1 for the first task) and can be used like any bash variable. In this example, &ldquo;sed&rdquo; is being used to get the contents of a particular line in the &ldquo;commandlist&rdquo; file using SLURM_ARRAY_TASK_ID. For the first task, the &ldquo;command&rdquo; variable will be &ldquo;sleep 5&rdquo;.<\/li>\n<li>Line 4 uses a shorthand method of accessing the job array ID and array task ID and embedding them into the name of the output file. The &ldquo;%A&rdquo; represents the SLURM_ARRAY_JOB_ID variable (e.g. 1212985) and the &ldquo;%a&rdquo; represents the SLURM_ARRAY_TASK_ID variable (e.g. 1). This would generate an output file similar to &ldquo;command_array-1212985_1.out&rdquo; for the first element of the array.<\/li>\n<\/ul>\n<p>To run the job array, simply use sbatch like you would with any other script. (The creation of the array is taken care of by SLURM when it sees the &ndash;&ndash;array option)<\/p>\n<p style=\"padding-left: 30px;\">[mkg52@wind ~ ]$ sbatch command_array.sh<\/p>\n<p>You can see all of the jobs in the array running at once (or at least as many as SLURM will allow based on your priority or fairshare) using the &ldquo;squeue&rdquo; command:<\/p>\n<p style=\"padding-left: 30px;\"><img loading=\"lazy\" decoding=\"async\" class=\"wp-image-173 size-tall-banner-image-lg aligncenter\" src=\"https:\/\/in.nau.edu\/wp-content\/uploads\/sites\/208\/2018\/01\/Screen-Shot-2018-01-18-at-2.07.30-PM-944x576.png\" alt=\"Screen Shot\" width=\"550\" height=\"576\"><br>\n<\/p><\/body><\/html>\n\n    <\/div>\n<\/div>\n\n<!-- shortcode-accordion -->\n<div class=\"shortcode-accordion shortcode-accordion--closed\" style=\"position: relative;\" >\n        <a class=\"shortcode-accordion__trigger\" data-header=\"Example 2_0\" href=\"#\">\n      <div class=\"shortcode-accordion__header\">\n          <h4>Example 2 <span class=\"screen-reader-text\">Accordion Closed<\/span><\/h4>\n          <span class=\"shortcode-accordion__header__arrow\"><\/span>\n      <\/div>\n    <\/a>\n    <div class=\"shortcode-accordion__body\">\n        <!DOCTYPE html PUBLIC \"-\/\/W3C\/\/DTD HTML 4.0 Transitional\/\/EN\" \"http:\/\/www.w3.org\/TR\/REC-html40\/loose.dtd\">\n<html><body>\n<p>With SLURM, it is also possible to create jobs that send different parameters to the same set of data. In this next example, we are going to use a simple program written in R that calculates the area of a triangle given two sides and an angle as input.<\/p>\n<p>In this scenario we will assume that two of the sides of the triangle are known, but we want to calculate how the area will change if the angle between those two sides changes. Let&rsquo;s consider each integer angle from 1 to 15 degrees. Below are the R program for calculating the area of the triangle and the bash script that calls the program:<\/p>\n<p><strong>area_of_triangle.r<\/strong><\/p>\n<p style=\"padding-left: 30px;\"># take in 3 integers, 2 sides of a triangle and the angle between them<\/p>\n<p style=\"padding-left: 30px;\">args &lt;- commandArgs(TRUE)<\/p>\n<p style=\"padding-left: 30px;\">side_a &lt;- strtoi(args[1], base=10L)<br>\nside_b &lt;- strtoi(args[2], base=10L)<br>\nangle &lt;- strtoi(args[3], base=10L)<\/p>\n<p style=\"padding-left: 30px;\">area = (1\/2)*side_a*side_b*sin(angle*pi\/180)<br>\nsprintf(&ldquo;The area of a triangle with sides %i and %i with angle %i degrees &nbsp;is %f&rdquo;, side_a, side_b, angle, area)<\/p>\n<p><strong>job_array_triangle.sh<\/strong><\/p>\n<p style=\"padding-left: 30px;\">#!\/bin\/bash<\/p>\n<p style=\"padding-left: 30px;\">#SBATCH &ndash;&ndash;job-name=&rdquo;Area of Triangles&rdquo;<br>\n#SBATCH &ndash;&ndash;output=\/scratch\/mkg52\/area_of_triangle_5_8_%a.out<br>\n#SBATCH &ndash;&ndash;workdir=\/home\/mkg52<br>\n#SBATCH &ndash;&ndash;array=1-15<\/p>\n<p style=\"padding-left: 30px;\">module load R<\/p>\n<p style=\"padding-left: 30px;\"># calculate the area of a triangle with 2 sides given, and a<br>\n# variable angle in degrees between them (Side-Angle-Side)<br>\nsrun Rscript area_of_triangle.r 5 8 ${SLURM_ARRAY_TASK_ID}<\/p>\n<p>The srun command in the &ldquo;Job_array_triangle.sh&rdquo; script is passing the same first two arguments (5 and 8) to each task of the array, but is changing the third to be whatever the current task ID is. So the first task calls &ldquo;srun Rscript area_of_triangle.r 5 8 1&rdquo; because our first array task starts at 1.<\/p>\n<p>Running the above script with &ldquo;sbatch job_array _triangle.sh&rdquo; creates a job array with 15 tasks, thus producing 15 different output files. Each file calculates a unique area. Below is a directory listing of the output folder.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-short-banner-image-xl wp-image-303\" src=\"https:\/\/in.nau.edu\/wp-content\/uploads\/sites\/208\/2018\/01\/sbatch-job-array-triangle-1108x600.png\" alt=\"sbatch job array triangle snapshot\" width=\"1300\" height=\"800\"><\/p>\n<p>Viewing the contents of one of the files shows the result of the calculation:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"size-short-banner-image wp-image-266 aligncenter\" src=\"https:\/\/in.nau.edu\/wp-content\/uploads\/sites\/208\/2018\/01\/Job-Array-example-2-job-array-result-960x186.png\" alt=\"Job Array output result \" width=\"550\" height=\"186\"><\/p>\n<\/body><\/html>\n\n    <\/div>\n<\/div>\n\n<!-- shortcode-accordion -->\n<div class=\"shortcode-accordion shortcode-accordion--closed\" style=\"position: relative;\" >\n        <a class=\"shortcode-accordion__trigger\" data-header=\"Example 3_0\" href=\"#\">\n      <div class=\"shortcode-accordion__header\">\n          <h4>Example 3 <span class=\"screen-reader-text\">Accordion Closed<\/span><\/h4>\n          <span class=\"shortcode-accordion__header__arrow\"><\/span>\n      <\/div>\n    <\/a>\n    <div class=\"shortcode-accordion__body\">\n        <!DOCTYPE html PUBLIC \"-\/\/W3C\/\/DTD HTML 4.0 Transitional\/\/EN\" \"http:\/\/www.w3.org\/TR\/REC-html40\/loose.dtd\">\n<html><body>\n<p>There may be times that you would like to send many different files as input to a program. Instead of having to do this one at a time, you can set up a job array to do this automatically. In this next example, we will be using a simple shell script called &ldquo;analysis.sh&rdquo; that takes an input file and an output directory as parameters.<\/p>\n<p><strong>analysis.sh<\/strong><\/p>\n<p style=\"padding-left: 30px;\">#!\/bin\/bash<br>\n# analysis.sh &ndash; an analysis program<br>\n# $1 (input) and $2 (output) are the first and second arguments to this script<\/p>\n<p># strip off the directory paths to get just the filename<br>\nBASE=`basename $1`<\/p>\n<p># generate random number between 1 and 5<br>\nRAND=&rdquo;$(($RANDOM % 5+1))&rdquo;<\/p>\n<p># begin the big analysis<br>\necho &ldquo;Beginning the analysis of $BASE at:&rdquo;<br>\ndate<\/p>\n<p># the sleep program will just sit idle doing nothing<br>\necho &ldquo;Sleeping for $RAND seconds &hellip;&rdquo;<br>\nsleep $RAND<\/p>\n<p># now actually do something, calculating the checksum of our input file<br>\nCHKSUM=`md5sum $1`<br>\necho &ldquo;${CHKSUM}&rdquo; &gt; $2\/${BASE}_sum<\/p>\n<p>echo &ldquo;Analysis of $BASE has been completed at:&rdquo;<br>\ndate<\/p>\n<p>In the analysis.sh script we are taking two arguments given to us, the first one being the file to be analyzed, and second the directory to output the analysis to. We are simply sleeping for a random amount of time and running md5sum on the file given to us and outputting the checksum to the output directory.<\/p>\n<p>Let&rsquo;s say we have 5 different files that we would like our program to analyze. We will store the paths to these input files in another file called &ldquo;filelist&rdquo;:<\/p>\n<p><strong>filelist<\/strong><\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"size-short-banner-image wp-image-270 aligncenter\" src=\"https:\/\/in.nau.edu\/wp-content\/uploads\/sites\/208\/2018\/01\/Job-Array-Example-3-filelist-960x198.png\" alt=\"\" width=\"550\" height=\"198\"><\/p>\n<p>Notice that the paths in &ldquo;filelist&rdquo; are absolute paths (starting with the root). **Although it is possible to use relative path names, absolute are recommended.<\/p>\n<p>Then we create a script called &ldquo;job_array.sh&rdquo; that uses the command line tool &ldquo;sed&rdquo; and the SLURM_ARRAY_TASK_ID variable to get a specific line of that file:<\/p>\n<p><strong>job_array.sh<\/strong><\/p>\n<p style=\"padding-left: 30px;\">#!\/bin\/bash<br>\n#SBATCH &ndash;&ndash;job-name=array_test<br>\n#SBATCH &ndash;&ndash;workdir=\/scratch\/mkg52\/ bigdata<br>\n#SBATCH &ndash;&ndash;output=\/scratch\/mkg52\/ bigdata\/logs\/job_%A_%a.log<br>\n#SBATCH &ndash;&ndash;time=20:00<br>\n#SBATCH &ndash;&ndash;partition=core<br>\n#SBATCH &ndash;&ndash;cpus-per-task=1<br>\n#SBATCH &ndash;&ndash;array=1-5<\/p>\n<p>name=$(sed -n &ldquo;$SLURM_ARRAY_TASK_ID&rdquo;p filelist)<\/p>\n<p>srun \/scratch\/mkg52\/bigdata\/ analysis.sh input\/$name output<\/p>\n<p>Last, we run the script using sbatch and can see that our output files have been generated in the &ldquo;output&rdquo; folder:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"size-short-banner-image wp-image-273 aligncenter\" src=\"https:\/\/in.nau.edu\/wp-content\/uploads\/sites\/208\/2018\/01\/Job-Array-example-3-output-960x176.png\" alt=\"Job Array Output Snapshot\" width=\"550\" height=\"176\"><\/p>\n<p><em><strong>**Note:<\/strong> These last 3 examples have shown how you can use job arrays, which by default, will run every task in the array at the same time. If you would rather have the jobs run serially, you can use the %1 option:<\/em><\/p>\n<p style=\"padding-left: 30px;\">#SBATCH &ndash;&ndash;array=1-5%1<\/p>\n<\/body><\/html>\n\n    <\/div>\n<\/div>\n\n","protected":false},"excerpt":{"rendered":"<p>Job arrays Job arrays allow you to leverage SLURM\u2019s ability to create multiple jobs from one script. Many of the situations where this is useful include: Establishing a list of commands to run and have a job created from each command in the list. Running many parameters against one set of data or analysis program. [&hellip;]<\/p>\n","protected":false},"author":76,"featured_media":145,"parent":71,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"_relevanssi_hide_post":"","_relevanssi_hide_content":"","_relevanssi_pin_for_all":"","_relevanssi_pin_keywords":"","_relevanssi_unpin_keywords":"","_relevanssi_related_keywords":"","_relevanssi_related_include_ids":"","_relevanssi_related_exclude_ids":"","_relevanssi_related_no_append":"","_relevanssi_related_not_related":"","_relevanssi_related_posts":"","_relevanssi_noindex_reason":"","ring_central_script_selection":"","footnotes":""},"class_list":["post-152","page","type-page","status-publish","has-post-thumbnail","hentry"],"_links":{"self":[{"href":"https:\/\/in.nau.edu\/arc\/wp-json\/wp\/v2\/pages\/152","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/in.nau.edu\/arc\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/in.nau.edu\/arc\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/in.nau.edu\/arc\/wp-json\/wp\/v2\/users\/76"}],"replies":[{"embeddable":true,"href":"https:\/\/in.nau.edu\/arc\/wp-json\/wp\/v2\/comments?post=152"}],"version-history":[{"count":8,"href":"https:\/\/in.nau.edu\/arc\/wp-json\/wp\/v2\/pages\/152\/revisions"}],"predecessor-version":[{"id":2361,"href":"https:\/\/in.nau.edu\/arc\/wp-json\/wp\/v2\/pages\/152\/revisions\/2361"}],"up":[{"embeddable":true,"href":"https:\/\/in.nau.edu\/arc\/wp-json\/wp\/v2\/pages\/71"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/in.nau.edu\/arc\/wp-json\/wp\/v2\/media\/145"}],"wp:attachment":[{"href":"https:\/\/in.nau.edu\/arc\/wp-json\/wp\/v2\/media?parent=152"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}