blob: a048703ea660b0ae473b89a15b43be1236e0d2b1 [file] [log] [blame]
koder aka kdanilov4643fd62015-02-10 16:20:13 -08001import abc
koder aka kdanilov66839a92015-04-11 13:22:31 +03002import time
koder aka kdanilov4643fd62015-02-10 16:20:13 -08003import os.path
koder aka kdanilove21d7472015-02-14 19:02:04 -08004import logging
5
koder aka kdanilov2e928022015-04-08 13:47:15 +03006from disk_perf_test_tool.tests import disk_test_agent
koder aka kdanilov66839a92015-04-11 13:22:31 +03007from disk_perf_test_tool.tests.disk_test_agent import parse_fio_config_full
koder aka kdanilov1c2b5112015-04-10 16:53:51 +03008from disk_perf_test_tool.tests.io_results_loader import parse_output
koder aka kdanilov2e928022015-04-08 13:47:15 +03009from disk_perf_test_tool.ssh_utils import copy_paths
10from disk_perf_test_tool.utils import run_over_ssh, ssize_to_b
koder aka kdanilov4643fd62015-02-10 16:20:13 -080011
koder aka kdanilove21d7472015-02-14 19:02:04 -080012logger = logging.getLogger("io-perf-tool")
13
14
koder aka kdanilov4643fd62015-02-10 16:20:13 -080015class IPerfTest(object):
16 def __init__(self, on_result_cb):
17 self.on_result_cb = on_result_cb
18
koder aka kdanilov4643fd62015-02-10 16:20:13 -080019 def pre_run(self, conn):
20 pass
21
22 @abc.abstractmethod
koder aka kdanilov2c473092015-03-29 17:12:13 +030023 def run(self, conn, barrier):
koder aka kdanilov4643fd62015-02-10 16:20:13 -080024 pass
25
26
Yulia Portnova7ddfa732015-02-24 17:32:58 +020027class TwoScriptTest(IPerfTest):
Yulia Portnova886a2562015-04-07 11:16:13 +030028 def __init__(self, opts, on_result_cb):
Yulia Portnova7ddfa732015-02-24 17:32:58 +020029 super(TwoScriptTest, self).__init__(on_result_cb)
30 self.opts = opts
31 self.pre_run_script = None
32 self.run_script = None
33 self.tmp_dir = "/tmp/"
34 self.set_run_script()
35 self.set_pre_run_script()
36
37 def set_run_script(self):
38 self.pre_run_script = self.opts.pre_run_script
39
40 def set_pre_run_script(self):
41 self.run_script = self.opts.run_script
42
43 def get_remote_for_script(self, script):
44 return os.path.join(self.tmp_dir, script.rpartition('/')[2])
45
46 def copy_script(self, conn, src):
47 remote_path = self.get_remote_for_script(src)
48 copy_paths(conn, {src: remote_path})
49 return remote_path
50
51 def pre_run(self, conn):
52 remote_script = self.copy_script(conn, self.pre_run_script)
53 cmd = remote_script
koder aka kdanilov66839a92015-04-11 13:22:31 +030054 run_over_ssh(conn, cmd)
Yulia Portnova7ddfa732015-02-24 17:32:58 +020055
koder aka kdanilov2c473092015-03-29 17:12:13 +030056 def run(self, conn, barrier):
Yulia Portnova7ddfa732015-02-24 17:32:58 +020057 remote_script = self.copy_script(conn, self.run_script)
Yulia Portnova886a2562015-04-07 11:16:13 +030058 cmd_opts = ' '.join(["%s %s" % (key, val) for key, val
59 in self.opts.items()])
60 cmd = remote_script + ' ' + cmd_opts
koder aka kdanilov66839a92015-04-11 13:22:31 +030061 out_err = run_over_ssh(conn, cmd)
62 self.on_result(out_err, cmd)
Yulia Portnova7ddfa732015-02-24 17:32:58 +020063
64 def parse_results(self, out):
65 for line in out.split("\n"):
66 key, separator, value = line.partition(":")
67 if key and value:
68 self.on_result_cb((key, float(value)))
69
koder aka kdanilov66839a92015-04-11 13:22:31 +030070 def on_result(self, out_err, cmd):
71 try:
72 self.parse_results(out_err)
73 except Exception as exc:
74 msg_templ = "Error during postprocessing results: {0!r}. {1}"
75 raise RuntimeError(msg_templ.format(exc.message, out_err))
Yulia Portnova7ddfa732015-02-24 17:32:58 +020076
77
78class PgBenchTest(TwoScriptTest):
79
80 def set_run_script(self):
Yulia Portnova886a2562015-04-07 11:16:13 +030081 self.pre_run_script = "tests/postgres/prepare.sh"
Yulia Portnova7ddfa732015-02-24 17:32:58 +020082
83 def set_pre_run_script(self):
Yulia Portnova886a2562015-04-07 11:16:13 +030084 self.run_script = "tests/postgres/run.sh"
Yulia Portnova7ddfa732015-02-24 17:32:58 +020085
86
koder aka kdanilov4643fd62015-02-10 16:20:13 -080087class IOPerfTest(IPerfTest):
koder aka kdanilovda45e882015-04-06 02:24:42 +030088 io_py_remote = "/tmp/disk_test_agent.py"
koder aka kdanilov2c473092015-03-29 17:12:13 +030089
koder aka kdanilov4643fd62015-02-10 16:20:13 -080090 def __init__(self,
koder aka kdanilov2c473092015-03-29 17:12:13 +030091 test_options,
92 on_result_cb):
koder aka kdanilov4643fd62015-02-10 16:20:13 -080093 IPerfTest.__init__(self, on_result_cb)
koder aka kdanilov2c473092015-03-29 17:12:13 +030094 self.options = test_options
koder aka kdanilovda45e882015-04-06 02:24:42 +030095 self.config_fname = test_options['cfg']
96 self.config_params = test_options.get('params', {})
97 self.tool = test_options.get('tool', 'fio')
98 self.raw_cfg = open(self.config_fname).read()
koder aka kdanilov66839a92015-04-11 13:22:31 +030099 self.configs = parse_fio_config_full(self.raw_cfg, self.config_params)
koder aka kdanilov4643fd62015-02-10 16:20:13 -0800100
101 def pre_run(self, conn):
koder aka kdanilovda45e882015-04-06 02:24:42 +0300102
103 # TODO: install fio, if not installed
koder aka kdanilov66839a92015-04-11 13:22:31 +0300104 cmd = "sudo apt-get -y install fio"
105
106 for i in range(3):
107 try:
108 run_over_ssh(conn, cmd)
109 break
110 except OSError:
111 time.sleep(3)
koder aka kdanilovda45e882015-04-06 02:24:42 +0300112
113 local_fname = disk_test_agent.__file__.rsplit('.')[0] + ".py"
koder aka kdanilov2c473092015-03-29 17:12:13 +0300114 self.files_to_copy = {local_fname: self.io_py_remote}
koder aka kdanilov50f18642015-02-11 08:54:44 -0800115 copy_paths(conn, self.files_to_copy)
koder aka kdanilov4643fd62015-02-10 16:20:13 -0800116
koder aka kdanilov2c473092015-03-29 17:12:13 +0300117 cmd_templ = "dd if=/dev/zero of={0} bs={1} count={2}"
118 for secname, params in self.configs:
119 sz = ssize_to_b(params['size'])
120 msz = msz = sz / (1024 ** 2)
121 if sz % (1024 ** 2) != 0:
122 msz += 1
koder aka kdanilov6e2ae792015-03-04 18:02:24 -0800123
koder aka kdanilov2c473092015-03-29 17:12:13 +0300124 cmd = cmd_templ.format(params['filename'], 1024 ** 2, msz)
koder aka kdanilov66839a92015-04-11 13:22:31 +0300125 run_over_ssh(conn, cmd)
koder aka kdanilov6e2ae792015-03-04 18:02:24 -0800126
koder aka kdanilov2c473092015-03-29 17:12:13 +0300127 def run(self, conn, barrier):
koder aka kdanilov66839a92015-04-11 13:22:31 +0300128 cmd_templ = "env python2 {0} --type {1} {2} --json -"
129
130 params = " ".join("{0}={1}".format(k, v)
131 for k, v in self.config_params.items())
132
133 if "" != params:
134 params = "--params " + params
135
136 cmd = cmd_templ.format(self.io_py_remote, self.tool, params)
137 logger.debug("Waiting on barrier")
koder aka kdanilov2c473092015-03-29 17:12:13 +0300138 try:
koder aka kdanilovda45e882015-04-06 02:24:42 +0300139 barrier.wait()
koder aka kdanilov66839a92015-04-11 13:22:31 +0300140 logger.debug("Run {0}".format(cmd))
141 out_err = run_over_ssh(conn, cmd, stdin_data=self.raw_cfg)
142 self.on_result(out_err, cmd)
koder aka kdanilov2c473092015-03-29 17:12:13 +0300143 finally:
144 barrier.exit()
145
koder aka kdanilov66839a92015-04-11 13:22:31 +0300146 def on_result(self, out_err, cmd):
147 try:
148 for data in parse_output(out_err):
149 self.on_result_cb(data)
150 except Exception as exc:
151 msg_templ = "Error during postprocessing results: {0!r}"
152 raise RuntimeError(msg_templ.format(exc.message))
153
154 def merge_results(self, results):
155 merged_result = results[0]
156 merged_data = merged_result['res']
157 expected_keys = set(merged_data.keys())
158 mergable_fields = ['bw_mean', 'clat', 'iops', 'lat', 'slat']
159
160 for res in results[1:]:
161 assert res['__meta__'] == merged_result['__meta__']
162
163 data = res['res']
164 diff = set(data.keys()).symmetric_difference(expected_keys)
165
166 msg = "Difference: {0}".format(",".join(diff))
167 assert len(diff) == 0, msg
168
169 for testname, test_data in data.items():
170 res_test_data = merged_data[testname]
171
172 diff = set(test_data.keys()).symmetric_difference(
173 res_test_data.keys())
174
175 msg = "Difference: {0}".format(",".join(diff))
176 assert len(diff) == 0, msg
177
178 for k, v in test_data.items():
179 if k in mergable_fields:
180 res_test_data[k].extend(v)
181 else:
182 msg = "{0!r} != {1!r}".format(res_test_data[k], v)
183 assert res_test_data[k] == v, msg
184
185 return merged_result