Skip to content
Snippets Groups Projects
launchBatches.py 10.05 KiB
#! /usr/bin/env python3

import sys
import os
import subprocess
import time

###############################################################################
def printUsageAndExit() :
  print("USAGE : %s (train | eval) (bash | oar | slurm) batchesDescription.py (--time nbHours)"%sys.argv[0], file=sys.stderr)
  exit(1)
###############################################################################

###############################################################################
def prepareExperiment(lang, template, expName) :
  subprocess.Popen("./prepareExperiment.sh %s %s %s"%(lang,template,expName),
      shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE).wait()
###############################################################################

###############################################################################
def launchTrain(mode, expName, arguments, launcher, nbHours, seed) :
  if launcher == "bash" :
    launchTrainBash(mode, expName, arguments, seed)
  elif launcher == "oar" :
    launchTrainOar(mode, expName, arguments, nbHours, seed)
  elif launcher == "slurm" :
    launchTrainSlurm(mode, expName, arguments, nbHours, seed)
  else :
    printUsageAndExit()
###############################################################################

###############################################################################
def launchTrainBash(mode, expName, arguments, seed) :
  subprocess.Popen("./train.sh %s bin/%s %s --silent --seed %d"%(mode,expName,arguments,seed),
    shell=True, stdout=open("%s.stdout"%expName,'w'), stderr=open("%s.stderr"%expName,'w'))
###############################################################################

###############################################################################
def nbMaxLongJobs() :
  return 2
###############################################################################

###############################################################################
def launchTrainOar(mode, expName, arguments, nbHours, seed) :
  bestEffort = getOarNbLongJobs() >= nbMaxLongJobs()

  command = "oarsub"
  command += " -t besteffort" if bestEffort else ""
  command += " -t idempotent" if bestEffort else ""
  command += " -n train:%s"%expName
  command += " -E %s.stderr"%expName
  command += " -O %s.stdout"%expName
  command += " -p \"gpu IS NOT NULL%s\""%getBestHostConstraint()
  command += " -l walltime=%d:00:00"%nbHours
  command += " \'" + "./train.sh %s bin/%s %s --silent --seed"%(mode,expName,arguments,seed) + "\'"

  subprocess.Popen(command, shell=True).wait()
###############################################################################

###############################################################################
def launchTrainSlurm(mode, expName, arguments, nbHours, seed) :
  filename = "train.{}.slurm".format(expName)
  sFile = open(filename, "w")

  print("""#! /usr/bin/env bash

#SBATCH --job-name=train:{}
#SBATCH --output={}.stdout
#SBATCH --error={}.stderr
#SBATCH --open-mode=append
#SBATCH --ntasks=1
#SBATCH --cpus-per-task=10
#SBATCH --gres=gpu:1
#SBATCH --hint=nomultithread
#SBATCH --partition=gpu_p1
#SBATCH --qos={}
#SBATCH --time={}:00:00

module purge
module load gcc/9.1.0
module load python/3.7.5

./train.sh {} bin/{} {} --silent --seed {}
""".format(expName, expName, expName, "qos_gpu-t4" if nbHours > 20 else "qos_gpu-t3", nbHours, mode, expName, arguments, seed), file=sFile)
  sFile.close()

  subprocess.Popen("sbatch {}".format(filename), shell=True).wait()
###############################################################################

###############################################################################
def launchEval(mode, expName, launcher, nbHours) :
  if launcher == "bash" :
    launchEvalBash(mode, expName)
  elif launcher == "oar" :
    launchEvalOar(mode, expName, nbHours)
  elif launcher == "slurm" :
    launchEvalSlurm(mode, expName, nbHours)
  else :
    printUsageAndExit()
###############################################################################

###############################################################################
def launchEvalBash(mode, expName) :
  subprocess.Popen("./evaluate.sh %s bin/%s --silent"%(mode,expName),
    shell=True, stdout=open("%s.stdout"%expName,'a'), stderr=open("%s.stderr"%expName,'a'))
###############################################################################

###############################################################################
def launchEvalOar(mode, expName, nbHours) :
  bestEffort = getOarNbLongJobs() >= nbMaxLongJobs() and nbHours > 10

  command = "oarsub"
  command += " -t besteffort" if bestEffort else ""
  command += " -t idempotent" if bestEffort else ""
  command += " -n eval:%s"%expName
  command += " -E %s.stderr"%expName
  command += " -O %s.stdout"%expName
  command += " -p \"gpu IS NOT NULL%s\""%getBestHostConstraint()
  command += " -l walltime=%d:00:00"%nbHours
  command += " \"" + "./evaluate.sh %s bin/%s --silent"%(mode,expName) + "\""

  subprocess.Popen(command, shell=True).wait()
###############################################################################

