start_nodes.pyΒΆ

"""
Start node processes in separate shell windows.
Run "python start_nodes.py *n xnode.py extra_args*" to start *n* processes
in separate shells, where shell *j*, for *j* = 0..*n*-1, runs 
"python *xnode.py n j extra_args*". Same as manually starting *n* shells
and entering the commands in the shells.
Assumes that *xnode.py* takes command-line arguments *n*, *j* and 
*extra_args*, where *extra_args* are any additional arguments.

Examples:

- ``python start_nodes.py 3 imp_0/node.py`` starts three shells running
  ``python imp_0/node.py 3 0``, ``python imp_0/node.py 3 1``, and
  ``python imp_0/node.py 3 2``.

- ``python start_nodes.py 3 imp_0/node.py -a xyz`` starts three shells
  where shell j, for j=0..2, runs ``python imp_0/node.py 3 j -a xyz``.

- ``python start_nodes.py 3 imp_0/node.py -a xyz --use imp_1.node -b 256``
  starts three shells where shell j, for j=0..2, runs 
  ``python imp_0/node.py 3 j -a xyz --use imp_1.node 3 j -b 256``.
"""

import subprocess as sp
import argparse, sys

def insert_num_nodes_and_myidplaceholder(x, n):
  p = [j for j,v in enumerate(x) if v=='--use']
  p.reverse()
  print("p", p)
  for k in p:
    x[k+2:k+2] = [str(n), 0]
  x[0:0] = [str(n), 0]
  return x

def start_nodes(argv):
  print("start_nodes argv", argv)
  p = argparse.ArgumentParser(
    description="Start n processes, each running 'python x n j xargs', \
    for j = 0..n-1, each in its own shell window. Same as manually starting \
    n command-line shells and entering 'python x n j xargs' in window j.")
  p.add_argument("n", type=int, help="number of nodes")
  p.add_argument("x", type=str,
                 help="script for each node, eg, 'node.py', 'test_node.py'")
  p.add_argument("xargs", nargs=argparse.REMAINDER,
                 help="any extra arguments (other than n and j) for x")
  args = p.parse_args(argv[1:])
  print("args", args)
  if args.n < 2:
    print('Error: n (number of nodes) must be at least 2')
    sys.exit(1)

  xargs_n_myidplaceholder = insert_num_nodes_and_myidplaceholder(
    args.xargs, args.n)
  for j in range(args.n):
    xargs_n_myid = [str(j) if p==0 else p for p in xargs_n_myidplaceholder]
    print("Starting: python", args.x, *xargs_n_myid)
    # Popen() arguments below is for Windows OS. Varies with OSes.
    sp.Popen(["python", args.x, *xargs_n_myid],
             creationflags=sp.CREATE_NEW_CONSOLE)
    # sp.Popen(["python", args.x, *xargs_n_myid],
    #          creationflags=0x8 | 0x200 | 0x08000000)


if __name__ == '__main__':
  start_nodes(sys.argv)