Skip to content

Commit e4efb1f

Browse files
goelakashgoel-akas
andauthored
Running tests in parallel for RL notebooks. (#1624)
Co-authored-by: Akash Goel <[email protected]>
1 parent 15be9e0 commit e4efb1f

File tree

2 files changed

+66
-46
lines changed

2 files changed

+66
-46
lines changed
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
rl_cartpole_ray/rl_cartpole_ray_gymEnv.ipynb
2-
rl_cartpole_coach/rl_cartpole_coach_gymEnv.ipynb
1+
./rl_roboschool_ray/rl_roboschool_ray.ipynb
2+
./rl_cartpole_ray/rl_cartpole_ray_gymEnv.ipynb

reinforcement_learning/testrunner.py

Lines changed: 64 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
#!/usr/bin/env python
22
# coding: utf-8
3+
from datetime import datetime
4+
startTime = datetime.now()
35

46
import itertools
57
import json
8+
import multiprocessing as mp
69
import os
7-
import subprocess
810
import sys
911
import time
1012
try:
@@ -15,39 +17,53 @@
1517
sys.exit("""Some libraries are missing. Please install them by running `pip install -r test_requirements.txt`.""")
1618

1719
# CONSTANTS
20+
manager = mp.Manager()
1821
TEST_NOTEBOOKS_FILE = 'testnotebooks.txt'
1922
TEST_CONFIG_FILE = 'testconfig.csv'
20-
SUCCESSES = 0
21-
EXCEPTIONS = 0
22-
SUCCESSFUL_EXECUTIONS = []
23-
FAILED_EXECUTIONS = []
23+
SUCCESSES = mp.Value('d', 0)
24+
EXCEPTIONS = mp.Value('d', 0)
25+
SUCCESSFUL_EXECUTIONS = manager.list()
26+
FAILED_EXECUTIONS = manager.list()
2427
CELL_EXECUTION_TIMEOUT_SECONDS = 1200
28+
ROOT = os.path.abspath('.')
29+
30+
jobs = []
2531

2632

2733
# helper functions
28-
def run_notebook(nb_path, test_config):
29-
dir_name = os.path.dirname(nb_path)
34+
35+
def execute_nb_with_params(nb_path, params):
36+
abs_nb_dir_path = os.path.join(ROOT, os.path.dirname(nb_path))
3037
nb_name = os.path.basename(nb_path)
3138
output_nb_name = "output_{}.ipynb".format(nb_name)
32-
os.chdir(dir_name)
39+
os.chdir(abs_nb_dir_path)
3340
print("Current directory: {}".format(os.getcwd()))
34-
global SUCCESSES
35-
global EXCEPTIONS
36-
for i in range(len(test_config)):
37-
params = json.loads(test_config.loc[i].to_json())
41+
print("RUN: " + nb_name + " with parameters " + str(params))
42+
# Execute notebook
43+
test_case = dict({'notebook':nb_name, 'params':params})
44+
try:
45+
papermill.execute_notebook(nb_name, output_nb_name, parameters=params, execution_timeout=CELL_EXECUTION_TIMEOUT_SECONDS, log_output=True)
46+
SUCCESSES.value += 1
47+
SUCCESSFUL_EXECUTIONS.append(test_case)
48+
except BaseException as error:
49+
print('An exception occurred: {}'.format(error))
50+
EXCEPTIONS.value += 1
51+
FAILED_EXECUTIONS.append(test_case)
52+
os.chdir(ROOT)
53+
54+
55+
def test_notebook(nb_path, df_test_config):
56+
for i in range(len(df_test_config)):
57+
params = json.loads(df_test_config.loc[i].to_json())
3858
# Coach notebooks support only single instance training, so skip the tests with multiple EC2 instances
39-
if 'coach' in nb_name.lower() and params['train_instance_count'] > 1:
59+
if 'coach' in nb_path.lower() and params['train_instance_count'] > 1:
4060
continue
41-
print("\nTEST: " + nb_name + " with parameters " + str(params))
42-
process = None
43-
try:
44-
papermill.execute_notebook(nb_name, output_nb_name, parameters=params, execution_timeout=CELL_EXECUTION_TIMEOUT_SECONDS, log_output=True)
45-
SUCCESSES += 1
46-
SUCCESSFUL_EXECUTIONS.append(dict({'notebook':nb_name, 'params':params}))
47-
except BaseException as error:
48-
print('An exception occurred: {}'.format(error))
49-
EXCEPTIONS += 1
50-
FAILED_EXECUTIONS.append(dict({'notebook':nb_name, 'params':params}))
61+
p = mp.Process(target=execute_nb_with_params, args=(nb_path, params))
62+
time.sleep(1)
63+
jobs.append(p)
64+
p.start()
65+
66+
5167

5268
def print_notebook_executions(nb_list_with_params):
5369
# This expects a list of dict type items.
@@ -65,26 +81,30 @@ def print_notebook_executions(nb_list_with_params):
6581
print(tabulate(pd.DataFrame([v for v in vals], columns=keys), showindex=False))
6682

6783

84+
if __name__ == "__main__":
85+
notebooks_list = open(TEST_NOTEBOOKS_FILE).readlines()
86+
config = pd.read_csv(TEST_CONFIG_FILE)
87+
# Run tests on each notebook listed in the config.
88+
print("Test Configuration: ")
89+
print(config)
6890

69-
notebooks_list = open(TEST_NOTEBOOKS_FILE).readlines()
70-
config = pd.read_csv(TEST_CONFIG_FILE)
71-
ROOT = os.path.abspath('.')
91+
for nb_path in notebooks_list:
92+
print("Testing: {}".format(nb_path))
93+
test_notebook(nb_path.strip(), config)
7294

73-
# Run tests on each notebook listed in the config.
74-
print("Test Configuration: ")
75-
print(config)
76-
for nb_path in notebooks_list:
77-
os.chdir(ROOT)
78-
print("Testing: {}".format(nb_path))
79-
run_notebook(nb_path.strip(), config)
80-
81-
# Print summary of tests ran.
82-
print("Summary: {}/{} tests passed.".format(SUCCESSES, SUCCESSES + EXCEPTIONS))
83-
print("Successful executions: ")
84-
print_notebook_executions(SUCCESSFUL_EXECUTIONS)
85-
86-
# Throw exception if any test fails, so that the CodeBuild also fails.
87-
if EXCEPTIONS > 0:
88-
print("Failed executions: ")
89-
print_notebook_executions(FAILED_EXECUTIONS)
90-
raise Exception("Test did not complete successfully")
95+
for job in jobs:
96+
job.join()
97+
98+
# Print summary of tests ran.
99+
print("Summary: {}/{} tests passed.".format(SUCCESSES.value, SUCCESSES.value + EXCEPTIONS.value))
100+
print("Successful executions: ")
101+
print_notebook_executions(SUCCESSFUL_EXECUTIONS)
102+
103+
# Throw exception if any test fails, so that the CodeBuild also fails.
104+
if EXCEPTIONS.value > 0:
105+
print("Failed executions: ")
106+
print_notebook_executions(FAILED_EXECUTIONS)
107+
raise Exception("Test did not complete successfully")
108+
109+
print("Total time taken for tests: ")
110+
print(datetime.now() - startTime)

0 commit comments

Comments
 (0)