VirtualBox

source: vbox/trunk/src/VBox/ValidationKit/tests/storage/tdStorageBenchmark1.py@ 79268

Last change on this file since 79268 was 79092, checked in by vboxsync, 6 years ago

ValKit,++: Pylint 2.3.1 adjustments.

  • Property svn:eol-style set to LF
  • Property svn:executable set to *
  • Property svn:keywords set to Author Date Id Revision
File size: 55.5 KB
Line 
1#!/usr/bin/env python
2# -*- coding: utf-8 -*-
3# $Id: tdStorageBenchmark1.py 79092 2019-06-11 15:26:40Z vboxsync $
4
5"""
6VirtualBox Validation Kit - Storage benchmark.
7"""
8
9__copyright__ = \
10"""
11Copyright (C) 2012-2019 Oracle Corporation
12
13This file is part of VirtualBox Open Source Edition (OSE), as
14available from http://www.virtualbox.org. This file is free software;
15you can redistribute it and/or modify it under the terms of the GNU
16General Public License (GPL) as published by the Free Software
17Foundation, in version 2 as it comes in the "COPYING" file of the
18VirtualBox OSE distribution. VirtualBox OSE is distributed in the
19hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
20
21The contents of this file may alternatively be used under the terms
22of the Common Development and Distribution License Version 1.0
23(CDDL) only, as it comes in the "COPYING.CDDL" file of the
24VirtualBox OSE distribution, in which case the provisions of the
25CDDL are applicable instead of those of the GPL.
26
27You may elect to license modified versions of this file under the
28terms and conditions of either the GPL or the CDDL or both.
29"""
30__version__ = "$Revision: 79092 $"
31
32
33# Standard Python imports.
34import os;
35import socket;
36import sys;
37if sys.version_info[0] >= 3:
38 from io import StringIO as StringIO; # pylint: disable=import-error,no-name-in-module,useless-import-alias
39else:
40 from StringIO import StringIO as StringIO; # pylint: disable=import-error,no-name-in-module,useless-import-alias
41
42# Only the main script needs to modify the path.
43try: __file__
44except: __file__ = sys.argv[0];
45g_ksValidationKitDir = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))));
46sys.path.append(g_ksValidationKitDir);
47
48# Validation Kit imports.
49from common import constants;
50from common import utils;
51from testdriver import reporter;
52from testdriver import base;
53from testdriver import vbox;
54from testdriver import vboxcon;
55from testdriver import vboxwrappers;
56
57import remoteexecutor;
58import storagecfg;
59
60
61class FioTest(object):
62 """
63 Flexible I/O tester testcase.
64 """
65
66 kdHostIoEngine = {
67 'solaris': ('solarisaio', False),
68 'linux': ('libaio', True)
69 };
70
71 def __init__(self, oExecutor, dCfg = None):
72 self.oExecutor = oExecutor;
73 self.sCfgFileId = None;
74 self.dCfg = dCfg;
75 self.sError = None;
76 self.sResult = None;
77
78 def prepare(self, cMsTimeout = 30000):
79 """ Prepares the testcase """
80
81 sTargetOs = self.dCfg.get('TargetOs', 'linux');
82 sIoEngine, fDirectIo = self.kdHostIoEngine.get(sTargetOs);
83 if sIoEngine is None:
84 return False;
85
86 cfgBuf = StringIO();
87 cfgBuf.write('[global]\n');
88 cfgBuf.write('bs=' + self.dCfg.get('RecordSize', '4k') + '\n');
89 cfgBuf.write('ioengine=' + sIoEngine + '\n');
90 cfgBuf.write('iodepth=' + self.dCfg.get('QueueDepth', '32') + '\n');
91 cfgBuf.write('size=' + self.dCfg.get('TestsetSize', '2g') + '\n');
92 if fDirectIo:
93 cfgBuf.write('direct=1\n');
94 else:
95 cfgBuf.write('direct=0\n');
96 cfgBuf.write('directory=' + self.dCfg.get('FilePath', '/mnt') + '\n');
97 cfgBuf.write('filename=fio.test.file');
98
99 cfgBuf.write('[seq-write]\n');
100 cfgBuf.write('rw=write\n');
101 cfgBuf.write('stonewall\n');
102
103 cfgBuf.write('[rand-write]\n');
104 cfgBuf.write('rw=randwrite\n');
105 cfgBuf.write('stonewall\n');
106
107 cfgBuf.write('[seq-read]\n');
108 cfgBuf.write('rw=read\n');
109 cfgBuf.write('stonewall\n');
110
111 cfgBuf.write('[rand-read]\n');
112 cfgBuf.write('rw=randread\n');
113 cfgBuf.write('stonewall\n');
114
115 self.sCfgFileId = self.oExecutor.copyString(cfgBuf.getvalue(), 'aio-test', cMsTimeout);
116 return self.sCfgFileId is not None;
117
118 def run(self, cMsTimeout = 30000):
119 """ Runs the testcase """
120 _ = cMsTimeout
121 fRc, sOutput, sError = self.oExecutor.execBinary('fio', (self.sCfgFileId,), cMsTimeout = cMsTimeout);
122 if fRc:
123 self.sResult = sOutput;
124 else:
125 self.sError = ('Binary: fio\n' +
126 '\nOutput:\n\n' +
127 sOutput +
128 '\nError:\n\n' +
129 sError);
130 return fRc;
131
132 def cleanup(self):
133 """ Cleans up any leftovers from the testcase. """
134
135 def reportResult(self):
136 """
137 Reports the test results to the test manager.
138 """
139 return True;
140
141 def getErrorReport(self):
142 """
143 Returns the error report in case the testcase failed.
144 """
145 return self.sError;
146
147class IozoneTest(object):
148 """
149 I/O zone testcase.
150 """
151 def __init__(self, oExecutor, dCfg = None):
152 self.oExecutor = oExecutor;
153 self.sResult = None;
154 self.sError = None;
155 self.lstTests = [ ('initial writers', 'FirstWrite'),
156 ('rewriters', 'Rewrite'),
157 ('re-readers', 'ReRead'),
158 ('stride readers', 'StrideRead'),
159 ('reverse readers', 'ReverseRead'),
160 ('random readers', 'RandomRead'),
161 ('mixed workload', 'MixedWorkload'),
162 ('random writers', 'RandomWrite'),
163 ('pwrite writers', 'PWrite'),
164 ('pread readers', 'PRead'),
165 ('fwriters', 'FWrite'),
166 ('freaders', 'FRead'),
167 ('readers', 'FirstRead')];
168 self.sRecordSize = dCfg.get('RecordSize', '4k');
169 self.sTestsetSize = dCfg.get('TestsetSize', '2g');
170 self.sQueueDepth = dCfg.get('QueueDepth', '32');
171 self.sFilePath = dCfg.get('FilePath', '/mnt/iozone');
172 self.fDirectIo = True;
173
174 sTargetOs = dCfg.get('TargetOs');
175 if sTargetOs == 'solaris':
176 self.fDirectIo = False;
177
178 def prepare(self, cMsTimeout = 30000):
179 """ Prepares the testcase """
180 _ = cMsTimeout;
181 return True; # Nothing to do.
182
183 def run(self, cMsTimeout = 30000):
184 """ Runs the testcase """
185 tupArgs = ('-r', self.sRecordSize, '-s', self.sTestsetSize, \
186 '-t', '1', '-T', '-F', self.sFilePath + '/iozone.tmp');
187 if self.fDirectIo:
188 tupArgs += ('-I',);
189 fRc, sOutput, sError = self.oExecutor.execBinary('iozone', tupArgs, cMsTimeout = cMsTimeout);
190 if fRc:
191 self.sResult = sOutput;
192 else:
193 self.sError = ('Binary: iozone\n' +
194 '\nOutput:\n\n' +
195 sOutput +
196 '\nError:\n\n' +
197 sError);
198
199 _ = cMsTimeout;
200 return fRc;
201
202 def cleanup(self):
203 """ Cleans up any leftovers from the testcase. """
204 return True;
205
206 def reportResult(self):
207 """
208 Reports the test results to the test manager.
209 """
210
211 fRc = True;
212 if self.sResult is not None:
213 try:
214 asLines = self.sResult.splitlines();
215 for sLine in asLines:
216 sLine = sLine.strip();
217 if sLine.startswith('Children') is True:
218 # Extract the value
219 idxValue = sLine.rfind('=');
220 if idxValue == -1:
221 raise Exception('IozoneTest: Invalid state');
222
223 idxValue += 1;
224 while sLine[idxValue] == ' ':
225 idxValue += 1;
226
227 # Get the reported value, cut off after the decimal point
228 # it is not supported by the testmanager yet and is not really
229 # relevant anyway.
230 idxValueEnd = idxValue;
231 while sLine[idxValueEnd].isdigit():
232 idxValueEnd += 1;
233
234 for sNeedle, sTestVal in self.lstTests:
235 if sLine.rfind(sNeedle) != -1:
236 reporter.testValue(sTestVal, sLine[idxValue:idxValueEnd],
237 constants.valueunit.g_asNames[constants.valueunit.KILOBYTES_PER_SEC]);
238 break;
239 except:
240 fRc = False;
241 else:
242 fRc = False;
243
244 return fRc;
245
246 def getErrorReport(self):
247 """
248 Returns the error report in case the testcase failed.
249 """
250 return self.sError;
251
252class StorTestCfgMgr(object):
253 """
254 Manages the different testcases.
255 """
256
257 def __init__(self, aasTestLvls, aasTestsBlacklist, fnIsCfgSupported = None):
258 self.aasTestsBlacklist = aasTestsBlacklist;
259 self.at3TestLvls = [];
260 self.iTestLvl = 0;
261 self.fnIsCfgSupported = fnIsCfgSupported;
262 for asTestLvl in aasTestLvls:
263 if isinstance(asTestLvl, tuple):
264 asTestLvl, fnTestFmt = asTestLvl;
265 self.at3TestLvls.append((0, fnTestFmt, asTestLvl));
266 else:
267 self.at3TestLvls.append((0, None, asTestLvl));
268
269 self.at3TestLvls.reverse();
270
271 # Get the first non blacklisted test.
272 asTestCfg = self.getCurrentTestCfg();
273 while asTestCfg and self.isTestCfgBlacklisted(asTestCfg):
274 asTestCfg = self.advanceTestCfg();
275
276 iLvl = 0;
277 for sCfg in asTestCfg:
278 reporter.testStart('%s' % (self.getTestIdString(sCfg, iLvl)));
279 iLvl += 1;
280
281 def __del__(self):
282 # Make sure the tests are marked as done.
283 while self.iTestLvl < len(self.at3TestLvls):
284 reporter.testDone();
285 self.iTestLvl += 1;
286
287 def getTestIdString(self, oCfg, iLvl):
288 """
289 Returns a potentially formatted string for the test name.
290 """
291
292 # The order of the test levels is reversed so get the level starting
293 # from the end.
294 _, fnTestFmt, _ = self.at3TestLvls[len(self.at3TestLvls) - 1 - iLvl];
295 if fnTestFmt is not None:
296 return fnTestFmt(oCfg);
297 return oCfg;
298
299 def isTestCfgBlacklisted(self, asTestCfg):
300 """
301 Returns whether the given test config is black listed.
302 """
303 fBlacklisted = False;
304
305 for asTestBlacklist in self.aasTestsBlacklist:
306 iLvl = 0;
307 fBlacklisted = True;
308 while iLvl < len(asTestBlacklist) and iLvl < len(asTestCfg):
309 if asTestBlacklist[iLvl] != asTestCfg[iLvl] and asTestBlacklist[iLvl] != '*':
310 fBlacklisted = False;
311 break;
312
313 iLvl += 1;
314
315 if not fBlacklisted and self.fnIsCfgSupported is not None:
316 fBlacklisted = not self.fnIsCfgSupported(asTestCfg);
317
318 return fBlacklisted;
319
320 def advanceTestCfg(self):
321 """
322 Advances to the next test config and returns it as an
323 array of strings or an empty config if there is no test left anymore.
324 """
325 iTestCfg, fnTestFmt, asTestCfg = self.at3TestLvls[self.iTestLvl];
326 iTestCfg += 1;
327 self.at3TestLvls[self.iTestLvl] = (iTestCfg, fnTestFmt, asTestCfg);
328 while iTestCfg == len(asTestCfg) and self.iTestLvl < len(self.at3TestLvls):
329 self.at3TestLvls[self.iTestLvl] = (0, fnTestFmt, asTestCfg);
330 self.iTestLvl += 1;
331 if self.iTestLvl < len(self.at3TestLvls):
332 iTestCfg, fnTestFmt, asTestCfg = self.at3TestLvls[self.iTestLvl];
333 iTestCfg += 1;
334 self.at3TestLvls[self.iTestLvl] = (iTestCfg, fnTestFmt, asTestCfg);
335 if iTestCfg < len(asTestCfg):
336 self.iTestLvl = 0;
337 break;
338 else:
339 break; # We reached the end of our tests.
340
341 return self.getCurrentTestCfg();
342
343 def getCurrentTestCfg(self):
344 """
345 Returns the current not black listed test config as an array of strings.
346 """
347 asTestCfg = [];
348
349 if self.iTestLvl < len(self.at3TestLvls):
350 for t3TestLvl in self.at3TestLvls:
351 iTestCfg, _, asTestLvl = t3TestLvl;
352 asTestCfg.append(asTestLvl[iTestCfg]);
353
354 asTestCfg.reverse()
355
356 return asTestCfg;
357
358 def getNextTestCfg(self, fSkippedLast = False):
359 """
360 Returns the next not blacklisted test config or an empty list if
361 there is no test left.
362 """
363 asTestCfgCur = self.getCurrentTestCfg();
364
365 asTestCfg = self.advanceTestCfg();
366 while asTestCfg and self.isTestCfgBlacklisted(asTestCfg):
367 asTestCfg = self.advanceTestCfg();
368
369 # Compare the current and next config and close the approriate test
370 # categories.
371 reporter.testDone(fSkippedLast);
372 if asTestCfg:
373 idxSame = 0;
374 while asTestCfgCur[idxSame] == asTestCfg[idxSame]:
375 idxSame += 1;
376
377 for i in range(idxSame, len(asTestCfg) - 1):
378 reporter.testDone();
379
380 for i in range(idxSame, len(asTestCfg)):
381 reporter.testStart('%s' % (self.getTestIdString(asTestCfg[i], i)));
382
383 else:
384 # No more tests, mark all tests as done
385 for i in range(0, len(asTestCfgCur) - 1):
386 reporter.testDone();
387
388 return asTestCfg;
389
390class tdStorageBenchmark(vbox.TestDriver): # pylint: disable=too-many-instance-attributes
391 """
392 Storage benchmark.
393 """
394
395 # Global storage configs for the testbox
396 kdStorageCfgs = {
397 'testboxstor1.de.oracle.com': r'c[3-9]t\dd0\Z',
398 'adaris': [ '/dev/sda' ]
399 };
400
401 # Available test sets.
402 kdTestSets = {
403 # Mostly for developing and debugging the testcase.
404 'Fast': {
405 'RecordSize': '64k',
406 'TestsetSize': '100m',
407 'QueueDepth': '32',
408 'DiskSizeGb': 2
409 },
410 # For quick functionality tests where benchmark results are not required.
411 'Functionality': {
412 'RecordSize': '64k',
413 'TestsetSize': '2g',
414 'QueueDepth': '32',
415 'DiskSizeGb': 10
416 },
417 # For benchmarking the I/O stack.
418 'Benchmark': {
419 'RecordSize': '64k',
420 'TestsetSize': '20g',
421 'QueueDepth': '32',
422 'DiskSizeGb': 30
423 },
424 # For stress testing which takes a lot of time.
425 'Stress': {
426 'RecordSize': '64k',
427 'TestsetSize': '2t',
428 'QueueDepth': '32',
429 'DiskSizeGb': 10000
430 },
431 };
432
433 # Dictionary mapping the virtualization mode mnemonics to a little less cryptic
434 # strings used in test descriptions.
435 kdVirtModeDescs = {
436 'raw' : 'Raw-mode',
437 'hwvirt' : 'HwVirt',
438 'hwvirt-np' : 'NestedPaging'
439 };
440
441 kdHostIoCacheDescs = {
442 'default' : 'HostCacheDef',
443 'hostiocache' : 'HostCacheOn',
444 'no-hostiocache' : 'HostCacheOff'
445 };
446
447 # Password ID for encryption.
448 ksPwId = 'EncPwId';
449
450 # Array indexes for the test configs.
451 kiVmName = 0;
452 kiStorageCtrl = 1;
453 kiHostIoCache = 2;
454 kiDiskFmt = 3;
455 kiDiskVar = 4;
456 kiCpuCount = 5;
457 kiVirtMode = 6;
458 kiIoTest = 7;
459 kiTestSet = 8;
460
461 def __init__(self):
462 vbox.TestDriver.__init__(self);
463 self.asRsrcs = None;
464 self.asTestVMsDef = ['tst-storage', 'tst-storage32'];
465 self.asTestVMs = self.asTestVMsDef;
466 self.asSkipVMs = [];
467 self.asVirtModesDef = ['hwvirt', 'hwvirt-np', 'raw',]
468 self.asVirtModes = self.asVirtModesDef;
469 self.acCpusDef = [1, 2];
470 self.acCpus = self.acCpusDef;
471 self.asStorageCtrlsDef = ['AHCI', 'IDE', 'LsiLogicSAS', 'LsiLogic', 'BusLogic', 'NVMe'];
472 self.asStorageCtrls = self.asStorageCtrlsDef;
473 self.asHostIoCacheDef = ['default', 'hostiocache', 'no-hostiocache'];
474 self.asHostIoCache = self.asHostIoCacheDef;
475 self.asDiskFormatsDef = ['VDI', 'VMDK', 'VHD', 'QED', 'Parallels', 'QCOW', 'iSCSI'];
476 self.asDiskFormats = self.asDiskFormatsDef;
477 self.asDiskVariantsDef = ['Dynamic', 'Fixed', 'DynamicSplit2G', 'FixedSplit2G', 'Network'];
478 self.asDiskVariants = self.asDiskVariantsDef;
479 self.asTestsDef = ['iozone', 'fio'];
480 self.asTests = self.asTestsDef;
481 self.asTestSetsDef = ['Fast', 'Functionality', 'Benchmark', 'Stress'];
482 self.asTestSets = self.asTestSetsDef;
483 self.asIscsiTargetsDef = [ ]; # @todo: Configure one target for basic iSCSI testing
484 self.asIscsiTargets = self.asIscsiTargetsDef;
485 self.cDiffLvlsDef = 0;
486 self.cDiffLvls = self.cDiffLvlsDef;
487 self.fTestHost = False;
488 self.fUseScratch = False;
489 self.fRecreateStorCfg = True;
490 self.fReportBenchmarkResults = True;
491 self.oStorCfg = None;
492 self.sIoLogPathDef = self.sScratchPath;
493 self.sIoLogPath = self.sIoLogPathDef;
494 self.fIoLog = False;
495 self.fUseRamDiskDef = False;
496 self.fUseRamDisk = self.fUseRamDiskDef;
497 self.fEncryptDiskDef = False;
498 self.fEncryptDisk = self.fEncryptDiskDef;
499 self.sEncryptPwDef = 'TestTestTest';
500 self.sEncryptPw = self.sEncryptPwDef;
501 self.sEncryptAlgoDef = 'AES-XTS256-PLAIN64';
502 self.sEncryptAlgo = self.sEncryptAlgoDef;
503
504 #
505 # Overridden methods.
506 #
507 def showUsage(self):
508 rc = vbox.TestDriver.showUsage(self);
509 reporter.log('');
510 reporter.log('tdStorageBenchmark1 Options:');
511 reporter.log(' --virt-modes <m1[:m2[:]]');
512 reporter.log(' Default: %s' % (':'.join(self.asVirtModesDef)));
513 reporter.log(' --cpu-counts <c1[:c2[:]]');
514 reporter.log(' Default: %s' % (':'.join(str(c) for c in self.acCpusDef)));
515 reporter.log(' --storage-ctrls <type1[:type2[:...]]>');
516 reporter.log(' Default: %s' % (':'.join(self.asStorageCtrlsDef)));
517 reporter.log(' --host-io-cache <setting1[:setting2[:...]]>');
518 reporter.log(' Default: %s' % (':'.join(self.asHostIoCacheDef)));
519 reporter.log(' --disk-formats <type1[:type2[:...]]>');
520 reporter.log(' Default: %s' % (':'.join(self.asDiskFormatsDef)));
521 reporter.log(' --disk-variants <variant1[:variant2[:...]]>');
522 reporter.log(' Default: %s' % (':'.join(self.asDiskVariantsDef)));
523 reporter.log(' --iscsi-targets <target1[:target2[:...]]>');
524 reporter.log(' Default: %s' % (':'.join(self.asIscsiTargetsDef)));
525 reporter.log(' --tests <test1[:test2[:...]]>');
526 reporter.log(' Default: %s' % (':'.join(self.asTestsDef)));
527 reporter.log(' --test-sets <set1[:set2[:...]]>');
528 reporter.log(' Default: %s' % (':'.join(self.asTestSetsDef)));
529 reporter.log(' --diff-levels <number of diffs>');
530 reporter.log(' Default: %s' % (self.cDiffLvlsDef));
531 reporter.log(' --test-vms <vm1[:vm2[:...]]>');
532 reporter.log(' Test the specified VMs in the given order. Use this to change');
533 reporter.log(' the execution order or limit the choice of VMs');
534 reporter.log(' Default: %s (all)' % (':'.join(self.asTestVMsDef)));
535 reporter.log(' --skip-vms <vm1[:vm2[:...]]>');
536 reporter.log(' Skip the specified VMs when testing.');
537 reporter.log(' --test-host');
538 reporter.log(' Do all configured tests on the host first and report the results');
539 reporter.log(' to get a baseline');
540 reporter.log(' --use-scratch');
541 reporter.log(' Use the scratch directory for testing instead of setting up');
542 reporter.log(' fresh volumes on dedicated disks (for development)');
543 reporter.log(' --always-wipe-storage-cfg');
544 reporter.log(' Recreate the host storage config before each test');
545 reporter.log(' --dont-wipe-storage-cfg');
546 reporter.log(' Don\'t recreate the host storage config before each test');
547 reporter.log(' --report-benchmark-results');
548 reporter.log(' Report all benchmark results');
549 reporter.log(' --dont-report-benchmark-results');
550 reporter.log(' Don\'t report any benchmark results');
551 reporter.log(' --io-log-path <path>');
552 reporter.log(' Default: %s' % (self.sIoLogPathDef));
553 reporter.log(' --enable-io-log');
554 reporter.log(' Whether to enable I/O logging for each test');
555 reporter.log(' --use-ramdisk');
556 reporter.log(' Default: %s' % (self.fUseRamDiskDef));
557 reporter.log(' --encrypt-disk');
558 reporter.log(' Default: %s' % (self.fEncryptDiskDef));
559 reporter.log(' --encrypt-password');
560 reporter.log(' Default: %s' % (self.sEncryptPwDef));
561 reporter.log(' --encrypt-algorithm');
562 reporter.log(' Default: %s' % (self.sEncryptAlgoDef));
563 return rc;
564
565 def parseOption(self, asArgs, iArg): # pylint: disable=too-many-branches,too-many-statements
566 if asArgs[iArg] == '--virt-modes':
567 iArg += 1;
568 if iArg >= len(asArgs): raise base.InvalidOption('The "--virt-modes" takes a colon separated list of modes');
569 self.asVirtModes = asArgs[iArg].split(':');
570 for s in self.asVirtModes:
571 if s not in self.asVirtModesDef:
572 raise base.InvalidOption('The "--virt-modes" value "%s" is not valid; valid values are: %s' \
573 % (s, ' '.join(self.asVirtModesDef)));
574 elif asArgs[iArg] == '--cpu-counts':
575 iArg += 1;
576 if iArg >= len(asArgs): raise base.InvalidOption('The "--cpu-counts" takes a colon separated list of cpu counts');
577 self.acCpus = [];
578 for s in asArgs[iArg].split(':'):
579 try: c = int(s);
580 except: raise base.InvalidOption('The "--cpu-counts" value "%s" is not an integer' % (s,));
581 if c <= 0: raise base.InvalidOption('The "--cpu-counts" value "%s" is zero or negative' % (s,));
582 self.acCpus.append(c);
583 elif asArgs[iArg] == '--storage-ctrls':
584 iArg += 1;
585 if iArg >= len(asArgs):
586 raise base.InvalidOption('The "--storage-ctrls" takes a colon separated list of Storage controller types');
587 self.asStorageCtrls = asArgs[iArg].split(':');
588 elif asArgs[iArg] == '--host-io-cache':
589 iArg += 1;
590 if iArg >= len(asArgs):
591 raise base.InvalidOption('The "--host-io-cache" takes a colon separated list of I/O cache settings');
592 self.asHostIoCache = asArgs[iArg].split(':');
593 elif asArgs[iArg] == '--disk-formats':
594 iArg += 1;
595 if iArg >= len(asArgs): raise base.InvalidOption('The "--disk-formats" takes a colon separated list of disk formats');
596 self.asDiskFormats = asArgs[iArg].split(':');
597 elif asArgs[iArg] == '--disk-variants':
598 iArg += 1;
599 if iArg >= len(asArgs):
600 raise base.InvalidOption('The "--disk-variants" takes a colon separated list of disk variants');
601 self.asDiskVariants = asArgs[iArg].split(':');
602 elif asArgs[iArg] == '--iscsi-targets':
603 iArg += 1;
604 if iArg >= len(asArgs):
605 raise base.InvalidOption('The "--iscsi-targets" takes a colon separated list of iscsi targets');
606 self.asIscsiTargets = asArgs[iArg].split(':');
607 elif asArgs[iArg] == '--tests':
608 iArg += 1;
609 if iArg >= len(asArgs): raise base.InvalidOption('The "--tests" takes a colon separated list of tests to run');
610 self.asTests = asArgs[iArg].split(':');
611 elif asArgs[iArg] == '--test-sets':
612 iArg += 1;
613 if iArg >= len(asArgs): raise base.InvalidOption('The "--test-sets" takes a colon separated list of test sets');
614 self.asTestSets = asArgs[iArg].split(':');
615 elif asArgs[iArg] == '--diff-levels':
616 iArg += 1;
617 if iArg >= len(asArgs): raise base.InvalidOption('The "--diff-levels" takes an integer');
618 try: self.cDiffLvls = int(asArgs[iArg]);
619 except: raise base.InvalidOption('The "--diff-levels" value "%s" is not an integer' % (asArgs[iArg],));
620 elif asArgs[iArg] == '--test-vms':
621 iArg += 1;
622 if iArg >= len(asArgs): raise base.InvalidOption('The "--test-vms" takes colon separated list');
623 self.asTestVMs = asArgs[iArg].split(':');
624 for s in self.asTestVMs:
625 if s not in self.asTestVMsDef:
626 raise base.InvalidOption('The "--test-vms" value "%s" is not valid; valid values are: %s' \
627 % (s, ' '.join(self.asTestVMsDef)));
628 elif asArgs[iArg] == '--skip-vms':
629 iArg += 1;
630 if iArg >= len(asArgs): raise base.InvalidOption('The "--skip-vms" takes colon separated list');
631 self.asSkipVMs = asArgs[iArg].split(':');
632 for s in self.asSkipVMs:
633 if s not in self.asTestVMsDef:
634 reporter.log('warning: The "--test-vms" value "%s" does not specify any of our test VMs.' % (s));
635 elif asArgs[iArg] == '--test-host':
636 self.fTestHost = True;
637 elif asArgs[iArg] == '--use-scratch':
638 self.fUseScratch = True;
639 elif asArgs[iArg] == '--always-wipe-storage-cfg':
640 self.fRecreateStorCfg = True;
641 elif asArgs[iArg] == '--dont-wipe-storage-cfg':
642 self.fRecreateStorCfg = False;
643 elif asArgs[iArg] == '--report-benchmark-results':
644 self.fReportBenchmarkResults = True;
645 elif asArgs[iArg] == '--dont-report-benchmark-results':
646 self.fReportBenchmarkResults = False;
647 elif asArgs[iArg] == '--io-log-path':
648 iArg += 1;
649 if iArg >= len(asArgs): raise base.InvalidOption('The "--io-log-path" takes a path argument');
650 self.sIoLogPath = asArgs[iArg];
651 elif asArgs[iArg] == '--enable-io-log':
652 self.fIoLog = True;
653 elif asArgs[iArg] == '--use-ramdisk':
654 self.fUseRamDisk = True;
655 elif asArgs[iArg] == '--encrypt-disk':
656 self.fEncryptDisk = True;
657 elif asArgs[iArg] == '--encrypt-password':
658 iArg += 1;
659 if iArg >= len(asArgs): raise base.InvalidOption('The "--encrypt-password" takes a string');
660 self.sEncryptPw = asArgs[iArg];
661 elif asArgs[iArg] == '--encrypt-algorithm':
662 iArg += 1;
663 if iArg >= len(asArgs): raise base.InvalidOption('The "--encrypt-algorithm" takes a string');
664 self.sEncryptAlgo = asArgs[iArg];
665 else:
666 return vbox.TestDriver.parseOption(self, asArgs, iArg);
667 return iArg + 1;
668
669 def completeOptions(self):
670 # Remove skipped VMs from the test list.
671 for sVM in self.asSkipVMs:
672 try: self.asTestVMs.remove(sVM);
673 except: pass;
674
675 return vbox.TestDriver.completeOptions(self);
676
677 def getResourceSet(self):
678 # Construct the resource list the first time it's queried.
679 if self.asRsrcs is None:
680 self.asRsrcs = [];
681 if 'tst-storage' in self.asTestVMs:
682 self.asRsrcs.append('5.0/storage/tst-storage.vdi');
683 if 'tst-storage32' in self.asTestVMs:
684 self.asRsrcs.append('5.0/storage/tst-storage32.vdi');
685
686 return self.asRsrcs;
687
688 def actionConfig(self):
689
690 # Make sure vboxapi has been imported so we can use the constants.
691 if not self.importVBoxApi():
692 return False;
693
694 #
695 # Configure the VMs we're going to use.
696 #
697
698 # Linux VMs
699 if 'tst-storage' in self.asTestVMs:
700 oVM = self.createTestVM('tst-storage', 1, '5.0/storage/tst-storage.vdi', sKind = 'ArchLinux_64', fIoApic = True, \
701 eNic0AttachType = vboxcon.NetworkAttachmentType_NAT, \
702 eNic0Type = vboxcon.NetworkAdapterType_Am79C973);
703 if oVM is None:
704 return False;
705
706 if 'tst-storage32' in self.asTestVMs:
707 oVM = self.createTestVM('tst-storage32', 1, '5.0/storage/tst-storage32.vdi', sKind = 'ArchLinux', fIoApic = True, \
708 eNic0AttachType = vboxcon.NetworkAttachmentType_NAT, \
709 eNic0Type = vboxcon.NetworkAdapterType_Am79C973);
710 if oVM is None:
711 return False;
712
713 return True;
714
715 def actionExecute(self):
716 """
717 Execute the testcase.
718 """
719 fRc = self.test1();
720 return fRc;
721
722
723 #
724 # Test execution helpers.
725 #
726
727 def prepareStorage(self, oStorCfg, fRamDisk = False, cbPool = None):
728 """
729 Prepares the host storage for disk images or direct testing on the host.
730 """
731 # Create a basic pool with the default configuration.
732 sMountPoint = None;
733 fRc, sPoolId = oStorCfg.createStoragePool(cbPool = cbPool, fRamDisk = fRamDisk);
734 if fRc:
735 fRc, sMountPoint = oStorCfg.createVolume(sPoolId);
736 if not fRc:
737 sMountPoint = None;
738 oStorCfg.cleanup();
739
740 return sMountPoint;
741
742 def cleanupStorage(self, oStorCfg):
743 """
744 Cleans up any created storage space for a test.
745 """
746 return oStorCfg.cleanup();
747
748 def getGuestDisk(self, oSession, oTxsSession, eStorageController):
749 """
750 Gets the path of the disk in the guest to use for testing.
751 """
752 lstDisks = None;
753
754 # The naming scheme for NVMe is different and we don't have
755 # to query the guest for unformatted disks here because the disk with the OS
756 # is not attached to a NVMe controller.
757 if eStorageController == vboxcon.StorageControllerType_NVMe:
758 lstDisks = [ '/dev/nvme0n1' ];
759 else:
760 # Find a unformatted disk (no partition).
761 # @todo: This is a hack because LIST and STAT are not yet implemented
762 # in TXS (get to this eventually)
763 lstBlkDev = [ '/dev/sda', '/dev/sdb' ];
764 for sBlkDev in lstBlkDev:
765 fRc = oTxsSession.syncExec('/usr/bin/ls', ('ls', sBlkDev + '1'));
766 if not fRc:
767 lstDisks = [ sBlkDev ];
768 break;
769
770 _ = oSession;
771 return lstDisks;
772
773 def getDiskFormatVariantsForTesting(self, sDiskFmt, asVariants):
774 """
775 Returns a list of disk variants for testing supported by the given
776 disk format and selected for testing.
777 """
778 lstDskFmts = self.oVBoxMgr.getArray(self.oVBox.systemProperties, 'mediumFormats');
779 for oDskFmt in lstDskFmts:
780 if oDskFmt.id == sDiskFmt:
781 lstDskVariants = [];
782 lstCaps = self.oVBoxMgr.getArray(oDskFmt, 'capabilities');
783
784 if vboxcon.MediumFormatCapabilities_CreateDynamic in lstCaps \
785 and 'Dynamic' in asVariants:
786 lstDskVariants.append('Dynamic');
787
788 if vboxcon.MediumFormatCapabilities_CreateFixed in lstCaps \
789 and 'Fixed' in asVariants:
790 lstDskVariants.append('Fixed');
791
792 if vboxcon.MediumFormatCapabilities_CreateSplit2G in lstCaps \
793 and vboxcon.MediumFormatCapabilities_CreateDynamic in lstCaps \
794 and 'DynamicSplit2G' in asVariants:
795 lstDskVariants.append('DynamicSplit2G');
796
797 if vboxcon.MediumFormatCapabilities_CreateSplit2G in lstCaps \
798 and vboxcon.MediumFormatCapabilities_CreateFixed in lstCaps \
799 and 'FixedSplit2G' in asVariants:
800 lstDskVariants.append('FixedSplit2G');
801
802 if vboxcon.MediumFormatCapabilities_TcpNetworking in lstCaps \
803 and 'Network' in asVariants:
804 lstDskVariants.append('Network'); # Solely for iSCSI to get a non empty list
805
806 return lstDskVariants;
807
808 return [];
809
810 def convDiskToMediumVariant(self, sDiskVariant):
811 """
812 Returns a tuple of medium variant flags matching the given disk variant.
813 """
814 tMediumVariant = None;
815 if sDiskVariant == 'Dynamic':
816 tMediumVariant = (vboxcon.MediumVariant_Standard, );
817 elif sDiskVariant == 'Fixed':
818 tMediumVariant = (vboxcon.MediumVariant_Fixed, );
819 elif sDiskVariant == 'DynamicSplit2G':
820 tMediumVariant = (vboxcon.MediumVariant_Standard, vboxcon.MediumVariant_VmdkSplit2G);
821 elif sDiskVariant == 'FixedSplit2G':
822 tMediumVariant = (vboxcon.MediumVariant_Fixed, vboxcon.MediumVariant_VmdkSplit2G);
823
824 return tMediumVariant;
825
826 def getStorageCtrlFromName(self, sStorageCtrl):
827 """
828 Resolves the storage controller string to the matching constant.
829 """
830 eStorageCtrl = None;
831
832 if sStorageCtrl == 'AHCI':
833 eStorageCtrl = vboxcon.StorageControllerType_IntelAhci;
834 elif sStorageCtrl == 'IDE':
835 eStorageCtrl = vboxcon.StorageControllerType_PIIX4;
836 elif sStorageCtrl == 'LsiLogicSAS':
837 eStorageCtrl = vboxcon.StorageControllerType_LsiLogicSas;
838 elif sStorageCtrl == 'LsiLogic':
839 eStorageCtrl = vboxcon.StorageControllerType_LsiLogic;
840 elif sStorageCtrl == 'BusLogic':
841 eStorageCtrl = vboxcon.StorageControllerType_BusLogic;
842 elif sStorageCtrl == 'NVMe':
843 eStorageCtrl = vboxcon.StorageControllerType_NVMe;
844
845 return eStorageCtrl;
846
847 def getStorageDriverFromEnum(self, eStorageCtrl, fHardDisk):
848 """
849 Returns the appropriate driver name for the given storage controller
850 and a flag whether the driver has the generic SCSI driver attached.
851 """
852 if eStorageCtrl == vboxcon.StorageControllerType_IntelAhci:
853 if fHardDisk:
854 return ('ahci', False);
855 return ('ahci', True);
856 if eStorageCtrl == vboxcon.StorageControllerType_PIIX4:
857 return ('piix3ide', False);
858 if eStorageCtrl == vboxcon.StorageControllerType_LsiLogicSas:
859 return ('lsilogicsas', True);
860 if eStorageCtrl == vboxcon.StorageControllerType_LsiLogic:
861 return ('lsilogicscsi', True);
862 if eStorageCtrl == vboxcon.StorageControllerType_BusLogic:
863 return ('buslogic', True);
864 if eStorageCtrl == vboxcon.StorageControllerType_NVMe:
865 return ('nvme', False);
866
867 return ('<invalid>', False);
868
869 def isTestCfgSupported(self, asTestCfg):
870 """
871 Returns whether a specific test config is supported.
872 """
873
874 # Check whether the disk variant is supported by the selected format.
875 asVariants = self.getDiskFormatVariantsForTesting(asTestCfg[self.kiDiskFmt], [ asTestCfg[self.kiDiskVar] ]);
876 if not asVariants:
877 return False;
878
879 # For iSCSI check whether we have targets configured.
880 if asTestCfg[self.kiDiskFmt] == 'iSCSI' and not self.asIscsiTargets:
881 return False;
882
883 # Check for virt mode, CPU count and selected VM.
884 if asTestCfg[self.kiVirtMode] == 'raw' \
885 and (asTestCfg[self.kiCpuCount] > 1 or asTestCfg[self.kiVmName] == 'tst-storage'):
886 return False;
887
888 # IDE does not support the no host I/O cache setting
889 if asTestCfg[self.kiHostIoCache] == 'no-hostiocache' \
890 and asTestCfg[self.kiStorageCtrl] == 'IDE':
891 return False;
892
893 return True;
894
895 def fnFormatCpuString(self, cCpus):
896 """
897 Formats the CPU count to be readable.
898 """
899 if cCpus == 1:
900 return '1 cpu';
901 return '%u cpus' % (cCpus);
902
903 def fnFormatVirtMode(self, sVirtMode):
904 """
905 Formats the virtualization mode to be a little less cryptic for use in test
906 descriptions.
907 """
908 return self.kdVirtModeDescs[sVirtMode];
909
910 def fnFormatHostIoCache(self, sHostIoCache):
911 """
912 Formats the host I/O cache mode to be a little less cryptic for use in test
913 descriptions.
914 """
915 return self.kdHostIoCacheDescs[sHostIoCache];
916
917 def testBenchmark(self, sTargetOs, sBenchmark, sMountpoint, oExecutor, dTestSet, \
918 cMsTimeout = 3600000):
919 """
920 Runs the given benchmark on the test host.
921 """
922
923 dTestSet['FilePath'] = sMountpoint;
924 dTestSet['TargetOs'] = sTargetOs;
925
926 oTst = None;
927 if sBenchmark == 'iozone':
928 oTst = IozoneTest(oExecutor, dTestSet);
929 elif sBenchmark == 'fio':
930 oTst = FioTest(oExecutor, dTestSet); # pylint: disable=redefined-variable-type
931
932 if oTst is not None:
933 fRc = oTst.prepare();
934 if fRc:
935 fRc = oTst.run(cMsTimeout);
936 if fRc:
937 if self.fReportBenchmarkResults:
938 fRc = oTst.reportResult();
939 else:
940 reporter.testFailure('Running the testcase failed');
941 reporter.addLogString(oTst.getErrorReport(), sBenchmark + '.log',
942 'log/release/client', 'Benchmark raw output');
943 else:
944 reporter.testFailure('Preparing the testcase failed');
945
946 oTst.cleanup();
947
948 return fRc;
949
950 def createHd(self, oSession, sDiskFormat, sDiskVariant, iDiffLvl, oHdParent, \
951 sDiskPath, cbDisk):
952 """
953 Creates a new disk with the given parameters returning the medium object
954 on success.
955 """
956
957 oHd = None;
958 if sDiskFormat == "iSCSI" and iDiffLvl == 0:
959 listNames = [];
960 listValues = [];
961 listValues = self.asIscsiTargets[0].split('|');
962 listNames.append('TargetAddress');
963 listNames.append('TargetName');
964 listNames.append('LUN');
965
966 if self.fpApiVer >= 5.0:
967 oHd = oSession.oVBox.createMedium(sDiskFormat, sDiskPath, vboxcon.AccessMode_ReadWrite, \
968 vboxcon.DeviceType_HardDisk);
969 else:
970 oHd = oSession.oVBox.createHardDisk(sDiskFormat, sDiskPath);
971 oHd.type = vboxcon.MediumType_Normal;
972 oHd.setProperties(listNames, listValues);
973 else:
974 if iDiffLvl == 0:
975 tMediumVariant = self.convDiskToMediumVariant(sDiskVariant);
976 oHd = oSession.createBaseHd(sDiskPath + '/base.disk', sDiskFormat, cbDisk, \
977 cMsTimeout = 3600 * 1000, tMediumVariant = tMediumVariant);
978 else:
979 sDiskPath = sDiskPath + '/diff_%u.disk' % (iDiffLvl);
980 oHd = oSession.createDiffHd(oHdParent, sDiskPath, None);
981
982 if oHd is not None and iDiffLvl == 0 and self.fEncryptDisk:
983 try:
984 oIProgress = oHd.changeEncryption('', self.sEncryptAlgo, self.sEncryptPw, self.ksPwId);
985 oProgress = vboxwrappers.ProgressWrapper(oIProgress, self.oVBoxMgr, self, 'Encrypting "%s"' % (sDiskPath,));
986 oProgress.wait(60*60000); # Wait for up to one hour, fixed disks take longer to encrypt.
987 if oProgress.logResult() is False:
988 raise base.GenError('Encrypting disk "%s" failed' % (sDiskPath, ));
989 except:
990 reporter.errorXcpt('changeEncryption("%s","%s","%s") failed on "%s"' \
991 % ('', self.sEncryptAlgo, self.sEncryptPw, oSession.sName) );
992 self.oVBox.deleteHdByMedium(oHd);
993 oHd = None;
994 else:
995 reporter.log('Encrypted "%s"' % (sDiskPath,));
996
997 return oHd;
998
999 def startVmAndConnect(self, sVmName):
1000 """
1001 Our own implementation of startVmAndConnectToTxsViaTcp to make it possible
1002 to add passwords to a running VM when encryption is used.
1003 """
1004 oSession = self.startVmByName(sVmName);
1005 if oSession is not None:
1006 # Add password to the session in case encryption is used.
1007 fRc = True;
1008 if self.fEncryptDisk:
1009 try:
1010 oSession.o.console.addDiskEncryptionPassword(self.ksPwId, self.sEncryptPw, False);
1011 except:
1012 reporter.logXcpt();
1013 fRc = False;
1014
1015 # Connect to TXS.
1016 if fRc:
1017 reporter.log2('startVmAndConnect: Started(/prepared) "%s", connecting to TXS ...' % (sVmName,));
1018 (fRc, oTxsSession) = self.txsDoConnectViaTcp(oSession, 15*60000, fNatForwardingForTxs = True);
1019 if fRc is True:
1020 if fRc is True:
1021 # Success!
1022 return (oSession, oTxsSession);
1023 else:
1024 reporter.error('startVmAndConnect: txsDoConnectViaTcp failed');
1025 # If something went wrong while waiting for TXS to be started - take VM screenshot before terminate it
1026
1027 self.terminateVmBySession(oSession);
1028
1029 return (None, None);
1030
1031 def testOneCfg(self, sVmName, eStorageController, sHostIoCache, sDiskFormat, # pylint: disable=too-many-arguments,too-many-locals,too-many-statements
1032 sDiskVariant, sDiskPath, cCpus, sIoTest, sVirtMode, sTestSet):
1033 """
1034 Runs the specified VM thru test #1.
1035
1036 Returns a success indicator on the general test execution. This is not
1037 the actual test result.
1038 """
1039 oVM = self.getVmByName(sVmName);
1040
1041 dTestSet = self.kdTestSets.get(sTestSet);
1042 cbDisk = dTestSet.get('DiskSizeGb') * 1024*1024*1024;
1043 fHwVirt = sVirtMode != 'raw';
1044 fNestedPaging = sVirtMode == 'hwvirt-np';
1045
1046 fRc = True;
1047 if sDiskFormat == 'iSCSI':
1048 sDiskPath = self.asIscsiTargets[0];
1049 elif self.fUseScratch:
1050 sDiskPath = self.sScratchPath;
1051 else:
1052 # If requested recreate the storage space to start with a clean config
1053 # for benchmarks
1054 if self.fRecreateStorCfg:
1055 sMountPoint = self.prepareStorage(self.oStorCfg, self.fUseRamDisk, 2 * cbDisk);
1056 if sMountPoint is not None:
1057 # Create a directory where every normal user can write to.
1058 self.oStorCfg.mkDirOnVolume(sMountPoint, 'test', 0o777);
1059 sDiskPath = sMountPoint + '/test';
1060 else:
1061 fRc = False;
1062 reporter.testFailure('Failed to prepare storage for VM');
1063
1064 if not fRc:
1065 return fRc;
1066
1067 lstDisks = []; # List of disks we have to delete afterwards.
1068
1069 for iDiffLvl in range(self.cDiffLvls + 1):
1070 sIoLogFile = None;
1071
1072 if iDiffLvl == 0:
1073 reporter.testStart('Base');
1074 else:
1075 reporter.testStart('Diff %u' % (iDiffLvl));
1076
1077 # Reconfigure the VM
1078 oSession = self.openSession(oVM);
1079 if oSession is not None:
1080 #
1081 # Disable audio controller which shares the interrupt line with the BusLogic controller and is suspected to cause
1082 # rare test failures because the device initialization fails.
1083 #
1084 fRc = oSession.setupAudio(vboxcon.AudioControllerType_AC97, False);
1085 # Attach HD
1086 fRc = fRc and oSession.ensureControllerAttached(self.controllerTypeToName(eStorageController));
1087 fRc = fRc and oSession.setStorageControllerType(eStorageController,
1088 self.controllerTypeToName(eStorageController));
1089
1090 if sHostIoCache == 'hostiocache':
1091 fRc = fRc and oSession.setStorageControllerHostIoCache(self.controllerTypeToName(eStorageController), True);
1092 elif sHostIoCache == 'no-hostiocache':
1093 fRc = fRc and oSession.setStorageControllerHostIoCache(self.controllerTypeToName(eStorageController), False);
1094
1095 iDevice = 0;
1096 if eStorageController in (vboxcon.StorageControllerType_PIIX3, vboxcon.StorageControllerType_PIIX4,):
1097 iDevice = 1; # Master is for the OS.
1098
1099 oHdParent = None;
1100 if iDiffLvl > 0:
1101 oHdParent = lstDisks[0];
1102 oHd = self.createHd(oSession, sDiskFormat, sDiskVariant, iDiffLvl, oHdParent, sDiskPath, cbDisk);
1103 if oHd is not None:
1104 lstDisks.insert(0, oHd);
1105 try:
1106 if oSession.fpApiVer >= 4.0:
1107 oSession.o.machine.attachDevice(self.controllerTypeToName(eStorageController),
1108 0, iDevice, vboxcon.DeviceType_HardDisk, oHd);
1109 else:
1110 oSession.o.machine.attachDevice(self.controllerTypeToName(eStorageController),
1111 0, iDevice, vboxcon.DeviceType_HardDisk, oHd.id);
1112 except:
1113 reporter.errorXcpt('attachDevice("%s",%s,%s,HardDisk,"%s") failed on "%s"' \
1114 % (self.controllerTypeToName(eStorageController), 1, 0, oHd.id, oSession.sName) );
1115 fRc = False;
1116 else:
1117 reporter.log('attached "%s" to %s' % (sDiskPath, oSession.sName));
1118 else:
1119 fRc = False;
1120
1121 # Set up the I/O logging config if enabled
1122 if fRc and self.fIoLog:
1123 try:
1124 oSession.o.machine.setExtraData('VBoxInternal2/EnableDiskIntegrityDriver', '1');
1125
1126 iLun = 0;
1127 if eStorageController in (vboxcon.StorageControllerType_PIIX3, vboxcon.StorageControllerType_PIIX4,):
1128 iLun = 1
1129 sDrv, fDrvScsi = self.getStorageDriverFromEnum(eStorageController, True);
1130 if fDrvScsi:
1131 sCfgmPath = 'VBoxInternal/Devices/%s/0/LUN#%u/AttachedDriver/Config' % (sDrv, iLun);
1132 else:
1133 sCfgmPath = 'VBoxInternal/Devices/%s/0/LUN#%u/Config' % (sDrv, iLun);
1134
1135 sIoLogFile = '%s/%s.iolog' % (self.sIoLogPath, sDrv);
1136 print(sCfgmPath);
1137 print(sIoLogFile);
1138 oSession.o.machine.setExtraData('%s/IoLog' % (sCfgmPath,), sIoLogFile);
1139 except:
1140 reporter.logXcpt();
1141
1142 fRc = fRc and oSession.enableVirtEx(fHwVirt);
1143 fRc = fRc and oSession.enableNestedPaging(fNestedPaging);
1144 fRc = fRc and oSession.setCpuCount(cCpus);
1145 fRc = fRc and oSession.saveSettings();
1146 fRc = oSession.close() and fRc and True; # pychecker hack.
1147 oSession = None;
1148 else:
1149 fRc = False;
1150
1151 # Start up.
1152 if fRc is True:
1153 self.logVmInfo(oVM);
1154 oSession, oTxsSession = self.startVmAndConnect(sVmName);
1155 if oSession is not None:
1156 self.addTask(oTxsSession);
1157
1158 # Fudge factor - Allow the guest to finish starting up.
1159 self.sleep(5);
1160
1161 # Prepare the storage on the guest
1162 lstBinaryPaths = ['/bin', '/sbin', '/usr/bin', '/usr/sbin' ];
1163 oExecVm = remoteexecutor.RemoteExecutor(oTxsSession, lstBinaryPaths, '${SCRATCH}');
1164 oStorCfgVm = storagecfg.StorageCfg(oExecVm, 'linux', self.getGuestDisk(oSession, oTxsSession, \
1165 eStorageController));
1166
1167 iTry = 0;
1168 while iTry < 3:
1169 sMountPoint = self.prepareStorage(oStorCfgVm);
1170 if sMountPoint is not None:
1171 reporter.log('Prepared storage on %s try' % (iTry + 1,));
1172 break;
1173 else:
1174 iTry = iTry + 1;
1175 self.sleep(5);
1176
1177 if sMountPoint is not None:
1178 self.testBenchmark('linux', sIoTest, sMountPoint, oExecVm, dTestSet, \
1179 cMsTimeout = 3 * 3600 * 1000); # 3 hours max (Benchmark and QED takes a lot of time)
1180 self.cleanupStorage(oStorCfgVm);
1181 else:
1182 reporter.testFailure('Failed to prepare storage for the guest benchmark');
1183
1184 # cleanup.
1185 self.removeTask(oTxsSession);
1186 self.terminateVmBySession(oSession);
1187
1188 # Add the I/O log if it exists and the test failed
1189 if reporter.testErrorCount() > 0 \
1190 and sIoLogFile is not None \
1191 and os.path.exists(sIoLogFile):
1192 reporter.addLogFile(sIoLogFile, 'misc/other', 'I/O log');
1193 os.remove(sIoLogFile);
1194
1195 else:
1196 fRc = False;
1197
1198 # Remove disk
1199 oSession = self.openSession(oVM);
1200 if oSession is not None:
1201 try:
1202 oSession.o.machine.detachDevice(self.controllerTypeToName(eStorageController), 0, iDevice);
1203
1204 # Remove storage controller if it is not an IDE controller.
1205 if eStorageController not in (vboxcon.StorageControllerType_PIIX3, vboxcon.StorageControllerType_PIIX4,):
1206 oSession.o.machine.removeStorageController(self.controllerTypeToName(eStorageController));
1207
1208 oSession.saveSettings();
1209 oSession.saveSettings();
1210 oSession.close();
1211 oSession = None;
1212 except:
1213 reporter.errorXcpt('failed to detach/delete disk %s from storage controller' % (sDiskPath));
1214 else:
1215 fRc = False;
1216
1217 reporter.testDone();
1218
1219 # Delete all disks
1220 for oHd in lstDisks:
1221 self.oVBox.deleteHdByMedium(oHd);
1222
1223 # Cleanup storage area
1224 if sDiskFormat != 'iSCSI' and not self.fUseScratch and self.fRecreateStorCfg:
1225 self.cleanupStorage(self.oStorCfg);
1226
1227 return fRc;
1228
1229 def testStorage(self, sDiskPath = None):
1230 """
1231 Runs the storage testcase through the selected configurations
1232 """
1233
1234 aasTestCfgs = [];
1235 aasTestCfgs.insert(self.kiVmName, self.asTestVMs);
1236 aasTestCfgs.insert(self.kiStorageCtrl, self.asStorageCtrls);
1237 aasTestCfgs.insert(self.kiHostIoCache, (self.asHostIoCache, self.fnFormatHostIoCache));
1238 aasTestCfgs.insert(self.kiDiskFmt, self.asDiskFormats);
1239 aasTestCfgs.insert(self.kiDiskVar, self.asDiskVariants);
1240 aasTestCfgs.insert(self.kiCpuCount, (self.acCpus, self.fnFormatCpuString));
1241 aasTestCfgs.insert(self.kiVirtMode, (self.asVirtModes, self.fnFormatVirtMode));
1242 aasTestCfgs.insert(self.kiIoTest, self.asTests);
1243 aasTestCfgs.insert(self.kiTestSet, self.asTestSets);
1244
1245 aasTestsBlacklist = [];
1246 aasTestsBlacklist.append(['tst-storage', 'BusLogic']); # 64bit Linux is broken with BusLogic
1247
1248 oTstCfgMgr = StorTestCfgMgr(aasTestCfgs, aasTestsBlacklist, self.isTestCfgSupported);
1249
1250 fRc = True;
1251 asTestCfg = oTstCfgMgr.getCurrentTestCfg();
1252 while asTestCfg:
1253 fRc = self.testOneCfg(asTestCfg[self.kiVmName], self.getStorageCtrlFromName(asTestCfg[self.kiStorageCtrl]), \
1254 asTestCfg[self.kiHostIoCache], asTestCfg[self.kiDiskFmt], asTestCfg[self.kiDiskVar],
1255 sDiskPath, asTestCfg[self.kiCpuCount], asTestCfg[self.kiIoTest], \
1256 asTestCfg[self.kiVirtMode], asTestCfg[self.kiTestSet]) and fRc and True; # pychecker hack.
1257
1258 asTestCfg = oTstCfgMgr.getNextTestCfg();
1259
1260 return fRc;
1261
1262 def test1(self):
1263 """
1264 Executes test #1.
1265 """
1266
1267 fRc = True;
1268 oDiskCfg = self.kdStorageCfgs.get(socket.gethostname().lower());
1269
1270 # Test the host first if requested
1271 if oDiskCfg is not None or self.fUseScratch:
1272 lstBinaryPaths = ['/bin', '/sbin', '/usr/bin', '/usr/sbin', \
1273 '/opt/csw/bin', '/usr/ccs/bin', '/usr/sfw/bin'];
1274 oExecutor = remoteexecutor.RemoteExecutor(None, lstBinaryPaths, self.sScratchPath);
1275 if not self.fUseScratch:
1276 self.oStorCfg = storagecfg.StorageCfg(oExecutor, utils.getHostOs(), oDiskCfg);
1277
1278 # Try to cleanup any leftovers from a previous run first.
1279 fRc = self.oStorCfg.cleanupLeftovers();
1280 if not fRc:
1281 reporter.error('Failed to cleanup any leftovers from a previous run');
1282
1283 if self.fTestHost:
1284 reporter.testStart('Host');
1285 if self.fUseScratch:
1286 sMountPoint = self.sScratchPath;
1287 else:
1288 sMountPoint = self.prepareStorage(self.oStorCfg);
1289 if sMountPoint is not None:
1290 for sIoTest in self.asTests:
1291 reporter.testStart(sIoTest);
1292 for sTestSet in self.asTestSets:
1293 reporter.testStart(sTestSet);
1294 dTestSet = self.kdTestSets.get(sTestSet);
1295 self.testBenchmark(utils.getHostOs(), sIoTest, sMountPoint, oExecutor, dTestSet);
1296 reporter.testDone();
1297 reporter.testDone();
1298 self.cleanupStorage(self.oStorCfg);
1299 else:
1300 reporter.testFailure('Failed to prepare host storage');
1301 fRc = False;
1302 reporter.testDone();
1303 else:
1304 # Create the storage space first if it is not done before every test.
1305 sMountPoint = None;
1306 if self.fUseScratch:
1307 sMountPoint = self.sScratchPath;
1308 elif not self.fRecreateStorCfg:
1309 reporter.testStart('Create host storage');
1310 sMountPoint = self.prepareStorage(self.oStorCfg);
1311 if sMountPoint is None:
1312 reporter.testFailure('Failed to prepare host storage');
1313 fRc = False;
1314 self.oStorCfg.mkDirOnVolume(sMountPoint, 'test', 0o777);
1315 sMountPoint = sMountPoint + '/test';
1316 reporter.testDone();
1317
1318 if fRc:
1319 # Run the storage tests.
1320 if not self.testStorage(sMountPoint):
1321 fRc = False;
1322
1323 if not self.fRecreateStorCfg and not self.fUseScratch:
1324 self.cleanupStorage(self.oStorCfg);
1325 else:
1326 fRc = False;
1327
1328 return fRc;
1329
1330if __name__ == '__main__':
1331 sys.exit(tdStorageBenchmark().main(sys.argv));
1332
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette