AWSの勉強も兼ねて、マラソンマッチの並列テスト環境を作ってみることにした。多分忘れるので自分用にメモを残す(いいやり方を誰か教えてください)
問題は何でもいいので、いつもの「Hokkaido Univ.& Hitachi 1st New-concept Computing Contest 2017 Probrem 1」を使うことにした。シンプルな問題設定なのでマラソンマッチで遊ぶのに向いている(テスターもついている(これは重要))
順番に並べて、ランダムで2点入れ替える山登りを書いてみた。 当然弱い。このソースコードを使って並列実行をしてみる。
ローカル環境はUbuntu 18.04.5 LTS。CPUは4コア4スレッドなので、4並列までは走らせられそうな感じがする。Python3を使ってマルチプロセスでテスターを走らせるスクリプトを書く。
シングルプロセスで5つのseedを順番にテストして結果を出力するコードを書いてみた。コマンドを順番に実行しているだけ。
import subprocess
toolkit_dir = "./problem1_toolkit_JP/scripts/"
input_dir = "./input/"
output_dir = "./output/"
for seed in range(5):
input_filename = "input_" + str(seed) + ".in"
output_filename = "output_" + str(seed) + ".out"
print("seed = " + str(seed))
# テストケース生成
subprocess.run([toolkit_dir + "graph_generator.out " + input_dir +
input_filename + " 0 " + str(seed)], shell=True)
# プログラム実行
subprocess.run(["./a.out < " + input_dir + input_filename +
" > " + output_dir + output_filename], shell=True)
# 評価
subprocess.run([toolkit_dir + "score_evaluator.out " + input_dir +
input_filename + " " + output_dir + output_filename], shell=True)
# ファイルを削除
subprocess.run(["rm " + input_dir + input_filename + " " +
output_dir + output_filename], shell=True)
並列にした。オプションでテスト数と並列度を指定できるようにして、スコアを取り出す部分も雑に書いてみた。コンテストによってテスト方法や出力のフォーマットが違うので、適当にうまく書く。全部同じ時間で終わるので、並列実行は$N$プロセス起動→終了したら次の$N$プロセス起動でよい。
import subprocess
import argparse
toolkit_dir = "./problem1_toolkit_JP/scripts/"
input_dir = "./input/"
output_dir = "./output/"
test_num = 10
parallel_num = 2
parser = argparse.ArgumentParser(description = "--testNum and --parallelNum")
parser.add_argument("--testNum", type=int)
parser.add_argument("--parallelNum", type=int)
args = parser.parse_args()
if args.testNum != None:
test_num = args.testNum
if args.parallelNum != None:
parallel_num = args.parallelNum
# テストケース生成
for seed in range(test_num):
input_filename = "input_" + str(seed) + ".in"
subprocess.run(toolkit_dir + "graph_generator.out " + input_dir +
input_filename + " 0 " + str(seed), shell=True)
# プログラム実行
running_procs = []
for seed in range(test_num):
print("seed = " + str(seed))
input_filename = "input_" + str(seed) + ".in"
output_filename = "output_" + str(seed) + ".out"
proc = subprocess.Popen("./a.out < " + input_dir + input_filename +
" > " + output_dir + output_filename, shell=True)
running_procs.append(proc)
if len(running_procs) == parallel_num or seed + 1 == test_num:
for p in running_procs:
p.communicate()
running_procs.clear()
# 評価, ファイルの削除
totalScore = 0
for seed in range(test_num):
input_filename = "input_" + str(seed) + ".in"
output_filename = "output_" + str(seed) + ".out"
proc = subprocess.run(toolkit_dir + "score_evaluator.out " + input_dir +
input_filename + " " + output_dir + output_filename, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
out = proc.stdout.decode("utf-8").strip()
print(out)
scores = out[14:].replace(" ", "").split("/")
score, sum = int(scores[0]), int(scores[1]) # スコア、合計
totalScore += score / sum * 10000 / test_num
subprocess.run("rm " + input_dir + input_filename + " " +
output_dir + output_filename, shell=True)
print(totalScore)
次に、AWSでサーバを借りて回す。スポットインスタンスとして借りると安くすむ。