Skip to content
Snippets Groups Projects
capacity-computing.md 13.6 KiB
Newer Older
  • Learn to ignore specific revisions
  • Lukáš Krupčík's avatar
    Lukáš Krupčík committed
    1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433
    Capacity computing 
    ==================
    
      
    
    Introduction
    ------------
    
    In many cases, it is useful to submit huge (>100+) number of
    computational jobs into the PBS queue system. Huge number of (small)
    jobs is one of the most effective ways to execute embarrassingly
    parallel calculations, achieving best runtime, throughput and computer
    utilization.
    
    However, executing huge number of jobs via the PBS queue may strain the
    system. This strain may result in slow response to commands, inefficient
    scheduling and overall degradation of performance and user experience,
    for all users. For this reason, the number of jobs is **limited to 100
    per user, 1000 per job array**
    
    Please follow one of the procedures below, in case you wish to schedule
    more than >100 jobs at a time.
    
    -   Use [Job arrays](capacity-computing.html#job-arrays)
        when running huge number of
        [multithread](capacity-computing.html#shared-jobscript-on-one-node)
        (bound to one node only) or multinode (multithread across
        several nodes) jobs
    -   Use [GNU
        parallel](capacity-computing.html#gnu-parallel) when
        running single core jobs
    -   Combine[GNU parallel with Job
        arrays](capacity-computing.html#combining-job-arrays-and-gnu-parallel) 
        when running huge number of single core jobs
    
    Policy
    ------
    
    1.  A user is allowed to submit at most 100 jobs. Each job may be [a job
        array](capacity-computing.html#job-arrays).
    2.  The array size is at most 1000 subjobs.
    
    Job arrays
    --------------
    
    Huge number of jobs may be easily submitted and managed as a job array.
    
    A job array is a compact representation of many jobs, called subjobs.
    The subjobs share the same job script, and have the same values for all
    attributes and resources, with the following exceptions:
    
    -   each subjob has a unique index, $PBS_ARRAY_INDEX
    -   job Identifiers of subjobs only differ by their indices
    -   the state of subjobs can differ (R,Q,...etc.)
    
    All subjobs within a job array have the same scheduling priority and
    schedule as independent jobs.
    Entire job array is submitted through a single qsub command and may be
    managed by qdel, qalter, qhold, qrls and qsig commands as a single job.
    
    ### Shared jobscript
    
    All subjobs in job array use the very same, single jobscript. Each
    subjob runs its own instance of the jobscript. The instances execute
    different work controlled by $PBS_ARRAY_INDEX variable.
    
    Example:
    
    Assume we have 900 input files with name beginning with "file" (e. g.
    file001, ..., file900). Assume we would like to use each of these input
    files with program executable myprog.x, each as a separate job.
    
    First, we create a tasklist file (or subjobs list), listing all tasks
    (subjobs) - all input files in our example:
    
    `
    $ find . -name 'file*' > tasklist
    `
    
    Then we create jobscript:
    
    `
    #!/bin/bash
    #PBS -A PROJECT_ID
    #PBS -q qprod
    #PBS -l select=1:ncpus=16,walltime=02:00:00
    
    # change to local scratch directory
    SCR=/lscratch/$PBS_JOBID
    mkdir -p $SCR ; cd $SCR || exit
    
    # get individual tasks from tasklist with index from PBS JOB ARRAY
    TASK=$(sed -n "${PBS_ARRAY_INDEX}p" $PBS_O_WORKDIR/tasklist)  
    
    # copy input file and executable to scratch 
    cp $PBS_O_WORKDIR/$TASK input ; cp $PBS_O_WORKDIR/myprog.x .
    
    # execute the calculation
    ./myprog.x < input > output
    
    # copy output file to submit directory
    cp output $PBS_O_WORKDIR/$TASK.out
    `
    
    In this example, the submit directory holds the 900 input files,
    executable myprog.x and the jobscript file. As input for each run, we
    take the filename of input file from created tasklist file. We copy the
    input file to local scratch /lscratch/$PBS_JOBID, execute the myprog.x
    and copy the output file back to >the submit directory,
    under the $TASK.out name. The myprog.x runs on one node only and must
    use threads to run in parallel. Be aware, that if the myprog.x **is not
    multithreaded**, then all the **jobs are run as single thread programs
    in sequential** manner. Due to allocation of the whole node, the
    accounted time is equal to the usage of whole node**, while using only
    1/16 of the node!
    
    If huge number of parallel multicore (in means of multinode multithread,
    e. g. MPI enabled) jobs is needed to run, then a job array approach
    should also be used. The main difference compared to previous example
    using one node is that the local scratch should not be used (as it's not
    shared between nodes) and MPI or other technique for parallel multinode
    run has to be used properly.
    
    ### Submit the job array
    
    To submit the job array, use the qsub -J command. The 900 jobs of the
    [example above](capacity-computing.html#array_example) may
    be submitted like this:
    
    `
    $ qsub -N JOBNAME -J 1-900 jobscript
    12345[].dm2
    `
    
    In this example, we submit a job array of 900 subjobs. Each subjob will
    run on full node and is assumed to take less than 2 hours (please note
    the #PBS directives in the beginning of the jobscript file, dont'
    forget to set your valid PROJECT_ID and desired queue).
    
    Sometimes for testing purposes, you may need to submit only one-element
    array. This is not allowed by PBSPro, but there's a workaround:
    
    `
    $ qsub -N JOBNAME -J 9-10:2 jobscript
    `
    
    This will only choose the lower index (9 in this example) for
    submitting/running your job.
    
    ### Manage the job array
    
    Check status of the job array by the qstat command.
    
    `
    $ qstat -a 12345[].dm2
    
    dm2:
                                                                Req'd  Req'd   Elap
    Job ID          Username Queue    Jobname    SessID NDS TSK Memory Time  S Time
    --------------- -------- --  |---|---| ------ --- --- ------ ----- - -----
    12345[].dm2     user2    qprod    xx          13516   1  16    --  00:50 B 00:02
    `
    
    The status B means that some subjobs are already running.
    
    Check status of the first 100 subjobs by the qstat command.
    
    `
    $ qstat -a 12345[1-100].dm2
    
    dm2:
                                                                Req'd  Req'd   Elap
    Job ID          Username Queue    Jobname    SessID NDS TSK Memory Time  S Time
    --------------- -------- --  |---|---| ------ --- --- ------ ----- - -----
    12345[1].dm2    user2    qprod    xx          13516   1  16    --  00:50 R 00:02
    12345[2].dm2    user2    qprod    xx          13516   1  16    --  00:50 R 00:02
    12345[3].dm2    user2    qprod    xx          13516   1  16    --  00:50 R 00:01
    12345[4].dm2    user2    qprod    xx          13516   1  16    --  00:50 Q   --
         .             .        .      .             .    .   .     .    .   .    .
         ,             .        .      .             .    .   .     .    .   .    . 
    12345[100].dm2  user2    qprod    xx          13516   1  16    --  00:50 Q   --
    `
    
    Delete the entire job array. Running subjobs will be killed, queueing
    subjobs will be deleted.
    
    `
    $ qdel 12345[].dm2
    `
    
    Deleting large job arrays may take a while.
    
    Display status information for all user's jobs, job arrays, and subjobs.
    
    `
    $ qstat -u $USER -t
    `
    
    Display status information for all user's subjobs.
    
    `
    $ qstat -u $USER -tJ
    `
    
    Read more on job arrays in the [PBSPro Users
    guide](../../pbspro-documentation.html).
    
    GNU parallel
    ----------------
    
    Use GNU parallel to run many single core tasks on one node.
    
    GNU parallel is a shell tool for executing jobs in parallel using one or
    more computers. A job can be a single command or a small script that has
    to be run for each of the lines in the input. GNU parallel is most
    useful in running single core jobs via the queue system on  Anselm.
    
    For more information and examples see the parallel man page:
    
    `
    $ module add parallel
    $ man parallel
    `
    
    ### GNU parallel jobscript
    
    The GNU parallel shell executes multiple instances of the jobscript
    using all cores on the node. The instances execute different work,
    controlled by the $PARALLEL_SEQ variable.
    
    Example:
    
    Assume we have 101 input files with name beginning with "file" (e. g.
    file001, ..., file101). Assume we would like to use each of these input
    files with program executable myprog.x, each as a separate single core
    job. We call these single core jobs tasks.
    
    First, we create a tasklist file, listing all tasks - all input files in
    our example:
    
    `
    $ find . -name 'file*' > tasklist
    `
    
    Then we create jobscript:
    
    `
    #!/bin/bash
    #PBS -A PROJECT_ID
    #PBS -q qprod
    #PBS -l select=1:ncpus=16,walltime=02:00:00
    
    [ -z "$PARALLEL_SEQ" ] && 
    { module add parallel ; exec parallel -a $PBS_O_WORKDIR/tasklist $0 ; }
    
    # change to local scratch directory
    SCR=/lscratch/$PBS_JOBID/$PARALLEL_SEQ
    mkdir -p $SCR ; cd $SCR || exit
    
    # get individual task from tasklist
    TASK=$1  
    
    # copy input file and executable to scratch 
    cp $PBS_O_WORKDIR/$TASK input 
    
    # execute the calculation
    cat  input > output
    
    # copy output file to submit directory
    cp output $PBS_O_WORKDIR/$TASK.out
    `
    
    In this example, tasks from tasklist are executed via the GNU
    parallel. The jobscript executes multiple instances of itself in
    parallel, on all cores of the node. Once an instace of jobscript is
    finished, new instance starts until all entries in tasklist are
    processed. Currently processed entry of the joblist may be retrieved via
    $1 variable. Variable $TASK expands to one of the input filenames from
    tasklist. We copy the input file to local scratch, execute the myprog.x
    and copy the output file back to the submit directory, under the
    $TASK.out name. 
    
    ### Submit the job
    
    To submit the job, use the qsub command. The 101 tasks' job of the
    [example above](capacity-computing.html#gp_example) may be
    submitted like this:
    
    `
    $ qsub -N JOBNAME jobscript
    12345.dm2
    `
    
    In this example, we submit a job of 101 tasks. 16 input files will be
    processed in  parallel. The 101 tasks on 16 cores are assumed to
    complete in less than 2 hours.
    
    Please note the #PBS directives in the beginning of the jobscript file,
    dont' forget to set your valid PROJECT_ID and desired queue.
    
    Job arrays and GNU parallel
    -------------------------------
    
    Combine the Job arrays and GNU parallel for best throughput of single
    core jobs
    
    While job arrays are able to utilize all available computational nodes,
    the GNU parallel can be used to efficiently run multiple single-core
    jobs on single node. The two approaches may be combined to utilize all
    available (current and future) resources to execute single core jobs.
    
    Every subjob in an array runs GNU parallel to utilize all cores on the
    node
    
    ### GNU parallel, shared jobscript
    
    Combined approach, very similar to job arrays, can be taken. Job array
    is submitted to the queuing system. The subjobs run GNU parallel. The
    GNU parallel shell executes multiple instances of the jobscript using
    all cores on the node. The instances execute different work, controlled
    by the $PBS_JOB_ARRAY and $PARALLEL_SEQ variables.
    
    Example:
    
    Assume we have 992 input files with name beginning with "file" (e. g.
    file001, ..., file992). Assume we would like to use each of these input
    files with program executable myprog.x, each as a separate single core
    job. We call these single core jobs tasks.
    
    First, we create a tasklist file, listing all tasks - all input files in
    our example:
    
    `
    $ find . -name 'file*' > tasklist
    `
    
    Next we create a file, controlling how many tasks will be executed in
    one subjob
    
    `
    $ seq 32 > numtasks
    `
    
    Then we create jobscript:
    
    `
    #!/bin/bash
    #PBS -A PROJECT_ID
    #PBS -q qprod
    #PBS -l select=1:ncpus=16,walltime=02:00:00
    
    [ -z "$PARALLEL_SEQ" ] && 
    { module add parallel ; exec parallel -a $PBS_O_WORKDIR/numtasks $0 ; }
    
    # change to local scratch directory
    SCR=/lscratch/$PBS_JOBID/$PARALLEL_SEQ
    mkdir -p $SCR ; cd $SCR || exit
    
    # get individual task from tasklist with index from PBS JOB ARRAY and index form Parallel
    IDX=$(($PBS_ARRAY_INDEX + $PARALLEL_SEQ - 1))
    TASK=$(sed -n "${IDX}p" $PBS_O_WORKDIR/tasklist)
    [ -z "$TASK" ] && exit
    
    # copy input file and executable to scratch 
    cp $PBS_O_WORKDIR/$TASK input 
    
    # execute the calculation
    cat input > output
    
    # copy output file to submit directory
    cp output $PBS_O_WORKDIR/$TASK.out
    `
    
    In this example, the jobscript executes in multiple instances in
    parallel, on all cores of a computing node.  Variable $TASK expands to
    one of the input filenames from tasklist. We copy the input file to
    local scratch, execute the myprog.x and copy the output file back to the
    submit directory, under the $TASK.out name.  The numtasks file controls
    how many tasks will be run per subjob. Once an task is finished, new
    task starts, until the number of tasks  in numtasks file is reached.
    
    Select  subjob walltime and number of tasks per subjob  carefully
    
     When deciding this values, think about following guiding rules :
    
    1.  Let n=N/16.  Inequality (n+1) * T &lt; W should hold. The N is
        number of tasks per subjob, T is expected single task walltime and W
        is subjob walltime. Short subjob walltime improves scheduling and
        job throughput.
    2.  Number of tasks should be modulo 16.
    3.  These rules are valid only when all tasks have similar task
        walltimes T.
    
    ### Submit the job array
    
    To submit the job array, use the qsub -J command. The 992 tasks' job of
    the [example
    above](capacity-computing.html#combined_example) may be
    submitted like this:
    
    `
    $ qsub -N JOBNAME -J 1-992:32 jobscript
    12345[].dm2
    `
    
    In this example, we submit a job array of 31 subjobs. Note the  -J
    1-992:**32**, this must be the same as the number sent to numtasks file.
    Each subjob will run on full node and process 16 input files in
    parallel, 32 in total per subjob.  Every subjob is assumed to complete
    in less than 2 hours.
    
    Please note the #PBS directives in the beginning of the jobscript file,
    dont' forget to set your valid PROJECT_ID and desired queue.
    
    Examples
    --------
    
    Download the examples in
    [capacity.zip](capacity-computing-examples), 
    illustrating the above listed ways to run huge number of jobs. We
    recommend to try out the examples, before using this for running
    production jobs.
    
    Unzip the archive in an empty directory on Anselm and follow the
    instructions in the README file
    
    `
    $ unzip capacity.zip
    $ cat README
    `