VirtualBox

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

Last change on this file since 79087 was 79087, checked in by vboxsync, 5 years ago

ValKit: New pylint version - cleanup in progress.

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