blob: ea0ffe4254c916f68ac0f45b067e575770b4d8af [file] [log] [blame]
#!/usr/bin/env python3
"""
multidd - run multiple dd concurrently to determine disk throughput
Usage: multidd {-i infile} {-o outfile} [-B blocksz] [-S filesz]
-i infile where infile specifies the path of input file
-o outfile where outfile specifies the path of output file
-B blocksz where blocksz is the size of each I/O block
[default=8KB]
-S filesz where filesz is the size of the file to write
[default=2X system RAM]
Multiple -i and -o arguments may be specified but they must pair up.
e.g. multidd -i /dev/zero -o /dbfast1/ddtest -B 8kb -S 2gb
"""
import getopt
import math
import os
import sys
def usage(exitarg):
print(__doc__)
sys.exit(exitarg)
def run(cmd):
f = None
ok = False
out = None
try:
f = os.popen(cmd)
out = f.read()
ok = not f.close()
except:
f.close()
ok = False
return ok, out
def getPlatform():
if sys.platform.find('linux') >= 0:
return 'linux'
if sys.platform.find('darwin') >= 0:
return 'darwin'
return '?'
def getMemory():
if getPlatform() == 'linux':
ok, out = run("sh -c 'cat /proc/meminfo | grep MemTotal'")
if not ok:
return '?'
mem_string_list = out.strip().split(' ')
val = int(mem_string_list[len(mem_string_list) - 2])
factor = mem_string_list[len(mem_string_list) - 1]
if factor == 'kB':
return val * 1024
return '?'
if getPlatform() == 'darwin':
ok, out = run("sysctl hw.physmem")
if not ok:
return '?'
mem_string_list = out.strip().split(' ')
val = int(mem_string_list[1])
return val
return '?'
def parseMemorySize(line):
factor = 1
try:
line = line.strip().upper()
if line.endswith('B'):
line = line[:-1]
if line.endswith('G'):
factor = 1024 * 1024 * 1024
elif line.endswith('M'):
factor = 1024 * 1024
elif line.endswith('K'):
factor = 1024
if factor > 1:
line = line[:-1]
return int(line) * factor
except:
return 0
def parseCommandLine():
global opt
try:
(options, args) = getopt.getopt(sys.argv[1:], '?i:o:B:S:')
except:
e = sys.exc_info()
usage('Error: %s %s' % (e[0], e[1]))
for (switch, val) in options:
if switch == '-?':
usage(0)
elif switch[1] in 'io':
opt[switch].append(val)
elif switch[1] in 'BS':
opt[switch] = parseMemorySize(val)
if opt['-S'] == '?':
sys.exit('Error: unable to obtain system RAM size')
if opt['-S'] < 0:
usage('Error: invalid -S filesz parameter')
if opt['-B'] <= 0:
usage('Error: invalid -B blocksz parameter')
if opt['-B'] > 1024 * 1024:
usage('Error: maximum 1MB for -B parameter')
if len(opt['-i']) != len(opt['-o']):
usage('Error: -i and -o parameters must pair up')
if len(opt['-i']) == 0:
usage('Error: missing -i and -o parameters')
opt = {'-i': [], '-o': [], '-B': parseMemorySize('8KB'), '-S': 0}
parseCommandLine()
if opt['-S'] == 0:
opt['-S'] = getMemory() * 2
if opt['-S'] < opt['-B']:
opt['-S'] = opt['-B']
cmd = []
pfile = []
blocksz = opt['-B']
cnt = int(math.ceil(opt['-S'] / blocksz))
totalBytes = 0
for i in range(len(opt['-i'])):
ifile = opt['-i'][i]
ofile = opt['-o'][i]
cmd.append('dd if=%s of=%s count=%d bs=%d' % (ifile, ofile, cnt, blocksz))
totalBytes += cnt * blocksz
for c in cmd:
print(c)
pfile.append(os.popen(c))
for f in pfile:
ok = False
try:
print(f.read())
ok = not f.close()
f = None
except:
if f:
f.close()
ok = False
if not ok:
sys.exit(1)
os.system('sync')
print('multidd total bytes ', totalBytes)