VirtualBox

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

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

ValidationKit: build fixes

  • Property svn:eol-style set to LF
  • Property svn:executable set to *
  • Property svn:keywords set to Author Date Id Revision
File size: 56.0 KB
Line 
1#!/usr/bin/env python
2# -*- coding: utf-8 -*-
3# $Id: tdStorageBenchmark1.py 79592 2019-07-08 12:31:34Z 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: 79592 $"
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': storagecfg.DiskCfg('solaris', storagecfg.g_ksDiskCfgRegExp, r'c[3-9]t\dd0\Z'),
398 'testboxstor2.de.oracle.com': storagecfg.DiskCfg('win', storagecfg.g_ksDiskCfgStatic, 'D:'),
399 'adaris': storagecfg.DiskCfg('linux', storagecfg.g_ksDiskCfgList, [ '/dev/sda' ]),
400 'daedalus': storagecfg.DiskCfg('darwin', storagecfg.g_ksDiskCfgStatic, \
401 '/Volumes/VirtualBox/Testsuite/StorageScratch')
402 };
403
404 # Available test sets.
405 kdTestSets = {
406 # Mostly for developing and debugging the testcase.
407 'Fast': {
408 'RecordSize': '64k',
409 'TestsetSize': '100m',
410 'QueueDepth': '32',
411 'DiskSizeGb': 2
412 },
413 # For quick functionality tests where benchmark results are not required.
414 'Functionality': {
415 'RecordSize': '64k',
416 'TestsetSize': '2g',
417 'QueueDepth': '32',
418 'DiskSizeGb': 10
419 },
420 # For benchmarking the I/O stack.
421 'Benchmark': {
422 'RecordSize': '64k',
423 'TestsetSize': '20g',
424 'QueueDepth': '32',
425 'DiskSizeGb': 30
426 },
427 # For stress testing which takes a lot of time.
428 'Stress': {
429 'RecordSize': '64k',
430 'TestsetSize': '2t',
431 'QueueDepth': '32',
432 'DiskSizeGb': 10000
433 },
434 };
435
436 # Dictionary mapping the virtualization mode mnemonics to a little less cryptic
437 # strings used in test descriptions.
438 kdVirtModeDescs = {
439 'raw' : 'Raw-mode',
440 'hwvirt' : 'HwVirt',
441 'hwvirt-np' : 'NestedPaging'
442 };
443
444 kdHostIoCacheDescs = {
445 'default' : 'HostCacheDef',
446 'hostiocache' : 'HostCacheOn',
447 'no-hostiocache' : 'HostCacheOff'
448 };
449
450 # Password ID for encryption.
451 ksPwId = 'EncPwId';
452
453 # Array indexes for the test configs.
454 kiVmName = 0;
455 kiStorageCtrl = 1;
456 kiHostIoCache = 2;
457 kiDiskFmt = 3;
458 kiDiskVar = 4;
459 kiCpuCount = 5;
460 kiVirtMode = 6;
461 kiIoTest = 7;
462 kiTestSet = 8;
463
464 def __init__(self):
465 vbox.TestDriver.__init__(self);
466 self.asRsrcs = None;
467 self.asTestVMsDef = ['tst-storage', 'tst-storage32'];
468 self.asTestVMs = self.asTestVMsDef;
469 self.asSkipVMs = [];
470 self.asVirtModesDef = ['hwvirt', 'hwvirt-np', 'raw',]
471 self.asVirtModes = self.asVirtModesDef;
472 self.acCpusDef = [1, 2];
473 self.acCpus = self.acCpusDef;
474 self.asStorageCtrlsDef = ['AHCI', 'IDE', 'LsiLogicSAS', 'LsiLogic', 'BusLogic', 'NVMe'];
475 self.asStorageCtrls = self.asStorageCtrlsDef;
476 self.asHostIoCacheDef = ['default', 'hostiocache', 'no-hostiocache'];
477 self.asHostIoCache = self.asHostIoCacheDef;
478 self.asDiskFormatsDef = ['VDI', 'VMDK', 'VHD', 'QED', 'Parallels', 'QCOW', 'iSCSI'];
479 self.asDiskFormats = self.asDiskFormatsDef;
480 self.asDiskVariantsDef = ['Dynamic', 'Fixed', 'DynamicSplit2G', 'FixedSplit2G', 'Network'];
481 self.asDiskVariants = self.asDiskVariantsDef;
482 self.asTestsDef = ['iozone', 'fio'];
483 self.asTests = self.asTestsDef;
484 self.asTestSetsDef = ['Fast', 'Functionality', 'Benchmark', 'Stress'];
485 self.asTestSets = self.asTestSetsDef;
486 self.asIscsiTargetsDef = [ ]; # @todo: Configure one target for basic iSCSI testing
487 self.asIscsiTargets = self.asIscsiTargetsDef;
488 self.cDiffLvlsDef = 0;
489 self.cDiffLvls = self.cDiffLvlsDef;
490 self.fTestHost = False;
491 self.fUseScratch = False;
492 self.fRecreateStorCfg = True;
493 self.fReportBenchmarkResults = True;
494 self.oStorCfg = None;
495 self.sIoLogPathDef = self.sScratchPath;
496 self.sIoLogPath = self.sIoLogPathDef;
497 self.fIoLog = False;
498 self.fUseRamDiskDef = False;
499 self.fUseRamDisk = self.fUseRamDiskDef;
500 self.fEncryptDiskDef = False;
501 self.fEncryptDisk = self.fEncryptDiskDef;
502 self.sEncryptPwDef = 'TestTestTest';
503 self.sEncryptPw = self.sEncryptPwDef;
504 self.sEncryptAlgoDef = 'AES-XTS256-PLAIN64';
505 self.sEncryptAlgo = self.sEncryptAlgoDef;
506
507 #
508 # Overridden methods.
509 #
510 def showUsage(self):
511 rc = vbox.TestDriver.showUsage(self);
512 reporter.log('');
513 reporter.log('tdStorageBenchmark1 Options:');
514 reporter.log(' --virt-modes <m1[:m2[:]]');
515 reporter.log(' Default: %s' % (':'.join(self.asVirtModesDef)));
516 reporter.log(' --cpu-counts <c1[:c2[:]]');
517 reporter.log(' Default: %s' % (':'.join(str(c) for c in self.acCpusDef)));
518 reporter.log(' --storage-ctrls <type1[:type2[:...]]>');
519 reporter.log(' Default: %s' % (':'.join(self.asStorageCtrlsDef)));
520 reporter.log(' --host-io-cache <setting1[:setting2[:...]]>');
521 reporter.log(' Default: %s' % (':'.join(self.asHostIoCacheDef)));
522 reporter.log(' --disk-formats <type1[:type2[:...]]>');
523 reporter.log(' Default: %s' % (':'.join(self.asDiskFormatsDef)));
524 reporter.log(' --disk-variants <variant1[:variant2[:...]]>');
525 reporter.log(' Default: %s' % (':'.join(self.asDiskVariantsDef)));
526 reporter.log(' --iscsi-targets <target1[:target2[:...]]>');
527 reporter.log(' Default: %s' % (':'.join(self.asIscsiTargetsDef)));
528 reporter.log(' --tests <test1[:test2[:...]]>');
529 reporter.log(' Default: %s' % (':'.join(self.asTestsDef)));
530 reporter.log(' --test-sets <set1[:set2[:...]]>');
531 reporter.log(' Default: %s' % (':'.join(self.asTestSetsDef)));
532 reporter.log(' --diff-levels <number of diffs>');
533 reporter.log(' Default: %s' % (self.cDiffLvlsDef));
534 reporter.log(' --test-vms <vm1[:vm2[:...]]>');
535 reporter.log(' Test the specified VMs in the given order. Use this to change');
536 reporter.log(' the execution order or limit the choice of VMs');
537 reporter.log(' Default: %s (all)' % (':'.join(self.asTestVMsDef)));
538 reporter.log(' --skip-vms <vm1[:vm2[:...]]>');
539 reporter.log(' Skip the specified VMs when testing.');
540 reporter.log(' --test-host');
541 reporter.log(' Do all configured tests on the host first and report the results');
542 reporter.log(' to get a baseline');
543 reporter.log(' --use-scratch');
544 reporter.log(' Use the scratch directory for testing instead of setting up');
545 reporter.log(' fresh volumes on dedicated disks (for development)');
546 reporter.log(' --always-wipe-storage-cfg');
547 reporter.log(' Recreate the host storage config before each test');
548 reporter.log(' --dont-wipe-storage-cfg');
549 reporter.log(' Don\'t recreate the host storage config before each test');
550 reporter.log(' --report-benchmark-results');
551 reporter.log(' Report all benchmark results');
552 reporter.log(' --dont-report-benchmark-results');
553 reporter.log(' Don\'t report any benchmark results');
554 reporter.log(' --io-log-path <path>');
555 reporter.log(' Default: %s' % (self.sIoLogPathDef));
556 reporter.log(' --enable-io-log');
557 reporter.log(' Whether to enable I/O logging for each test');
558 reporter.log(' --use-ramdisk');
559 reporter.log(' Default: %s' % (self.fUseRamDiskDef));
560 reporter.log(' --encrypt-disk');
561 reporter.log(' Default: %s' % (self.fEncryptDiskDef));
562 reporter.log(' --encrypt-password');
563 reporter.log(' Default: %s' % (self.sEncryptPwDef));
564 reporter.log(' --encrypt-algorithm');
565 reporter.log(' Default: %s' % (self.sEncryptAlgoDef));
566 return rc;
567
568 def parseOption(self, asArgs, iArg): # pylint: disable=too-many-branches,too-many-statements
569 if asArgs[iArg] == '--virt-modes':
570 iArg += 1;
571 if iArg >= len(asArgs): raise base.InvalidOption('The "--virt-modes" takes a colon separated list of modes');
572 self.asVirtModes = asArgs[iArg].split(':');
573 for s in self.asVirtModes:
574 if s not in self.asVirtModesDef:
575 raise base.InvalidOption('The "--virt-modes" value "%s" is not valid; valid values are: %s' \
576 % (s, ' '.join(self.asVirtModesDef)));
577 elif asArgs[iArg] == '--cpu-counts':
578 iArg += 1;
579 if iArg >= len(asArgs): raise base.InvalidOption('The "--cpu-counts" takes a colon separated list of cpu counts');
580 self.acCpus = [];
581 for s in asArgs[iArg].split(':'):
582 try: c = int(s);
583 except: raise base.InvalidOption('The "--cpu-counts" value "%s" is not an integer' % (s,));
584 if c <= 0: raise base.InvalidOption('The "--cpu-counts" value "%s" is zero or negative' % (s,));
585 self.acCpus.append(c);
586 elif asArgs[iArg] == '--storage-ctrls':
587 iArg += 1;
588 if iArg >= len(asArgs):
589 raise base.InvalidOption('The "--storage-ctrls" takes a colon separated list of Storage controller types');
590 self.asStorageCtrls = asArgs[iArg].split(':');
591 elif asArgs[iArg] == '--host-io-cache':
592 iArg += 1;
593 if iArg >= len(asArgs):
594 raise base.InvalidOption('The "--host-io-cache" takes a colon separated list of I/O cache settings');
595 self.asHostIoCache = asArgs[iArg].split(':');
596 elif asArgs[iArg] == '--disk-formats':
597 iArg += 1;
598 if iArg >= len(asArgs): raise base.InvalidOption('The "--disk-formats" takes a colon separated list of disk formats');
599 self.asDiskFormats = asArgs[iArg].split(':');
600 elif asArgs[iArg] == '--disk-variants':
601 iArg += 1;
602 if iArg >= len(asArgs):
603 raise base.InvalidOption('The "--disk-variants" takes a colon separated list of disk variants');
604 self.asDiskVariants = asArgs[iArg].split(':');
605 elif asArgs[iArg] == '--iscsi-targets':
606 iArg += 1;
607 if iArg >= len(asArgs):
608 raise base.InvalidOption('The "--iscsi-targets" takes a colon separated list of iscsi targets');
609 self.asIscsiTargets = asArgs[iArg].split(':');
610 elif asArgs[iArg] == '--tests':
611 iArg += 1;
612 if iArg >= len(asArgs): raise base.InvalidOption('The "--tests" takes a colon separated list of tests to run');
613 self.asTests = asArgs[iArg].split(':');
614 elif asArgs[iArg] == '--test-sets':
615 iArg += 1;
616 if iArg >= len(asArgs): raise base.InvalidOption('The "--test-sets" takes a colon separated list of test sets');
617 self.asTestSets = asArgs[iArg].split(':');
618 elif asArgs[iArg] == '--diff-levels':
619 iArg += 1;
620 if iArg >= len(asArgs): raise base.InvalidOption('The "--diff-levels" takes an integer');
621 try: self.cDiffLvls = int(asArgs[iArg]);
622 except: raise base.InvalidOption('The "--diff-levels" value "%s" is not an integer' % (asArgs[iArg],));
623 elif asArgs[iArg] == '--test-vms':
624 iArg += 1;
625 if iArg >= len(asArgs): raise base.InvalidOption('The "--test-vms" takes colon separated list');
626 self.asTestVMs = asArgs[iArg].split(':');
627 for s in self.asTestVMs:
628 if s not in self.asTestVMsDef:
629 raise base.InvalidOption('The "--test-vms" value "%s" is not valid; valid values are: %s' \
630 % (s, ' '.join(self.asTestVMsDef)));
631 elif asArgs[iArg] == '--skip-vms':
632 iArg += 1;
633 if iArg >= len(asArgs): raise base.InvalidOption('The "--skip-vms" takes colon separated list');
634 self.asSkipVMs = asArgs[iArg].split(':');
635 for s in self.asSkipVMs:
636 if s not in self.asTestVMsDef:
637 reporter.log('warning: The "--test-vms" value "%s" does not specify any of our test VMs.' % (s));
638 elif asArgs[iArg] == '--test-host':
639 self.fTestHost = True;
640 elif asArgs[iArg] == '--use-scratch':
641 self.fUseScratch = True;
642 elif asArgs[iArg] == '--always-wipe-storage-cfg':
643 self.fRecreateStorCfg = True;
644 elif asArgs[iArg] == '--dont-wipe-storage-cfg':
645 self.fRecreateStorCfg = False;
646 elif asArgs[iArg] == '--report-benchmark-results':
647 self.fReportBenchmarkResults = True;
648 elif asArgs[iArg] == '--dont-report-benchmark-results':
649 self.fReportBenchmarkResults = False;
650 elif asArgs[iArg] == '--io-log-path':
651 iArg += 1;
652 if iArg >= len(asArgs): raise base.InvalidOption('The "--io-log-path" takes a path argument');
653 self.sIoLogPath = asArgs[iArg];
654 elif asArgs[iArg] == '--enable-io-log':
655 self.fIoLog = True;
656 elif asArgs[iArg] == '--use-ramdisk':
657 self.fUseRamDisk = True;
658 elif asArgs[iArg] == '--encrypt-disk':
659 self.fEncryptDisk = True;
660 elif asArgs[iArg] == '--encrypt-password':
661 iArg += 1;
662 if iArg >= len(asArgs): raise base.InvalidOption('The "--encrypt-password" takes a string');
663 self.sEncryptPw = asArgs[iArg];
664 elif asArgs[iArg] == '--encrypt-algorithm':
665 iArg += 1;
666 if iArg >= len(asArgs): raise base.InvalidOption('The "--encrypt-algorithm" takes a string');
667 self.sEncryptAlgo = asArgs[iArg];
668 else:
669 return vbox.TestDriver.parseOption(self, asArgs, iArg);
670 return iArg + 1;
671
672 def completeOptions(self):
673 # Remove skipped VMs from the test list.
674 for sVM in self.asSkipVMs:
675 try: self.asTestVMs.remove(sVM);
676 except: pass;
677
678 return vbox.TestDriver.completeOptions(self);
679
680 def getResourceSet(self):
681 # Construct the resource list the first time it's queried.
682 if self.asRsrcs is None:
683 self.asRsrcs = [];
684 if 'tst-storage' in self.asTestVMs:
685 self.asRsrcs.append('5.0/storage/tst-storage.vdi');
686 if 'tst-storage32' in self.asTestVMs:
687 self.asRsrcs.append('5.0/storage/tst-storage32.vdi');
688
689 return self.asRsrcs;
690
691 def actionConfig(self):
692
693 # Make sure vboxapi has been imported so we can use the constants.
694 if not self.importVBoxApi():
695 return False;
696
697 #
698 # Configure the VMs we're going to use.
699 #
700
701 # Linux VMs
702 if 'tst-storage' in self.asTestVMs:
703 oVM = self.createTestVM('tst-storage', 1, '5.0/storage/tst-storage.vdi', sKind = 'ArchLinux_64', fIoApic = True, \
704 eNic0AttachType = vboxcon.NetworkAttachmentType_NAT, \
705 eNic0Type = vboxcon.NetworkAdapterType_Am79C973);
706 if oVM is None:
707 return False;
708
709 if 'tst-storage32' in self.asTestVMs:
710 oVM = self.createTestVM('tst-storage32', 1, '5.0/storage/tst-storage32.vdi', sKind = 'ArchLinux', fIoApic = True, \
711 eNic0AttachType = vboxcon.NetworkAttachmentType_NAT, \
712 eNic0Type = vboxcon.NetworkAdapterType_Am79C973);
713 if oVM is None:
714 return False;
715
716 return True;
717
718 def actionExecute(self):
719 """
720 Execute the testcase.
721 """
722 fRc = self.test1();
723 return fRc;
724
725
726 #
727 # Test execution helpers.
728 #
729
730 def prepareStorage(self, oStorCfg, fRamDisk = False, cbPool = None):
731 """
732 Prepares the host storage for disk images or direct testing on the host.
733 """
734 # Create a basic pool with the default configuration.
735 sMountPoint = None;
736 fRc, sPoolId = oStorCfg.createStoragePool(cbPool = cbPool, fRamDisk = fRamDisk);
737 if fRc:
738 fRc, sMountPoint = oStorCfg.createVolume(sPoolId);
739 if not fRc:
740 sMountPoint = None;
741 oStorCfg.cleanup();
742
743 return sMountPoint;
744
745 def cleanupStorage(self, oStorCfg):
746 """
747 Cleans up any created storage space for a test.
748 """
749 return oStorCfg.cleanup();
750
751 def getGuestDisk(self, oSession, oTxsSession, eStorageController):
752 """
753 Gets the path of the disk in the guest to use for testing.
754 """
755 lstDisks = None;
756
757 # The naming scheme for NVMe is different and we don't have
758 # to query the guest for unformatted disks here because the disk with the OS
759 # is not attached to a NVMe controller.
760 if eStorageController == vboxcon.StorageControllerType_NVMe:
761 lstDisks = [ '/dev/nvme0n1' ];
762 else:
763 # Find a unformatted disk (no partition).
764 # @todo: This is a hack because LIST and STAT are not yet implemented
765 # in TXS (get to this eventually)
766 lstBlkDev = [ '/dev/sda', '/dev/sdb' ];
767 for sBlkDev in lstBlkDev:
768 fRc = oTxsSession.syncExec('/usr/bin/ls', ('ls', sBlkDev + '1'));
769 if not fRc:
770 lstDisks = [ sBlkDev ];
771 break;
772
773 _ = oSession;
774 return lstDisks;
775
776 def getDiskFormatVariantsForTesting(self, sDiskFmt, asVariants):
777 """
778 Returns a list of disk variants for testing supported by the given
779 disk format and selected for testing.
780 """
781 lstDskFmts = self.oVBoxMgr.getArray(self.oVBox.systemProperties, 'mediumFormats');
782 for oDskFmt in lstDskFmts:
783 if oDskFmt.id == sDiskFmt:
784 lstDskVariants = [];
785 lstCaps = self.oVBoxMgr.getArray(oDskFmt, 'capabilities');
786
787 if vboxcon.MediumFormatCapabilities_CreateDynamic in lstCaps \
788 and 'Dynamic' in asVariants:
789 lstDskVariants.append('Dynamic');
790
791 if vboxcon.MediumFormatCapabilities_CreateFixed in lstCaps \
792 and 'Fixed' in asVariants:
793 lstDskVariants.append('Fixed');
794
795 if vboxcon.MediumFormatCapabilities_CreateSplit2G in lstCaps \
796 and vboxcon.MediumFormatCapabilities_CreateDynamic in lstCaps \
797 and 'DynamicSplit2G' in asVariants:
798 lstDskVariants.append('DynamicSplit2G');
799
800 if vboxcon.MediumFormatCapabilities_CreateSplit2G in lstCaps \
801 and vboxcon.MediumFormatCapabilities_CreateFixed in lstCaps \
802 and 'FixedSplit2G' in asVariants:
803 lstDskVariants.append('FixedSplit2G');
804
805 if vboxcon.MediumFormatCapabilities_TcpNetworking in lstCaps \
806 and 'Network' in asVariants:
807 lstDskVariants.append('Network'); # Solely for iSCSI to get a non empty list
808
809 return lstDskVariants;
810
811 return [];
812
813 def convDiskToMediumVariant(self, sDiskVariant):
814 """
815 Returns a tuple of medium variant flags matching the given disk variant.
816 """
817 tMediumVariant = None;
818 if sDiskVariant == 'Dynamic':
819 tMediumVariant = (vboxcon.MediumVariant_Standard, );
820 elif sDiskVariant == 'Fixed':
821 tMediumVariant = (vboxcon.MediumVariant_Fixed, );
822 elif sDiskVariant == 'DynamicSplit2G':
823 tMediumVariant = (vboxcon.MediumVariant_Standard, vboxcon.MediumVariant_VmdkSplit2G);
824 elif sDiskVariant == 'FixedSplit2G':
825 tMediumVariant = (vboxcon.MediumVariant_Fixed, vboxcon.MediumVariant_VmdkSplit2G);
826
827 return tMediumVariant;
828
829 def getStorageCtrlFromName(self, sStorageCtrl):
830 """
831 Resolves the storage controller string to the matching constant.
832 """
833 eStorageCtrl = None;
834
835 if sStorageCtrl == 'AHCI':
836 eStorageCtrl = vboxcon.StorageControllerType_IntelAhci;
837 elif sStorageCtrl == 'IDE':
838 eStorageCtrl = vboxcon.StorageControllerType_PIIX4;
839 elif sStorageCtrl == 'LsiLogicSAS':
840 eStorageCtrl = vboxcon.StorageControllerType_LsiLogicSas;
841 elif sStorageCtrl == 'LsiLogic':
842 eStorageCtrl = vboxcon.StorageControllerType_LsiLogic;
843 elif sStorageCtrl == 'BusLogic':
844 eStorageCtrl = vboxcon.StorageControllerType_BusLogic;
845 elif sStorageCtrl == 'NVMe':
846 eStorageCtrl = vboxcon.StorageControllerType_NVMe;
847
848 return eStorageCtrl;
849
850 def getStorageDriverFromEnum(self, eStorageCtrl, fHardDisk):
851 """
852 Returns the appropriate driver name for the given storage controller
853 and a flag whether the driver has the generic SCSI driver attached.
854 """
855 if eStorageCtrl == vboxcon.StorageControllerType_IntelAhci:
856 if fHardDisk:
857 return ('ahci', False);
858 return ('ahci', True);
859 if eStorageCtrl == vboxcon.StorageControllerType_PIIX4:
860 return ('piix3ide', False);
861 if eStorageCtrl == vboxcon.StorageControllerType_LsiLogicSas:
862 return ('lsilogicsas', True);
863 if eStorageCtrl == vboxcon.StorageControllerType_LsiLogic:
864 return ('lsilogicscsi', True);
865 if eStorageCtrl == vboxcon.StorageControllerType_BusLogic:
866 return ('buslogic', True);
867 if eStorageCtrl == vboxcon.StorageControllerType_NVMe:
868 return ('nvme', False);
869
870 return ('<invalid>', False);
871
872 def isTestCfgSupported(self, asTestCfg):
873 """
874 Returns whether a specific test config is supported.
875 """
876
877 # Check whether the disk variant is supported by the selected format.
878 asVariants = self.getDiskFormatVariantsForTesting(asTestCfg[self.kiDiskFmt], [ asTestCfg[self.kiDiskVar] ]);
879 if not asVariants:
880 return False;
881
882 # For iSCSI check whether we have targets configured.
883 if asTestCfg[self.kiDiskFmt] == 'iSCSI' and not self.asIscsiTargets:
884 return False;
885
886 # Check for virt mode, CPU count and selected VM.
887 if asTestCfg[self.kiVirtMode] == 'raw' \
888 and (asTestCfg[self.kiCpuCount] > 1 or asTestCfg[self.kiVmName] == 'tst-storage'):
889 return False;
890
891 # IDE does not support the no host I/O cache setting
892 if asTestCfg[self.kiHostIoCache] == 'no-hostiocache' \
893 and asTestCfg[self.kiStorageCtrl] == 'IDE':
894 return False;
895
896 return True;
897
898 def fnFormatCpuString(self, cCpus):
899 """
900 Formats the CPU count to be readable.
901 """
902 if cCpus == 1:
903 return '1 cpu';
904 return '%u cpus' % (cCpus);
905
906 def fnFormatVirtMode(self, sVirtMode):
907 """
908 Formats the virtualization mode to be a little less cryptic for use in test
909 descriptions.
910 """
911 return self.kdVirtModeDescs[sVirtMode];
912
913 def fnFormatHostIoCache(self, sHostIoCache):
914 """
915 Formats the host I/O cache mode to be a little less cryptic for use in test
916 descriptions.
917 """
918 return self.kdHostIoCacheDescs[sHostIoCache];
919
920 def testBenchmark(self, sTargetOs, sBenchmark, sMountpoint, oExecutor, dTestSet, \
921 cMsTimeout = 3600000):
922 """
923 Runs the given benchmark on the test host.
924 """
925
926 dTestSet['FilePath'] = sMountpoint;
927 dTestSet['TargetOs'] = sTargetOs;
928
929 oTst = None;
930 if sBenchmark == 'iozone':
931 oTst = IozoneTest(oExecutor, dTestSet);
932 elif sBenchmark == 'fio':
933 oTst = FioTest(oExecutor, dTestSet); # pylint: disable=redefined-variable-type
934
935 if oTst is not None:
936 fRc = oTst.prepare();
937 if fRc:
938 fRc = oTst.run(cMsTimeout);
939 if fRc:
940 if self.fReportBenchmarkResults:
941 fRc = oTst.reportResult();
942 else:
943 reporter.testFailure('Running the testcase failed');
944 reporter.addLogString(oTst.getErrorReport(), sBenchmark + '.log',
945 'log/release/client', 'Benchmark raw output');
946 else:
947 reporter.testFailure('Preparing the testcase failed');
948
949 oTst.cleanup();
950
951 return fRc;
952
953 def createHd(self, oSession, sDiskFormat, sDiskVariant, iDiffLvl, oHdParent, \
954 sDiskPath, cbDisk):
955 """
956 Creates a new disk with the given parameters returning the medium object
957 on success.
958 """
959
960 oHd = None;
961 if sDiskFormat == "iSCSI" and iDiffLvl == 0:
962 listNames = [];
963 listValues = [];
964 listValues = self.asIscsiTargets[0].split('|');
965 listNames.append('TargetAddress');
966 listNames.append('TargetName');
967 listNames.append('LUN');
968
969 if self.fpApiVer >= 5.0:
970 oHd = oSession.oVBox.createMedium(sDiskFormat, sDiskPath, vboxcon.AccessMode_ReadWrite, \
971 vboxcon.DeviceType_HardDisk);
972 else:
973 oHd = oSession.oVBox.createHardDisk(sDiskFormat, sDiskPath);
974 oHd.type = vboxcon.MediumType_Normal;
975 oHd.setProperties(listNames, listValues);
976 else:
977 if iDiffLvl == 0:
978 tMediumVariant = self.convDiskToMediumVariant(sDiskVariant);
979 oHd = oSession.createBaseHd(sDiskPath + '/base.disk', sDiskFormat, cbDisk, \
980 cMsTimeout = 3600 * 1000, tMediumVariant = tMediumVariant);
981 else:
982 sDiskPath = sDiskPath + '/diff_%u.disk' % (iDiffLvl);
983 oHd = oSession.createDiffHd(oHdParent, sDiskPath, None);
984
985 if oHd is not None and iDiffLvl == 0 and self.fEncryptDisk:
986 try:
987 oIProgress = oHd.changeEncryption('', self.sEncryptAlgo, self.sEncryptPw, self.ksPwId);
988 oProgress = vboxwrappers.ProgressWrapper(oIProgress, self.oVBoxMgr, self, 'Encrypting "%s"' % (sDiskPath,));
989 oProgress.wait(60*60000); # Wait for up to one hour, fixed disks take longer to encrypt.
990 if oProgress.logResult() is False:
991 raise base.GenError('Encrypting disk "%s" failed' % (sDiskPath, ));
992 except:
993 reporter.errorXcpt('changeEncryption("%s","%s","%s") failed on "%s"' \
994 % ('', self.sEncryptAlgo, self.sEncryptPw, oSession.sName) );
995 self.oVBox.deleteHdByMedium(oHd);
996 oHd = None;
997 else:
998 reporter.log('Encrypted "%s"' % (sDiskPath,));
999
1000 return oHd;
1001
1002 def startVmAndConnect(self, sVmName):
1003 """
1004 Our own implementation of startVmAndConnectToTxsViaTcp to make it possible
1005 to add passwords to a running VM when encryption is used.
1006 """
1007 oSession = self.startVmByName(sVmName);
1008 if oSession is not None:
1009 # Add password to the session in case encryption is used.
1010 fRc = True;
1011 if self.fEncryptDisk:
1012 try:
1013 oSession.o.console.addDiskEncryptionPassword(self.ksPwId, self.sEncryptPw, False);
1014 except:
1015 reporter.logXcpt();
1016 fRc = False;
1017
1018 # Connect to TXS.
1019 if fRc:
1020 reporter.log2('startVmAndConnect: Started(/prepared) "%s", connecting to TXS ...' % (sVmName,));
1021 (fRc, oTxsSession) = self.txsDoConnectViaTcp(oSession, 15*60000, fNatForwardingForTxs = True);
1022 if fRc is True:
1023 if fRc is True:
1024 # Success!
1025 return (oSession, oTxsSession);
1026 else:
1027 reporter.error('startVmAndConnect: txsDoConnectViaTcp failed');
1028 # If something went wrong while waiting for TXS to be started - take VM screenshot before terminate it
1029
1030 self.terminateVmBySession(oSession);
1031
1032 return (None, None);
1033
1034 def testOneCfg(self, sVmName, eStorageController, sHostIoCache, sDiskFormat, # pylint: disable=too-many-arguments,too-many-locals,too-many-statements
1035 sDiskVariant, sDiskPath, cCpus, sIoTest, sVirtMode, sTestSet):
1036 """
1037 Runs the specified VM thru test #1.
1038
1039 Returns a success indicator on the general test execution. This is not
1040 the actual test result.
1041 """
1042 oVM = self.getVmByName(sVmName);
1043
1044 dTestSet = self.kdTestSets.get(sTestSet);
1045 cbDisk = dTestSet.get('DiskSizeGb') * 1024*1024*1024;
1046 fHwVirt = sVirtMode != 'raw';
1047 fNestedPaging = sVirtMode == 'hwvirt-np';
1048
1049 fRc = True;
1050 if sDiskFormat == 'iSCSI':
1051 sDiskPath = self.asIscsiTargets[0];
1052 elif self.fUseScratch:
1053 sDiskPath = self.sScratchPath;
1054 else:
1055 # If requested recreate the storage space to start with a clean config
1056 # for benchmarks
1057 if self.fRecreateStorCfg:
1058 sMountPoint = self.prepareStorage(self.oStorCfg, self.fUseRamDisk, 2 * cbDisk);
1059 if sMountPoint is not None:
1060 # Create a directory where every normal user can write to.
1061 self.oStorCfg.mkDirOnVolume(sMountPoint, 'test', 0o777);
1062 sDiskPath = sMountPoint + '/test';
1063 else:
1064 fRc = False;
1065 reporter.testFailure('Failed to prepare storage for VM');
1066
1067 if not fRc:
1068 return fRc;
1069
1070 lstDisks = []; # List of disks we have to delete afterwards.
1071
1072 for iDiffLvl in range(self.cDiffLvls + 1):
1073 sIoLogFile = None;
1074
1075 if iDiffLvl == 0:
1076 reporter.testStart('Base');
1077 else:
1078 reporter.testStart('Diff %u' % (iDiffLvl));
1079
1080 # Reconfigure the VM
1081 oSession = self.openSession(oVM);
1082 if oSession is not None:
1083 #
1084 # Disable audio controller which shares the interrupt line with the BusLogic controller and is suspected to cause
1085 # rare test failures because the device initialization fails.
1086 #
1087 fRc = oSession.setupAudio(vboxcon.AudioControllerType_AC97, False);
1088 # Attach HD
1089 fRc = fRc and oSession.ensureControllerAttached(self.controllerTypeToName(eStorageController));
1090 fRc = fRc and oSession.setStorageControllerType(eStorageController,
1091 self.controllerTypeToName(eStorageController));
1092
1093 if sHostIoCache == 'hostiocache':
1094 fRc = fRc and oSession.setStorageControllerHostIoCache(self.controllerTypeToName(eStorageController), True);
1095 elif sHostIoCache == 'no-hostiocache':
1096 fRc = fRc and oSession.setStorageControllerHostIoCache(self.controllerTypeToName(eStorageController), False);
1097
1098 iDevice = 0;
1099 if eStorageController in (vboxcon.StorageControllerType_PIIX3, vboxcon.StorageControllerType_PIIX4,):
1100 iDevice = 1; # Master is for the OS.
1101
1102 oHdParent = None;
1103 if iDiffLvl > 0:
1104 oHdParent = lstDisks[0];
1105 oHd = self.createHd(oSession, sDiskFormat, sDiskVariant, iDiffLvl, oHdParent, sDiskPath, cbDisk);
1106 if oHd is not None:
1107 lstDisks.insert(0, oHd);
1108 try:
1109 if oSession.fpApiVer >= 4.0:
1110 oSession.o.machine.attachDevice(self.controllerTypeToName(eStorageController),
1111 0, iDevice, vboxcon.DeviceType_HardDisk, oHd);
1112 else:
1113 oSession.o.machine.attachDevice(self.controllerTypeToName(eStorageController),
1114 0, iDevice, vboxcon.DeviceType_HardDisk, oHd.id);
1115 except:
1116 reporter.errorXcpt('attachDevice("%s",%s,%s,HardDisk,"%s") failed on "%s"' \
1117 % (self.controllerTypeToName(eStorageController), 1, 0, oHd.id, oSession.sName) );
1118 fRc = False;
1119 else:
1120 reporter.log('attached "%s" to %s' % (sDiskPath, oSession.sName));
1121 else:
1122 fRc = False;
1123
1124 # Set up the I/O logging config if enabled
1125 if fRc and self.fIoLog:
1126 try:
1127 oSession.o.machine.setExtraData('VBoxInternal2/EnableDiskIntegrityDriver', '1');
1128
1129 iLun = 0;
1130 if eStorageController in (vboxcon.StorageControllerType_PIIX3, vboxcon.StorageControllerType_PIIX4,):
1131 iLun = 1
1132 sDrv, fDrvScsi = self.getStorageDriverFromEnum(eStorageController, True);
1133 if fDrvScsi:
1134 sCfgmPath = 'VBoxInternal/Devices/%s/0/LUN#%u/AttachedDriver/Config' % (sDrv, iLun);
1135 else:
1136 sCfgmPath = 'VBoxInternal/Devices/%s/0/LUN#%u/Config' % (sDrv, iLun);
1137
1138 sIoLogFile = '%s/%s.iolog' % (self.sIoLogPath, sDrv);
1139 print(sCfgmPath);
1140 print(sIoLogFile);
1141 oSession.o.machine.setExtraData('%s/IoLog' % (sCfgmPath,), sIoLogFile);
1142 except:
1143 reporter.logXcpt();
1144
1145 fRc = fRc and oSession.enableVirtEx(fHwVirt);
1146 fRc = fRc and oSession.enableNestedPaging(fNestedPaging);
1147 fRc = fRc and oSession.setCpuCount(cCpus);
1148 fRc = fRc and oSession.saveSettings();
1149 fRc = oSession.close() and fRc and True; # pychecker hack.
1150 oSession = None;
1151 else:
1152 fRc = False;
1153
1154 # Start up.
1155 if fRc is True:
1156 self.logVmInfo(oVM);
1157 oSession, oTxsSession = self.startVmAndConnect(sVmName);
1158 if oSession is not None:
1159 self.addTask(oTxsSession);
1160
1161 # Fudge factor - Allow the guest to finish starting up.
1162 self.sleep(5);
1163
1164 # Prepare the storage on the guest
1165 lstBinaryPaths = ['/bin', '/sbin', '/usr/bin', '/usr/sbin' ];
1166 oExecVm = remoteexecutor.RemoteExecutor(oTxsSession, lstBinaryPaths, '${SCRATCH}');
1167 oGstDiskCfg = storagecfg.DiskCfg('linux', storagecfg.g_ksDiskCfgList, \
1168 self.getGuestDisk(oSession, oTxsSession, eStorageController));
1169 oStorCfgVm = storagecfg.StorageCfg(oExecVm, oGstDiskCfg);
1170
1171 iTry = 0;
1172 while iTry < 3:
1173 sMountPoint = self.prepareStorage(oStorCfgVm);
1174 if sMountPoint is not None:
1175 reporter.log('Prepared storage on %s try' % (iTry + 1,));
1176 break;
1177 else:
1178 iTry = iTry + 1;
1179 self.sleep(5);
1180
1181 if sMountPoint is not None:
1182 self.testBenchmark('linux', sIoTest, sMountPoint, oExecVm, dTestSet, \
1183 cMsTimeout = 3 * 3600 * 1000); # 3 hours max (Benchmark and QED takes a lot of time)
1184 self.cleanupStorage(oStorCfgVm);
1185 else:
1186 reporter.testFailure('Failed to prepare storage for the guest benchmark');
1187
1188 # cleanup.
1189 self.removeTask(oTxsSession);
1190 self.terminateVmBySession(oSession);
1191
1192 # Add the I/O log if it exists and the test failed
1193 if reporter.testErrorCount() > 0 \
1194 and sIoLogFile is not None \
1195 and os.path.exists(sIoLogFile):
1196 reporter.addLogFile(sIoLogFile, 'misc/other', 'I/O log');
1197 os.remove(sIoLogFile);
1198
1199 else:
1200 fRc = False;
1201
1202 # Remove disk
1203 oSession = self.openSession(oVM);
1204 if oSession is not None:
1205 try:
1206 oSession.o.machine.detachDevice(self.controllerTypeToName(eStorageController), 0, iDevice);
1207
1208 # Remove storage controller if it is not an IDE controller.
1209 if eStorageController not in (vboxcon.StorageControllerType_PIIX3, vboxcon.StorageControllerType_PIIX4,):
1210 oSession.o.machine.removeStorageController(self.controllerTypeToName(eStorageController));
1211
1212 oSession.saveSettings();
1213 oSession.saveSettings();
1214 oSession.close();
1215 oSession = None;
1216 except:
1217 reporter.errorXcpt('failed to detach/delete disk %s from storage controller' % (sDiskPath));
1218 else:
1219 fRc = False;
1220
1221 reporter.testDone();
1222
1223 # Delete all disks
1224 for oHd in lstDisks:
1225 self.oVBox.deleteHdByMedium(oHd);
1226
1227 # Cleanup storage area
1228 if sDiskFormat != 'iSCSI' and not self.fUseScratch and self.fRecreateStorCfg:
1229 self.cleanupStorage(self.oStorCfg);
1230
1231 return fRc;
1232
1233 def testStorage(self, sDiskPath = None):
1234 """
1235 Runs the storage testcase through the selected configurations
1236 """
1237
1238 aasTestCfgs = [];
1239 aasTestCfgs.insert(self.kiVmName, self.asTestVMs);
1240 aasTestCfgs.insert(self.kiStorageCtrl, self.asStorageCtrls);
1241 aasTestCfgs.insert(self.kiHostIoCache, (self.asHostIoCache, self.fnFormatHostIoCache));
1242 aasTestCfgs.insert(self.kiDiskFmt, self.asDiskFormats);
1243 aasTestCfgs.insert(self.kiDiskVar, self.asDiskVariants);
1244 aasTestCfgs.insert(self.kiCpuCount, (self.acCpus, self.fnFormatCpuString));
1245 aasTestCfgs.insert(self.kiVirtMode, (self.asVirtModes, self.fnFormatVirtMode));
1246 aasTestCfgs.insert(self.kiIoTest, self.asTests);
1247 aasTestCfgs.insert(self.kiTestSet, self.asTestSets);
1248
1249 aasTestsBlacklist = [];
1250 aasTestsBlacklist.append(['tst-storage', 'BusLogic']); # 64bit Linux is broken with BusLogic
1251
1252 oTstCfgMgr = StorTestCfgMgr(aasTestCfgs, aasTestsBlacklist, self.isTestCfgSupported);
1253
1254 fRc = True;
1255 asTestCfg = oTstCfgMgr.getCurrentTestCfg();
1256 while asTestCfg:
1257 fRc = self.testOneCfg(asTestCfg[self.kiVmName], self.getStorageCtrlFromName(asTestCfg[self.kiStorageCtrl]), \
1258 asTestCfg[self.kiHostIoCache], asTestCfg[self.kiDiskFmt], asTestCfg[self.kiDiskVar],
1259 sDiskPath, asTestCfg[self.kiCpuCount], asTestCfg[self.kiIoTest], \
1260 asTestCfg[self.kiVirtMode], asTestCfg[self.kiTestSet]) and fRc and True; # pychecker hack.
1261
1262 asTestCfg = oTstCfgMgr.getNextTestCfg();
1263
1264 return fRc;
1265
1266 def test1(self):
1267 """
1268 Executes test #1.
1269 """
1270
1271 fRc = True;
1272 oDiskCfg = self.kdStorageCfgs.get(socket.gethostname().lower());
1273
1274 # Test the host first if requested
1275 if oDiskCfg is not None or self.fUseScratch:
1276 lstBinaryPaths = ['/bin', '/sbin', '/usr/bin', '/usr/sbin', \
1277 '/opt/csw/bin', '/usr/ccs/bin', '/usr/sfw/bin'];
1278 oExecutor = remoteexecutor.RemoteExecutor(None, lstBinaryPaths, self.sScratchPath);
1279 if not self.fUseScratch:
1280 self.oStorCfg = storagecfg.StorageCfg(oExecutor, oDiskCfg);
1281
1282 # Try to cleanup any leftovers from a previous run first.
1283 fRc = self.oStorCfg.cleanupLeftovers();
1284 if not fRc:
1285 reporter.error('Failed to cleanup any leftovers from a previous run');
1286
1287 if self.fTestHost:
1288 reporter.testStart('Host');
1289 if self.fUseScratch:
1290 sMountPoint = self.sScratchPath;
1291 else:
1292 sMountPoint = self.prepareStorage(self.oStorCfg);
1293 if sMountPoint is not None:
1294 for sIoTest in self.asTests:
1295 reporter.testStart(sIoTest);
1296 for sTestSet in self.asTestSets:
1297 reporter.testStart(sTestSet);
1298 dTestSet = self.kdTestSets.get(sTestSet);
1299 self.testBenchmark(utils.getHostOs(), sIoTest, sMountPoint, oExecutor, dTestSet);
1300 reporter.testDone();
1301 reporter.testDone();
1302 self.cleanupStorage(self.oStorCfg);
1303 else:
1304 reporter.testFailure('Failed to prepare host storage');
1305 fRc = False;
1306 reporter.testDone();
1307 else:
1308 # Create the storage space first if it is not done before every test.
1309 sMountPoint = None;
1310 if self.fUseScratch:
1311 sMountPoint = self.sScratchPath;
1312 elif not self.fRecreateStorCfg:
1313 reporter.testStart('Create host storage');
1314 sMountPoint = self.prepareStorage(self.oStorCfg);
1315 if sMountPoint is None:
1316 reporter.testFailure('Failed to prepare host storage');
1317 fRc = False;
1318 self.oStorCfg.mkDirOnVolume(sMountPoint, 'test', 0o777);
1319 sMountPoint = sMountPoint + '/test';
1320 reporter.testDone();
1321
1322 if fRc:
1323 # Run the storage tests.
1324 if not self.testStorage(sMountPoint):
1325 fRc = False;
1326
1327 if not self.fRecreateStorCfg and not self.fUseScratch:
1328 self.cleanupStorage(self.oStorCfg);
1329 else:
1330 fRc = False;
1331
1332 return fRc;
1333
1334if __name__ == '__main__':
1335 sys.exit(tdStorageBenchmark().main(sys.argv));
1336
Note: See TracBrowser for help on using the repository browser.

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