run.py 4.33 KB
Newer Older
Deshui Yu's avatar
Deshui Yu committed
1
2
3
4
5
6
#!/usr/bin/env python3

import contextlib
import json
import os
import subprocess
QuanluZhang's avatar
QuanluZhang committed
7
8
import requests
import sys
Deshui Yu's avatar
Deshui Yu committed
9
import time
10
import traceback
Deshui Yu's avatar
Deshui Yu committed
11
12
13
14
15

GREEN = '\33[32m'
RED = '\33[31m'
CLEAR = '\33[0m'

QuanluZhang's avatar
QuanluZhang committed
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
class Integration_test():
    def __init__(self):
        self.experiment_url = 'http://localhost:8080/api/v1/nni/experiment'
        self.experiment_id = None
        self.experiment_done_signal = '"Experiment done"'

    def read_last_line(self, file_name):
        try:
            *_, last_line = open(file_name)
            return last_line.strip()
        except (FileNotFoundError, ValueError):
            return None

    def fetch_experiment_config(self):
        experiment_profile = requests.get(self.experiment_url)
        self.experiment_id = json.loads(experiment_profile.text)['id']
        self.experiment_path = os.path.join(os.environ['HOME'], 'nni/experiments', self.experiment_id)
        self.nnimanager_log_path = os.path.join(self.experiment_path, 'log', 'nnimanager.log')

    def check_experiment_status(self):
        assert os.path.exists(self.nnimanager_log_path), 'Experiment starts failed'
        cmds = ['cat', self.nnimanager_log_path, '|', 'grep', self.experiment_done_signal]
        completed_process = subprocess.run(' '.join(cmds), shell = True)
        
        return completed_process.returncode == 0

    def remove_files(self, file_list):
        for file_path in file_list:
            with contextlib.suppress(FileNotFoundError):
                os.remove(file_path)

    def run(self, installed = True):
        if not installed:
            os.environ['PATH'] = os.environ['PATH'] + ':' + os.environ['PWD']
            sdk_path = os.path.abspath('../../src/sdk/pynni')
            cmd_path = os.path.abspath('../../tools')
            pypath = os.environ.get('PYTHONPATH')
            if pypath:
                pypath = ':'.join([pypath, sdk_path, cmd_path])
            else:
                pypath = ':'.join([sdk_path, cmd_path])
            os.environ['PYTHONPATH'] = pypath

        to_remove = ['tuner_search_space.json', 'tuner_result.txt', 'assessor_result.txt']
        self.remove_files(to_remove)

        proc = subprocess.run(['nnictl', 'create', '--config', 'local.yml'])
        assert proc.returncode == 0, '`nnictl create` failed with code %d' % proc.returncode

        print('Spawning trials...')
        time.sleep(1)
        self.fetch_experiment_config()
        current_trial = 0
Deshui Yu's avatar
Deshui Yu committed
69

QuanluZhang's avatar
QuanluZhang committed
70
71
        for _ in range(60):
            time.sleep(1)
Deshui Yu's avatar
Deshui Yu committed
72

QuanluZhang's avatar
QuanluZhang committed
73
74
75
            tuner_status = self.read_last_line('tuner_result.txt')
            assessor_status = self.read_last_line('assessor_result.txt')
            experiment_status = self.check_experiment_status()
Deshui Yu's avatar
Deshui Yu committed
76

QuanluZhang's avatar
QuanluZhang committed
77
78
            assert tuner_status != 'ERROR', 'Tuner exited with error'
            assert assessor_status != 'ERROR', 'Assessor exited with error'
Deshui Yu's avatar
Deshui Yu committed
79

QuanluZhang's avatar
QuanluZhang committed
80
81
            if experiment_status:
                break
Deshui Yu's avatar
Deshui Yu committed
82

QuanluZhang's avatar
QuanluZhang committed
83
84
85
86
87
88
89
90
            if tuner_status is not None:
                for line in open('tuner_result.txt'):
                    if line.strip() == 'ERROR':
                        break
                    trial = int(line.split(' ')[0])
                    if trial > current_trial:
                        current_trial = trial
                        print('Trial #%d done' % trial)
Deshui Yu's avatar
Deshui Yu committed
91

QuanluZhang's avatar
QuanluZhang committed
92
        assert experiment_status, 'Failed to finish in 1 min'
Deshui Yu's avatar
Deshui Yu committed
93

QuanluZhang's avatar
QuanluZhang committed
94
95
96
        ss1 = json.load(open('search_space.json'))
        ss2 = json.load(open('tuner_search_space.json'))
        assert ss1 == ss2, 'Tuner got wrong search space'
Deshui Yu's avatar
Deshui Yu committed
97

QuanluZhang's avatar
QuanluZhang committed
98
99
100
101
102
        tuner_result = set(open('tuner_result.txt'))
        expected = set(open('expected_tuner_result.txt'))
        # Trials may complete before NNI gets assessor's result,
        # so it is possible to have more final result than expected
        assert tuner_result.issuperset(expected), 'Bad tuner result'
Deshui Yu's avatar
Deshui Yu committed
103

QuanluZhang's avatar
QuanluZhang committed
104
105
106
        assessor_result = set(open('assessor_result.txt'))
        expected = set(open('expected_assessor_result.txt'))
        assert assessor_result == expected, 'Bad assessor result'
Deshui Yu's avatar
Deshui Yu committed
107
108

if __name__ == '__main__':
QuanluZhang's avatar
QuanluZhang committed
109
110
    installed = (sys.argv[-1] != '--preinstall')
    ci = Integration_test()
Deshui Yu's avatar
Deshui Yu committed
111
    try:
QuanluZhang's avatar
QuanluZhang committed
112
        ci.run(installed)
Deshui Yu's avatar
Deshui Yu committed
113
114
        # TODO: check the output of rest server
        print(GREEN + 'PASS' + CLEAR)
115
    except Exception as error:
Deshui Yu's avatar
Deshui Yu committed
116
        print(RED + 'FAIL' + CLEAR)
117
        print('%r' % error)
118
        traceback.print_exc()
QuanluZhang's avatar
QuanluZhang committed
119
120
121
        sys.exit(1)
    finally:
        subprocess.run(['nnictl', 'stop'])