blob: b4961906d4bcf3914a17b18f1a39ab5eb68668b3 [file] [log] [blame]
koder aka kdanilov0c598a12015-04-21 03:01:40 +03001import os.path
2import unittest
3
4
5from oktest import ok, main, test
6
7
koder aka kdanilov39e449e2016-12-17 15:15:26 +02008from wally.suits.io import fio_task_parser
koder aka kdanilov0c598a12015-04-21 03:01:40 +03009
10code_test_defaults = """
11[defaults]
12wait_for_previous
13buffered=0
14iodepth=2
15RUNTIME=20
16
17[sec1]
18group_reporting
19time_based
20softrandommap=1
21filename=/tmp/xxx
22size=5G
23ramp_time=20
24runtime={RUNTIME}
25blocksize=1m
26rw=read
27direct=1
28numjobs=1
29some_extra=1.2314
30
31[sec2]
32group_reporting
33time_based
34iodepth=1
35softrandommap=1
36filename=/tmp/xxx
37size=5G
38ramp_time=20
39runtime={RUNTIME}
40blocksize=1m
41rw=read
42direct=1
43numjobs=1
44some_extra=1.2314
45"""
46
47defaults = """
48[defaults]
49wait_for_previous
50group_reporting
51time_based
52buffered=0
53iodepth=1
54softrandommap=1
55filename=/tmp/xxx
56size=5G
57ramp_time=20
58runtime=20
59blocksize=1m
60rw=read
61direct=1
62numjobs=1
63"""
64
65code_test_auto_params_1 = defaults + """
66[defaults]
67RUNTIME=30
68
69[sec1_{TEST_SUMM}]
70ramp_time={% 20, 40 %}
71runtime={RUNTIME}
72blocksize={% 4k, 4m %}
73"""
74
75
76code_test_uniq = defaults + """
77[defaults]
78REPCOUNT=2
79RUNTIME=30
80
81[sec1_{TEST_SUMM}_{UNIQ} * 3]
82
83[sec2_{TEST_SUMM}_{UNIQ} * {REPCOUNT}]
84"""
85
86code_test_cycles_default = defaults + """
87[defaults]
88REPCOUNT=2
89RUNTIME={% 30, 60 %}
90
91[sec1_{TEST_SUMM}_{UNIQ} * 3]
92runtime={RUNTIME}
93blocksize={% 4k, 4m %}
94"""
95
96
koder aka kdanilov0c598a12015-04-21 03:01:40 +030097class AgentTest(unittest.TestCase):
98 @test("test_parse_value")
99 def test_parse_value(self):
100 x = "asdfasd adsd d"
koder aka kdanilov39e449e2016-12-17 15:15:26 +0200101 ok(fio_task_parser.parse_value(x)) == x
102 ok(fio_task_parser.parse_value("10 2")) == "10 2"
103 ok(fio_task_parser.parse_value("None")).is_(None)
104 ok(fio_task_parser.parse_value("10")) == 10
105 ok(fio_task_parser.parse_value("20")) == 20
106 ok(fio_task_parser.parse_value("10.1") - 10.1) < 1E-7
107 ok(fio_task_parser.parse_value("{% 10, 20 %}")) == [10, 20]
108 ok(fio_task_parser.parse_value("{% 10,20 %}")) == [10, 20]
koder aka kdanilov0c598a12015-04-21 03:01:40 +0300109
110 code_test_compile_simplest = defaults + """
111[sec1]
112some_extra=1.2314
113"""
114
115 @test("test_compile_simplest")
116 def test_compile_simplest(self):
koder aka kdanilov39e449e2016-12-17 15:15:26 +0200117 sections = fio_task_parser.parse_all_in_1(self.code_test_compile_simplest, {})
koder aka kdanilov0c598a12015-04-21 03:01:40 +0300118 sections = list(sections)
119
120 ok(len(sections)) == 1
121 sec1 = sections[0]
122 ok(sec1.name) == "sec1"
123 vals = sec1.vals
124 ok(vals['wait_for_previous']).is_(None)
125 ok(vals['iodepth']) == 1
126 ok(vals['some_extra'] - 1.2314) < 1E-7
127
128 code_test_params_in_defaults = defaults + """
129[defaults]
130RUNTIME=20
131
132[sec1]
133runtime={RUNTIME}
134"""
135
136 @test("test_compile_defaults")
137 def test_compile_defaults(self):
koder aka kdanilov39e449e2016-12-17 15:15:26 +0200138 sections = fio_task_parser.parse_all_in_1(self.code_test_params_in_defaults, {})
koder aka kdanilov0c598a12015-04-21 03:01:40 +0300139 sections = list(sections)
140
141 ok(len(sections)) == 1
142 sec1 = sections[0]
143 ok(sec1.name) == "sec1"
144 vals = sec1.vals
145 ok(vals['wait_for_previous']).is_(None)
146 ok(vals['iodepth']) == 1
147 ok(vals['runtime']) == 20
148
149 @test("test_defaults")
150 def test_defaults(self):
koder aka kdanilov39e449e2016-12-17 15:15:26 +0200151 sections = fio_task_parser.parse_all_in_1(code_test_defaults, {})
koder aka kdanilov0c598a12015-04-21 03:01:40 +0300152 sections = list(sections)
153
154 ok(len(sections)) == 2
155 sec1, sec2 = sections
156
157 ok(sec1.name) == "sec1"
158 ok(sec2.name) == "sec2"
159
160 ok(sec1.vals['wait_for_previous']).is_(None)
161 ok(sec2.vals['wait_for_previous']).is_(None)
162
163 ok(sec1.vals['iodepth']) == 2
164 ok(sec2.vals['iodepth']) == 1
165
166 ok(sec1.vals['buffered']) == 0
167 ok(sec2.vals['buffered']) == 0
168
169 code_test_ext_params = defaults + """
170[sec1]
171runtime={RUNTIME}
172"""
173
174 @test("test_external_params")
175 def test_external_params(self):
176 with self.assertRaises(KeyError):
koder aka kdanilov39e449e2016-12-17 15:15:26 +0200177 sections = fio_task_parser.parse_all_in_1(self.code_test_ext_params, {})
koder aka kdanilov0c598a12015-04-21 03:01:40 +0300178 list(sections)
179
koder aka kdanilov39e449e2016-12-17 15:15:26 +0200180 sections = fio_task_parser.parse_all_in_1(self.code_test_ext_params, {'RUNTIME': 20})
koder aka kdanilov0c598a12015-04-21 03:01:40 +0300181 sections = list(sections)
182
183 code_test_cycle = defaults + """
184[sec1]
185runtime={RUNTIME}
186ramp_time={% 20, 40 %}
187"""
188
189 @test("test_cycle")
190 def test_cycle(self):
koder aka kdanilov39e449e2016-12-17 15:15:26 +0200191 sections = fio_task_parser.parse_all_in_1(self.code_test_cycle, {'RUNTIME': 20})
koder aka kdanilov0c598a12015-04-21 03:01:40 +0300192 sections = list(sections)
193 ok(len(sections)) == 2
194 ok(sections[0].vals['ramp_time']) == 20
195 ok(sections[1].vals['ramp_time']) == 40
196
197 code_test_cycles = defaults + """
198[sec1]
199ramp_time={% 20, 40 %}
200runtime={RUNTIME}
201blocksize={% 4k, 4m %}
202"""
203
204 @test("test_cycles")
205 def test_cycles(self):
koder aka kdanilov39e449e2016-12-17 15:15:26 +0200206 sections = fio_task_parser.parse_all_in_1(self.code_test_cycles, {'RUNTIME': 20})
koder aka kdanilov0c598a12015-04-21 03:01:40 +0300207 sections = list(sections)
208 ok(len(sections)) == 4
209
210 combinations = [
211 (section.vals['ramp_time'], section.vals['blocksize'])
212 for section in sections
213 ]
214
215 combinations.sort()
216
217 ok(combinations) == [(20, '4k'), (20, '4m'), (40, '4k'), (40, '4m')]
218
219 @test("test_time_estimate")
220 def test_time_estimate(self):
koder aka kdanilov39e449e2016-12-17 15:15:26 +0200221 sections = fio_task_parser.parse_all_in_1(self.code_test_cycles, {'RUNTIME': 20})
koder aka kdanilov0c598a12015-04-21 03:01:40 +0300222 sections = list(sections)
koder aka kdanilov39e449e2016-12-17 15:15:26 +0200223 etime = fio_task_parser.calculate_execution_time(sections)
koder aka kdanilov0c598a12015-04-21 03:01:40 +0300224
225 ok(etime) == 20 * 4 + 20 * 2 + 40 * 2
koder aka kdanilov39e449e2016-12-17 15:15:26 +0200226 ok(fio_task_parser.sec_to_str(etime)) == "0:03:20"
koder aka kdanilov0c598a12015-04-21 03:01:40 +0300227
228 code_test_cycles2 = defaults + """
229[sec1 * 7]
230ramp_time={% 20, 40 %}
231runtime={RUNTIME}
232blocksize={% 4k, 4m %}
233"""
234
235 @test("test_time_estimate")
236 def test_time_estimate_large(self):
koder aka kdanilov39e449e2016-12-17 15:15:26 +0200237 sections = fio_task_parser.parse_all_in_1(self.code_test_cycles2, {'RUNTIME': 30})
koder aka kdanilov0c598a12015-04-21 03:01:40 +0300238 sections = list(sections)
239
240 ok(sections[0].name) == 'sec1'
241 ok(len(sections)) == 7 * 4
242
koder aka kdanilov39e449e2016-12-17 15:15:26 +0200243 etime = fio_task_parser.calculate_execution_time(sections)
koder aka kdanilov0c598a12015-04-21 03:01:40 +0300244 # ramptime optimization
245 expected_time = (20 + 30 + 30 * 6) * 2
246 expected_time += (40 + 30 + 30 * 6) * 2
247 ok(etime) == expected_time
248
249 code_test_cycles3 = defaults + """
250[sec1 * 7]
251ramp_time={% 20, 40 %}
252runtime={RUNTIME}
253blocksize={% 4k, 4m %}
254
255[sec2 * 7]
256ramp_time={% 20, 40 %}
257runtime={RUNTIME}
258blocksize={% 4k, 4m %}
259"""
260
261 @test("test_time_estimate2")
262 def test_time_estimate_large2(self):
koder aka kdanilov39e449e2016-12-17 15:15:26 +0200263 sections = fio_task_parser.parse_all_in_1(self.code_test_cycles3, {'RUNTIME': 30})
koder aka kdanilov0c598a12015-04-21 03:01:40 +0300264 sections = list(sections)
265
266 ok(sections[0].name) == 'sec1'
267 ok(sections[1].name) == 'sec1'
268 ok(len(sections)) == 7 * 4 * 2
269
koder aka kdanilov39e449e2016-12-17 15:15:26 +0200270 etime = fio_task_parser.calculate_execution_time(sections)
koder aka kdanilov0c598a12015-04-21 03:01:40 +0300271 # ramptime optimization
272 expected_time = (20 + 30 + 30 * 6) * 2
273 expected_time += (40 + 30 + 30 * 6) * 2
274 ok(etime) == expected_time * 2
275
276 code_test_repeats = defaults + """
277[defaults]
278REPCOUNT=2
279[sec1 * 3]
280[sec2 * {REPCOUNT}]
281"""
282
283 @test("test_repeat")
284 def test_repeat(self):
koder aka kdanilov39e449e2016-12-17 15:15:26 +0200285 sections = fio_task_parser.parse_all_in_1(self.code_test_repeats, {})
koder aka kdanilov0c598a12015-04-21 03:01:40 +0300286 sections = list(sections)
287 ok(len(sections)) == 2 + 3
288 ok(sections[0].name) == 'sec1'
289 ok(sections[1].name) == 'sec1'
290 ok(sections[2].name) == 'sec1'
291 ok(sections[3].name) == 'sec2'
292 ok(sections[4].name) == 'sec2'
293
294 @test("test_real_tasks")
295 def test_real_tasks(self):
koder aka kdanilov39e449e2016-12-17 15:15:26 +0200296 tasks_dir = os.path.dirname(fio_task_parser.__file__)
koder aka kdanilov0c598a12015-04-21 03:01:40 +0300297 fname = os.path.join(tasks_dir, 'io_scenario_ceph.cfg')
298 fc = open(fname).read()
299
300 sections = P(fc, {'FILENAME': '/dev/null'})
301 sections = list(sections)
302
303 ok(len(sections)) == 7 * 9 * 4 + 7
304
koder aka kdanilov39e449e2016-12-17 15:15:26 +0200305 etime = fio_task_parser.calculate_execution_time(sections)
koder aka kdanilov0c598a12015-04-21 03:01:40 +0300306 # ramptime optimization
307 expected_time = (60 * 7 + 30) * 9 * 4 + (60 * 7 + 30)
308 ok(etime) == expected_time
309
310if __name__ == '__main__':
311 main()
312
313# def do_run_fio_fake(bconf):
314# def estimate_iops(sz, bw, lat):
315# return 1 / (lat + float(sz) / bw)
316# global count
317# count += 1
318# parsed_out = []
319
320# BW = 120.0 * (1024 ** 2)
321# LAT = 0.003
322
323# for name, cfg in bconf:
324# sz = to_bytes(cfg['blocksize'])
325# curr_lat = LAT * ((random.random() - 0.5) * 0.1 + 1)
326# curr_ulat = curr_lat * 1000000
327# curr_bw = BW * ((random.random() - 0.5) * 0.1 + 1)
328# iops = estimate_iops(sz, curr_bw, curr_lat)
329# bw = iops * sz
330
331# res = {'ctx': 10683,
332# 'error': 0,
333# 'groupid': 0,
334# 'jobname': name,
335# 'majf': 0,
336# 'minf': 30,
337# 'read': {'bw': 0,
338# 'bw_agg': 0.0,
339# 'bw_dev': 0.0,
340# 'bw_max': 0,
341# 'bw_mean': 0.0,
342# 'bw_min': 0,
343# 'clat': {'max': 0,
344# 'mean': 0.0,
345# 'min': 0,
346# 'stddev': 0.0},
347# 'io_bytes': 0,
348# 'iops': 0,
349# 'lat': {'max': 0, 'mean': 0.0,
350# 'min': 0, 'stddev': 0.0},
351# 'runtime': 0,
352# 'slat': {'max': 0, 'mean': 0.0,
353# 'min': 0, 'stddev': 0.0}
354# },
355# 'sys_cpu': 0.64,
356# 'trim': {'bw': 0,
357# 'bw_agg': 0.0,
358# 'bw_dev': 0.0,
359# 'bw_max': 0,
360# 'bw_mean': 0.0,
361# 'bw_min': 0,
362# 'clat': {'max': 0,
363# 'mean': 0.0,
364# 'min': 0,
365# 'stddev': 0.0},
366# 'io_bytes': 0,
367# 'iops': 0,
368# 'lat': {'max': 0, 'mean': 0.0,
369# 'min': 0, 'stddev': 0.0},
370# 'runtime': 0,
371# 'slat': {'max': 0, 'mean': 0.0,
372# 'min': 0, 'stddev': 0.0}
373# },
374# 'usr_cpu': 0.23,
375# 'write': {'bw': 0,
376# 'bw_agg': 0,
377# 'bw_dev': 0,
378# 'bw_max': 0,
379# 'bw_mean': 0,
380# 'bw_min': 0,
381# 'clat': {'max': 0, 'mean': 0,
382# 'min': 0, 'stddev': 0},
383# 'io_bytes': 0,
384# 'iops': 0,
385# 'lat': {'max': 0, 'mean': 0,
386# 'min': 0, 'stddev': 0},
387# 'runtime': 0,
388# 'slat': {'max': 0, 'mean': 0.0,
389# 'min': 0, 'stddev': 0.0}
390# }
391# }
392
393# if cfg['rw'] in ('read', 'randread'):
394# key = 'read'
395# elif cfg['rw'] in ('write', 'randwrite'):
396# key = 'write'
397# else:
398# raise ValueError("Uknown op type {0}".format(key))
399
400# res[key]['bw'] = bw
401# res[key]['iops'] = iops
402# res[key]['runtime'] = 30
403# res[key]['io_bytes'] = res[key]['runtime'] * bw
404# res[key]['bw_agg'] = bw
405# res[key]['bw_dev'] = bw / 30
406# res[key]['bw_max'] = bw * 1.5
407# res[key]['bw_min'] = bw / 1.5
408# res[key]['bw_mean'] = bw
409# res[key]['clat'] = {'max': curr_ulat * 10, 'mean': curr_ulat,
410# 'min': curr_ulat / 2, 'stddev': curr_ulat}
411# res[key]['lat'] = res[key]['clat'].copy()
412# res[key]['slat'] = res[key]['clat'].copy()
413
414# parsed_out.append(res)
415
416# return zip(parsed_out, bconf)