TABLE OF CONTENTS


2.9 Remote and parallel execution of PWTK scripts

DESCRIPTION

This sections explains how to perform remote and concurent (parallel) execution of scripts in PWTK.

TABLE OF CONTENTS

  1. Remote execution of PWTK scripts
  2. Parallel execution of PWTK scripts
  3. Beware of caveat: PWTK child instances

Remote execution of PWTK scripts

PWTK supports remote execution. To this end, it relies on ssh and rsync tools. Furthermore, PWTK needs to be installed on local and remote machine.

There are two ways how to instruct PWTK to run a PWTK script on remote machine. The first is from the terminal, i.e.:

   pwtk -r user@host job.pwtk

will run the job.pwtk script on the remote host machine with the user account (note that the user@host syntax is analogous to that of used by ssh).

It is also possible to request remote execution within the PWTK script. This is achieved with the 'remote' command (see ::pwtk::remote), for example:

    remote user@host {
       job.pwtk
    }

Parallel execution of PWTK scripts

PWTK supports asynchronous parallel execution of scripts using three types of concepts: backgrounds, threads, and thread-pools.

It is highly recommended to use bacgrounds rather than threads because they are safer to use. Bacgrounds are completely independent from one another. In contrast, threads use some common resources, such as current wokring directory and enviromental variables, which make them tricky to use.

Backgrounds

Backgrounds allow for scripts to run concurrently (see ::pwtk::bg). For example, the following script will run four structural relaxations simultaneously with 8 processors each:

    foreach xsf {str1.xsf str2.xsf str3.xsf str4.xsf} {
       bg {
          import data.pwtk
          prefix mpirun -np 8
          ::pwtk::relax_fromXSF pw.x $xsf
       }
    }

Technically, each script is executed by launching a new PWTK process in the background. Hence, the bg command returns immediately (i.e. it is non-blocking).

Threads

Threads are another way to achieve concurrent execution of scripts (see ::pwtk::thread). Here is the analogous example as used above for backgrounds but uses threads instead:

    foreach xsf {str1.xsf str2.xsf str3.xsf str4.xsf} {
       thread {
          import data.pwtk
          prefix mpirun -np 8
          ::pwtk::relax_fromXSF pw.x $xsf
       }
    }

The thread command returns immediately (i.e. it is non-blocking).

BEWARE
Threads require the Tcl-thread extension, which in Debian based distros can be installed as:

    sudo apt install tcl-thread

Thread-pools

Thread-pool (aka tpool) consists of multiple worker threads waiting for jobs to be allocated for concurrent execution and after completing their assigned tasks return to the pool. A typical usage of thread-pool is the following: suppose we have N jobs to perform on M workers, where N >> M. This task can be efficiently managed with a thread-pool, which will initially distribute M jobs to M workers, i.e., one job per worker. When the first job finishes, it submits the next job to a free worker, and so on until all jobs are completed.

Thread-pools require the Tcl-thread extension.

PWTK supports three types of thread-pools, depending on what type of workers they uses, i.e., remotes, backgrounds, or threads. Remote workers run on remote machines, whereas background and thread workers run on the local machine.

Here is an example with remote workers:

    set tp [::pwtk::tpool new -h {host1 host1 host2 host2}]

    foreach i [seq 1 24] {
       $tp job {
          import data.pwtk
          prefix mpirun -np 8
          ::pwtk::relax_fromXSF pw.x str$i.xsf
       }
    }

The "-h" options stands for a host list. In this example, 4 remote workers are created, two on host1 and two on host2. These 4 workers need to perform 24 jobs. The thread-pool will initially distribute one job to each worker. When some job finishes, thread-pool submits the next job to a free worker, and so on until all jobs are completed.

Local background workers are requested with the "-b" options, i.e.:

    set tp [::pwtk::tpool new -b 4]
    foreach i [seq 1 24] {
       $tp job { ... }
    }

whereas local thread workers are requested with the "-t" option, i.e.:

    set tp [::pwtk::tpool new -t 4]
    foreach i [seq 1 24] {
       $tp job { ... }
    }

Beware of caveat: PWTK child instances

The remotes, backgrounds, threads, and thread-pools are PWTK child instances. The problem with child instances is that they do not automatically inherit the state from the parent. For example, the following script will fail:

       import data.pwtk
       bg {
          prefix mpirun -np 8
          runPW calc1
       }

because the script supplied to the 'bg' command is a child instance born in the empty state. Hence, runPW will fail because it has no input data. There are two ways how to deal with this issue. The first was used for the above examples, where all relevant data were included inside the remote, bg, thread... commands, e.g.:

       bg {
          import data.pwtk
          prefix mpirun -np 8
          runPW calc1
       }

The other option is to use the PWTK's propagate mechanism (see ::pwtk::propagate), with which one can specify what to propagate to child processes, i.e.:

    propagate {
       import data.pwtk
       prefix mpirun -np 8
    }
    foreach xsf {str1.xsf str2.xsf str3.xsf str4.xsf} {
       bg {
          ::pwtk::relax_fromXSF pw.x $xsf
       }
    }