1##########################################################################
2# Copyright (c) 2016, ETH Zurich.
3# All rights reserved.
4#
5# This file is distributed under the terms in the attached LICENSE file.
6# If you do not find this file, copies can be found by writing to:
7# ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
8##########################################################################
9
10import re, datetime
11import debug, tests
12from common import TestCommon, TimeoutError
13from results import RowResults, PassFailResult
14
15BLK_TEST_TIMEOUT = datetime.timedelta(minutes=8) # XXX: tilsiter1 needs a bit longer (slow write speeds?)
16
17bandwidth = {
18    'tilsiter1': {
19        'read': {
20            512: 32.67,
21            1024: 50.08,
22            2048: 90.15,
23            4096: 154.21,
24            8192: 236.92,
25            16384: 318.05,
26            32768: 379.68,
27            65536: 416.99,
28            131072: 428.64,
29            262144: 439.88,
30            524288: 495.27,
31            1048576: 528.16,
32            2097152: 546.71
33        },
34        'write': {
35            512: 5.41,
36            1024: 1.70,
37            2048: 3.32,
38            4096: 6.68,
39            8192: 26.50,
40            16384: 49.92,
41            32768: 88.74,
42            65536: 143.63,
43            131072: 212.54,
44            262144: 281.08,
45            524288: 377.55,
46            1048576: 436.48,
47            2097152: 49.25,
48        },
49    },
50
51    'vacherin': {
52        'read': {
53            512: 15.24,
54            1024: 15.35,
55            2048: 30.32,
56            4096: 57.29,
57            8192: 102.01,
58            16384: 167.28,
59            32768: 237.24,
60            65536: 316.74,
61            131072: 361.41,
62            262144: 405.19,
63            524288: 490.97,
64            1048576: 415.05,
65            2097152: 424.57
66        },
67        'write': {
68            512: 15.20,
69            1024: 12.55,
70            2048: 26.87,
71            4096: 51.89,
72            8192: 93.21,
73            16384: 152.43,
74            32768: 213.55,
75            65536: 296.29,
76            131072: 365.72,
77            262144: 412.98,
78            524288: 440.78,
79            1048576: 454.21,
80            2097152: 462.02,
81        }
82    },
83
84    'babybel1': {
85        'read': {
86            512: 43.42,
87            1024: 25.56,
88            2048: 31.16,
89            4096: 55.63,
90            8192: 85.02,
91            16384: 114.35,
92            32768: 105.40,
93            65536: 147.15,
94            131072: 414.57,
95            262144: 482.58,
96            524288: 515.73,
97            1048576: 534.20,
98            2097152: 544.49,
99            4194304: 549.79,
100        },
101        'write': {
102            512: 42.52,
103            1024: 38.18,
104            2048: 41.29,
105            4096: 75.26,
106            8192: 221.12,
107            16384: 267.90,
108            32768: 426.09,
109            65536: 494.36,
110            131072: 516.22,
111            262144: 526.34,
112            524288: 533.67,
113            1048576: 533.67,
114            2097152: 522.25,
115            4194304: 523.27
116        },
117    },
118
119    'babybel2': {
120        'read': {
121            512: 43.32,
122            1024: 14.08,
123            2048: 31.10,
124            4096: 55.14,
125            8192: 83.53,
126            16384: 108.78,
127            32768: 95.90,
128            65536: 115.02,
129            131072: 159.26,
130            262144: 427.62,
131            524288: 514.74,
132            1048576: 533.14,
133            2097152: 503.16
134        },
135        'write': {
136            512: 43.09,
137            1024: 22.52,
138            2048: 41.00,
139            4096: 75.28,
140            8192: 220.75,
141            16384: 268.17,
142            32768: 416.18,
143            65536: 497.10,
144            131072: 519.22,
145            262144: 529.46,
146            524288: 534.73,
147            1048576: 537.95,
148            2097152: 518.22,
149        },
150    },
151
152    'babybel3': {
153        'read': {
154            512: 43.53,
155            1024: 25.71,
156            2048: 26.38,
157            4096: 55.21,
158            8192: 83.35,
159            16384: 107.88,
160            32768: 95.66,
161            65536: 115.43,
162            131072: 159.21,
163            262144: 428.30,
164            524288: 514.24,
165            1048576: 532.87,
166            2097152: 504.82,
167        },
168        'write': {
169            512: 42.86,
170            1024: 38.40,
171            2048: 41.43,
172            4096: 75.83,
173            8192: 225.01,
174            16384: 265.78,
175            32768: 428.13,
176            65536: 495.27,
177            131072: 513.26,
178            262144: 528.42,
179            524288: 532.61,
180            1048576: 532.61,
181            2097152: 525.31,
182        }
183    },
184
185    'babybel4': {
186        'read': {
187            512: 43.46,
188            1024: 25.73,
189            2048: 31.17,
190            4096: 55.25,
191            8192: 83.51,
192            16384: 108.35,
193            32768: 95.72,
194            65536: 115.08,
195            131072: 159.78,
196            262144: 381.98,
197            524288: 492.54,
198            1048576: 512.53,
199            2097152: 451.34
200        },
201        'write': {
202            512: 42.49,
203            1024: 38.40,
204            2048: 41.47,
205            4096: 76.96,
206            8192: 225.20,
207            16384: 265.51,
208            32768: 430.19,
209            65536: 496.18,
210            131072: 517.22,
211            262144: 529.46,
212            524288: 534.73,
213            1048576: 534.73,
214            2097152: 524.29
215        }
216    }
217}
218
219class BlkTests(TestCommon):
220
221    def __init__(self, options):
222        super(BlkTests, self).__init__(options)
223
224    def get_module_name(self):
225        return "ahci_test"
226
227    def boot(self, *args):
228        super(BlkTests, self).boot(*args)
229        self.set_timeout(BLK_TEST_TIMEOUT)
230
231    def get_modules(self, build, machine):
232        self.machine = machine.name
233        modules = super(BlkTests, self).get_modules(build, machine)
234        modules.add_module_arg("kaluga","add_device_db=device_db_ahcitest")
235        modules.add_module(self.get_module_name(), ["auto", self.OP])
236
237        return modules
238
239    def get_finish_string(self):
240        return "AHCI testing completed."
241
242    def process_data(self, testdir, rawiter):
243        self.regex = re.compile(self.REGEX)
244        result = RowResults(['op', 'buffer', 'block', 'bandwidth'])
245        if not bandwidth.has_key(self.machine):
246            result.mark_failed('No data about this disk, please set the initial performance values.')
247            return result
248
249        matches = 0
250        num_fail = 0
251        for line in rawiter:
252            match = self.regex.match(line)
253            if match:
254                matches += 1
255
256                buffer_size, bs, bw = match.groups()
257                buffer_size = int(buffer_size)
258                bs = int(bs)
259                bw = float(bw)
260                operation = self.OP.lower()
261                if not bandwidth[self.machine].has_key(operation):
262                    result.mark_failed('No data about this benchmark, please set the initial performance values.')
263                    return result
264                if not bandwidth[self.machine][operation].has_key(bs):
265                    result.mark_failed('No data for {} with bs {}.'.format(operation, bs))
266                    return result
267
268                lower_bound = bandwidth[self.machine][operation][bs] * (1 - 0.25)
269                upper_bound = bandwidth[self.machine][operation][bs] * (1 + 0.25)
270
271                result.add_row((operation, buffer_size, bs, bw))
272                if bw <= lower_bound:
273                    error = "{} for {} bytes blocks not within expected range (was {}, should be >= {}).".format(operation, bs, bw, lower_bound)
274                    debug.log(error)
275                    num_fail+= 1;
276                    if num_fail > 1:
277                        result.mark_failed(reason=error)
278                elif bw >= upper_bound:
279                    error = "Achieved {} bandwidth for {} bytes blocks was better ({}) than expected ({}).".format(operation, bs, bw, upper_bound)
280                    debug.log(error)
281                    debug.log("This is good, if you can explain it! Adjust the bandwidth numbers in blk_tests.py and re-run the test.")
282                    num_fail+= 1
283                    if num_fail > 1:
284                        result.mark_failed(reason=error)
285                else:
286                    pass
287
288            if line.startswith("AHCI testing completed.") and matches > 0:
289                return result
290
291        result.mark_failed('Did not see end of test or got no bandwidth numbers.')
292        return result
293
294@tests.add_test
295class BlkAhciWriteBWTest(BlkTests):
296    ''' AHCI Driver Write Bandwidth Test'''
297    name = "blk_read_test"
298    OP = "read"
299    REGEX = r"\[ahci_perf_sequential\] Read sequential size (\d+) bs (\d+): (\d+\.\d+) \[MB/s\]"
300
301@tests.add_test
302class BlkAhciReadBWTest(BlkTests):
303    ''' AHCI Driver Read Bandwidth Test'''
304    name = "blk_write_test"
305    OP = "write"
306    REGEX = r"\[ahci_perf_sequential\] Write sequential size (\d+) bs (\d+): (\d+\.\d+) \[MB/s\]"
307
308@tests.add_test
309class BlkAhciVerifyTest(BlkTests):
310    ''' AHCI Driver Correctness test '''
311    name = "blk_verify_test"
312    OP = "verify"
313    REGEX = r"\[ahci_verify_sequential\] SUCCESS \((\d+) (\d+)\)"
314    TESTS = 14
315
316    def process_data(self, testdir, rawiter):
317        self.regex = re.compile(self.REGEX)
318
319        matches = 0
320        for line in rawiter:
321            match = self.regex.match(line)
322            if match:
323                matches += 1
324
325        if matches == self.TESTS:
326            return PassFailResult(True)
327        elif matches < self.TESTS:
328            return PassFailResult(False, "Some block/buffer size checks did not report back with SUCCESS.")
329        elif matches > self.TESTS:
330            return PassFailResult(False, "Got more SUCCESS lines than expected. If you changed the test you may need to increase self.TESTS.")
331        else:
332            assert "Should not come here"
333