###############################################################################
def launchEvalSlurm(mode, expName, nbHours) :
  filename = "eval.{}.slurm".format(expName)
  sFile = open(filename, "w")

  print("""#! /usr/bin/env bash

#SBATCH --job-name=eval:{}
#SBATCH --output={}.stdout
#SBATCH --error={}.stderr
#SBATCH --open-mode=append
#SBATCH --ntasks=1
#SBATCH --cpus-per-task=10
#SBATCH --gres=gpu:1
#SBATCH --hint=nomultithread
#SBATCH --partition=gpu_p1
#SBATCH --time={}:00:00

module purge
module load gcc/9.1.0
module load python/3.7.5

./evaluate.sh {} bin/{} --silent
""".format(expName, expName, expName, nbHours, mode, expName), file=sFile)
  sFile.close()

  subprocess.Popen("sbatch {}".format(filename), shell=True).wait()
###############################################################################

###############################################################################
def getOarNbLongJobs() :
  return int(subprocess.Popen('oarstat -u | grep "Q=long" | wc -l',
    shell=True, stdout=subprocess.PIPE).stdout.read())
###############################################################################

###############################################################################
def getOarNbGpuPerNode() :
  l = subprocess.Popen("oarnodes | grep gpunum=. | grep -o 'host=[^,]*' | cut -f2 -d= | sort | uniq -c", shell=True, stdout=subprocess.PIPE).stdout.read().decode('utf8').split('\n')

  res = {}
  for line in l :
    splited = line.split()
    if len(splited) != 2 :
      continue
    res[splited[1]] = int(splited[0])

  return res
###############################################################################

###############################################################################
def getOarNbUsedGpuPerNode() :
  l = subprocess.Popen("oarstat -f | grep 'assigned_hostnames =\|propert\|wanted_resources' | grep -i 'gpu is not null' -B 2 | grep [^-]", shell=True, stdout=subprocess.PIPE).stdout.read().decode("utf8").split('\n')

  res = {}

  for i in range(len(l)//3) :
    ressources = l[3*i]
    hostname = l[3*i+1].split()[-1]
    cores = 1
    gpunum = 1
    if "core=" in ressources :
      coresStr=""
      coresStrBase = ressources.split("core=")[-1]
      for symbol in coresStrBase :
        if symbol < '0' or symbol > '9' :
          break
        coresStr = coresStr + symbol
      cores = int(coresStr)
    if "gpunum=" in ressources :
      gpunum = int(ressources.split("gpunum=")[-1].split(',')[0])

    if hostname not in res :
      res[hostname] = 0
    res[hostname] += cores * gpunum

  return res
###############################################################################

###############################################################################
def getOarNotAliveNodes() :
  res =  subprocess.Popen("oarnodes | grep -B 2 'state : [^A]' | grep 'network_address' | sort --unique | awk '{print $3}'", shell=True, stdout=subprocess.PIPE).stdout.read().decode("utf8").split('\n')
  return [node for node in res if len(node) > 0]
###############################################################################

###############################################################################
def getOarNbFreeGpuPerNode() :
  gpus = getOarNbGpuPerNode()
  notAlive = getOarNotAliveNodes()
  usedGpus = getOarNbUsedGpuPerNode()

  for gpu in gpus :
    gpus[gpu] -= usedGpus[gpu] if gpu in usedGpus else 0

  for host in notAlive :
    gpus[host] = 0

  return gpus
###############################################################################

###############################################################################
def getBestHostConstraint() :
  freeGpus = getOarNbFreeGpuPerNode()

  if freeGpus["diflives1"] > 0 or freeGpus["lisnode2"] > 0 or freeGpus["lisnode3"] > 0 :
    return " and host!='lifnode1' and host!='adnvideo1' and host!='asfalda1' and host!='see4c1' and host!='sensei1'"
  return ""
###############################################################################

###############################################################################
if __name__ == "__main__" :

  if len(sys.argv) < 4 :
    printUsageAndExit()

  mode = sys.argv[1]
  launcher = sys.argv[2]
  batchesDescription = sys.argv[3]
  nbHours = 92

  if len(sys.argv) > 4 :
    if sys.argv[4] == "--time" :
      if 5 not in range(4,len(sys.argv)) :
        printUsageAndExit()
      nbHours = int(sys.argv[5])
    else :
      printUsageAndExit()

  if mode not in ["train","eval"] or launcher not in  ["bash","oar","slurm"] :
    printUsageAndExit()

  desc = __import__(os.path.splitext(batchesDescription)[0])

  for lang in desc.langs :
    for xp in desc.templatesExperiments :
      for i in range(desc.nbReplicas) :
        xp['lang'] = lang
        xp['expName'] = xp['expName'].split('.')[0]+"."+lang+"."+str(i)
        if mode == "train" :
          prepareExperiment(xp['lang'],xp['template'],xp['expName'])
          launchTrain(xp['mode'],xp['expName'],xp['arguments'],launcher,nbHours,seed=100+i)
        else :
          launchEval(xp['mode'],xp['expName'],launcher,nbHours)

###############################################################################