updates to tests
diff --git a/data.py b/data.py
new file mode 100644
index 0000000..5569616
--- /dev/null
+++ b/data.py
@@ -0,0 +1,113 @@
+import re
+import sys
+
+
+splitter_rr = "(?ms)=====+\n"
+
+
+def get_data_from_output(fname):
+ results = {}
+ fc = open(fname).read()
+
+ for block in re.split(splitter_rr, fc):
+ block = block.strip()
+ if not block.startswith("[{u'__meta__':"):
+ continue
+ for val in eval(block):
+ meta = val['__meta__']
+ meta['sync'] = 's' if meta['sync'] else 'a'
+ key = "{action} {sync} {blocksize}k".format(**meta)
+ results.setdefault(key, []).append(val['bw_mean'])
+
+ processed_res = {}
+
+ for k, v in results.items():
+ v.sort()
+ med = float(sum(v)) / len(v)
+ ran = sum(abs(x - med) for x in v) / len(v)
+ processed_res[k] = (int(med), int(ran))
+
+ return processed_res
+
+
+def ksort(x):
+ op, sync, sz = x.split(" ")
+ return (op, sync, int(sz[:-1]))
+
+
+def show_data(path1, path2=None):
+ templ_1 = " {:>10} {:>5} {:>5} {:>6} ~ {:>5} {:>2}% {:>5}"
+ templ_2 = templ_1 + " {:>6} ~ {:>5} {:>2}% {:>5} ---- {:>6}% "
+
+ ln_1 = templ_1.replace("<", "^").replace(">", "^")
+ ln_1 = ln_1.format("Oper", "Sync", "BSZ", "BW1", "DEV1", "%", "IOPS1")
+
+ ln_2 = templ_2.replace("<", "^").replace(">", "^")
+ ln_2 = ln_2.format("Oper", "Sync", "BSZ", "BW1", "DEV1", "%",
+ "IOPS1", "BW2", "DEV2", "%", "IOPS2", "DIFF %")
+
+ sep_1 = '-' * len(ln_1)
+ sep_2 = '-' * len(ln_2)
+
+ res_1 = get_data_from_output(path1)
+
+ if path2 is None:
+ res_2 = None
+ sep = sep_1
+ ln = ln_1
+ templ = templ_1
+ else:
+ res_2 = get_data_from_output(path2)
+ sep = sep_2
+ ln = ln_2
+ templ = templ_2
+
+ print sep
+ print ln
+ print sep
+
+ prev_tp = None
+
+ common_keys = set(res_1.keys())
+
+ if res_2 is not None:
+ common_keys &= set(res_2.keys())
+
+ for k in sorted(common_keys, key=ksort):
+ tp = k.rsplit(" ", 1)[0]
+ op, s, sz = k.split(" ")
+ s = 'sync' if s == 's' else 'async'
+
+ if tp != prev_tp and prev_tp is not None:
+ print sep
+
+ prev_tp = tp
+
+ m1, d1 = res_1[k]
+ iops1 = m1 / int(sz[:-1])
+ perc1 = int(d1 * 100.0 / m1 + 0.5)
+
+ if res_2 is not None:
+ m2, d2 = res_2[k]
+ iops2 = m2 / int(sz[:-1])
+ perc2 = int(d2 * 100.0 / m2 + 0.5)
+ avg_diff = int(((m2 - m1) * 100.) / m2 + 0.5)
+
+ if res_2 is not None:
+ print templ.format(op, s, sz, m1, d1, perc1, iops1,
+ m2, d2, perc2, iops2, avg_diff)
+ else:
+ print templ.format(op, s, sz, m1, d1, perc1, iops1)
+
+ print sep
+
+
+def main(argv):
+ path1 = argv[0]
+ path2 = argv[1] if len(argv) > 1 else None
+ show_data(path1, path2)
+ return 0
+
+if __name__ == "__main__":
+ exit(main(sys.argv[1:]))
+# print " ", results[k]
diff --git a/data_generator.py b/data_generator.py
index b6373b1..096da3b 100644
--- a/data_generator.py
+++ b/data_generator.py
@@ -1,11 +1,11 @@
-import sys
import os
+import sys
import uuid
import random
import itertools
from petname import Generate as pet_generate
-from storage_api import create_storage, TEST_PATH
+from storage_api import create_storage
from report import ssize_to_kb
@@ -13,12 +13,11 @@
random.shuffle(types)
tp = itertools.cycle(types)
-sz = ["4k", "64k", "1m"]
+sz = ["1k", "4k", "64k", "256k", "1m"]
op_type = ["randread", "read", "randwrite", "write"]
is_sync = ["s", "a"]
-
-storage = create_storage("file://" + TEST_PATH + "/sample.json", "", "")
+storage = create_storage(sys.argv[1], "", "")
combinations = list(itertools.product(op_type, is_sync, sz))
for i in range(30):
diff --git a/io-scenario/io.py b/io-scenario/io.py
index 3b62967..8a3509a 100644
--- a/io-scenario/io.py
+++ b/io-scenario/io.py
@@ -142,7 +142,9 @@
def do_run_iozone(params, filename, timeout, iozone_path='iozone',
microsecond_mode=False):
- cmd = [iozone_path]
+ PATTERN = "\x6d"
+
+ cmd = [iozone_path, "-V", "109"]
if params.sync:
cmd.append('-o')
@@ -171,15 +173,22 @@
fsz = params.size
for fname in all_files:
- ccmd = [iozone_path, "-f", fname, "-i", "0",
- "-s", str(fsz), "-r", str(bsz), "-w"]
- subprocess.check_output(ccmd)
+ with open(fname, "wb") as fd:
+ if fsz > 1024:
+ pattern = PATTERN * 1024 * 1024
+ for _ in range(int(fsz / 1024) + 1):
+ fd.write(pattern)
+ else:
+ fd.write(PATTERN * 1024 * fsz)
+ fd.flush()
cmd.append('-i')
if params.action == 'write':
cmd.append("0")
- elif params.action == 'randwrite':
+ elif params.action == 'read':
+ cmd.append("1")
+ elif params.action == 'randwrite' or params.action == 'randread':
cmd.append("2")
else:
raise ValueError("Unknown action {0!r}".format(params.action))
@@ -206,14 +215,13 @@
elif params.action == 'randread':
res['bw_mean'] = parsed_res['random read']
except:
- print raw_res
raise
# res['bw_dev'] = 0
# res['bw_max'] = res["bw_mean"]
# res['bw_min'] = res["bw_mean"]
- return res
+ return res, " ".join(cmd)
def run_iozone(benchmark, iozone_path, tmpname, timeout=None):
@@ -221,7 +229,7 @@
benchmark.size = benchmark.blocksize * 50
res_time = do_run_iozone(benchmark, tmpname, timeout,
iozone_path=iozone_path,
- microsecond_mode=True)
+ microsecond_mode=True)[0]
size = (benchmark.blocksize * timeout * 1000000)
size /= res_time["bw_mean"]
@@ -252,8 +260,7 @@
if is_ubuntu or "Debian GNU/Linux" in os_release_cont:
subprocess.check_output(["apt-get", "install", "iozone3"])
return
- except (IOError, OSError) as exc:
- print exc
+ except (IOError, OSError):
pass
raise RuntimeError("Unknown host OS.")
@@ -308,11 +315,11 @@
cmd_line.append("--prio=0")
raw_out = subprocess.check_output(cmd_line)
- return json.loads(raw_out)["jobs"][0]
+ return json.loads(raw_out)["jobs"][0], " ".join(cmd_line)
def run_fio(benchmark, fio_path, tmpname, timeout=None):
- job_output = run_fio_once(benchmark, fio_path, tmpname, timeout)
+ job_output, cmd_line = run_fio_once(benchmark, fio_path, tmpname, timeout)
if benchmark.action in ('write', 'randwrite'):
raw_result = job_output['write']
@@ -325,11 +332,11 @@
for field in ["bw_mean"]:
res[field] = raw_result[field]
- return res
+ return res, cmd_line
def locate_fio():
- return False, None
+ return False, which('fio')
# ----------------------------------------------------------------------------
@@ -380,6 +387,22 @@
raise ValueError(msg)
+def type_size_ext(string):
+ if string.startswith("x"):
+ int(string[1:])
+ return string
+
+ if string.startswith("r"):
+ int(string[1:])
+ return string
+
+ try:
+ return re.match("\d+[KGBM]?", string, re.I).group(0)
+ except:
+ msg = "{0!r} don't looks like size-description string".format(string)
+ raise ValueError(msg)
+
+
def ssize_to_kb(ssize):
try:
smap = dict(k=1, K=1, M=1024, m=1024, G=1024**2, g=1024**2)
@@ -397,6 +420,19 @@
raise ValueError(tmpl.format(ssize))
+def get_ram_size():
+ try:
+ with open("/proc/meminfo") as fd:
+ for ln in fd:
+ if "MemTotal:" in ln:
+ sz, kb = ln.split(':')[1].strip().split(" ")
+ assert kb == 'kB'
+ return int(sz)
+ except (ValueError, TypeError, AssertionError):
+ raise
+ # return None
+
+
def parse_args(argv):
parser = argparse.ArgumentParser(
description="Run 'iozone' or 'fio' and return result")
@@ -417,7 +453,7 @@
"--timeout", metavar="TIMEOUT", type=int,
help="runtime of a single run", default=None)
parser.add_argument(
- "--iosize", metavar="SIZE", type=type_size,
+ "--iosize", metavar="SIZE", type=type_size_ext,
help="file size", default=None)
parser.add_argument(
"-s", "--sync", default=False, action="store_true",
@@ -445,7 +481,16 @@
argv_obj.blocksize = ssize_to_kb(argv_obj.blocksize)
if argv_obj.iosize is not None:
- argv_obj.iosize = ssize_to_kb(argv_obj.iosize)
+ if argv_obj.iosize.startswith('x'):
+ argv_obj.iosize = argv_obj.blocksize * int(argv_obj.iosize[1:])
+ elif argv_obj.iosize.startswith('r'):
+ rs = get_ram_size()
+ if rs is None:
+ sys.stderr.write("Can't determine ram size\n")
+ exit(1)
+ argv_obj.iosize = rs * int(argv_obj.iosize[1:])
+ else:
+ argv_obj.iosize = ssize_to_kb(argv_obj.iosize)
benchmark = BenchmarkOption(1,
argv_obj.iodepth,
@@ -469,6 +514,7 @@
argv_obj.binary_path)
if binary_path is None:
+ sys.stderr.write("Can't locate binary {0}\n".format(argv_obj.type))
return 1
try:
@@ -477,11 +523,12 @@
if dt > 0:
time.sleep(dt)
- res = run_benchmark(argv_obj.type,
- benchmark,
- binary_path,
- test_file_name)
- res['__meta__'] = benchmark.__dict__
+ res, cmd = run_benchmark(argv_obj.type,
+ benchmark,
+ binary_path,
+ test_file_name)
+ res['__meta__'] = benchmark.__dict__.copy()
+ res['__meta__']['cmdline'] = cmd
sys.stdout.write(json.dumps(res) + "\n")
finally:
if remove_binary:
@@ -500,7 +547,6 @@
# this line would be patched in case of run under rally
# don't modify it!
argvs = INSERT_TOOL_ARGS(sys.argv[1:])
-
code = 0
for argv in argvs:
tcode = main(argv)
diff --git a/io-scenario/io.yaml b/io-scenario/io.yaml
index df2bc51..deb4b99 100644
--- a/io-scenario/io.yaml
+++ b/io-scenario/io.yaml
@@ -2,7 +2,7 @@
-
args:
flavor:
- name: "m1.small"
+ name: "ceph.512"
image:
name: "ubuntu"
diff --git a/run.sh b/run.sh
new file mode 100644
index 0000000..342356e
--- /dev/null
+++ b/run.sh
@@ -0,0 +1,72 @@
+#!/bin/bash
+set -x
+set -e
+
+type="iozone"
+
+bsizes="1k 4k 64k 256k 1m"
+ops="write randwrite"
+osync="s a"
+three_times="1 2 3"
+
+for bsize in $bsizes ; do
+ for op in $ops ; do
+ for sync in $osync ; do
+ for xxx in $three_times ; do
+ if [[ "$ops" == "write" && "$osync" == "s" ]] ; then
+ continue
+ fi
+
+ if [[ "$sync" == "s" ]] ; then
+ ssync="-s"
+ factor="x500"
+ else
+ if [[ "$bsize" == "1k" || "$bsize" == "4k" ]] ; then
+ continue
+ fi
+
+ ssync=
+ factor="r2"
+ fi
+
+ io_opts="--type $type -a $op --iodepth 16 --blocksize $bsize --iosize $factor $ssync"
+ python run_rally_test.py -l -o "$io_opts" -t io-scenario $type --rally-extra-opts="--deployment $1"
+ done
+ done
+ done
+done
+
+# bsizes="4k 64k 256k 1m"
+# ops="randread read"
+
+# for bsize in $bsizes ; do
+# for op in $ops ; do
+# for xxx in $three_times ; do
+# io_opts="--type $type -a $op --iodepth 16 --blocksize $bsize --iosize r2"
+# python run_rally_test.py -l -o "$io_opts" -t io-scenario $type --rally-extra-opts="--deployment $1"
+# done
+# done
+# done
+
+# bsizes="1k 4k"
+# ops="randwrite write"
+# three_times="1 2 3"
+
+# for bsize in $bsizes ; do
+# for op in $ops ; do
+# for xxx in $three_times ; do
+# factor="r2"
+# io_opts="--type $type -a $op --iodepth 16 --blocksize $bsize --iosize $factor"
+# python run_rally_test.py -l -o "$io_opts" -t io-scenario $type --rally-extra-opts="--deployment $1"
+# done
+# done
+# done
+
+# ops="randread read"
+
+# for op in $ops ; do
+# for xxx in $three_times ; do
+# io_opts="--type $type -a $op --iodepth 16 --blocksize 1k --iosize r2"
+# python run_rally_test.py -l -o "$io_opts" -t io-scenario $type --rally-extra-opts="--deployment $1"
+# done
+# done
diff --git a/run_2.sh b/run_2.sh
new file mode 100644
index 0000000..566b1d5
--- /dev/null
+++ b/run_2.sh
@@ -0,0 +1,43 @@
+#!/bin/bash
+set -x
+set -e
+
+type="iozone"
+
+bsizes="1k 4k 64k 256k 1m"
+ops="randwrite write"
+osync="s a"
+three_times="1 2 3"
+
+for bsize in $bsizes ; do
+ for op in $ops ; do
+ for sync in $osync ; do
+ for xxx in $three_times ; do
+ if [[ "$sync" == "s" ]] ; then
+ ssync="-s"
+ factor="x500"
+ else
+ if [[ "$bsize" == "1k" || "$bsize" == "4k" ]] ; then
+ continue
+ fi
+
+ ssync=
+ factor="r2"
+ fi
+
+ python run_rally_test.py -l -o "--type $type -a $op --iodepth 16 --blocksize $bsize --iosize $factor $ssync" -t io-scenario $type --rally-extra-opts="--deployment perf-2"
+ done
+ done
+ done
+done
+
+bsizes="4k 64k 256k 1m"
+ops="randread read"
+
+for bsize in $bsizes ; do
+ for op in $ops ; do
+ for xxx in $three_times ; do
+ python run_rally_test.py -l -o "--type $type -a $op --iodepth 16 --blocksize $bsize --iosize r2" -t io-scenario $type --rally-extra-opts="--deployment perf-2"
+ done
+ done
+done
diff --git a/run_rally_test.py b/run_rally_test.py
index 3787da4..61fd4e7 100644
--- a/run_rally_test.py
+++ b/run_rally_test.py
@@ -185,7 +185,8 @@
def run_test(tool, testtool_py_args_v, dst_testtool_path, files_dir,
- rally_extra_opts, max_preparation_time=300):
+ rally_extra_opts, max_preparation_time=300,
+ keet_temp_files=False):
path = 'iozone' if 'iozone' == tool else 'fio'
testtool_local = os.path.join(files_dir, path)
@@ -219,8 +220,9 @@
return rally_result
finally:
- os.unlink(yaml_file)
- os.unlink(py_file)
+ if not keet_temp_files:
+ os.unlink(yaml_file)
+ os.unlink(py_file)
def parse_args(argv):
@@ -236,10 +238,13 @@
help="cmd line options for io.py")
parser.add_argument("-t", "--test-directory", help="directory with test",
dest="test_directory", required=True)
- parser.add_argument("rally_extra_opts", nargs="*",
- default=[], help="rally extra options")
parser.add_argument("--max-preparation-time", default=300,
type=int, dest="max_preparation_time")
+ parser.add_argument("-k", "--keep", default=False,
+ help="keep temporary files",
+ dest="keet_temp_files", action='store_true')
+ parser.add_argument("--rally-extra-opts", dest="rally_extra_opts",
+ default="", help="rally extra options")
return parser.parse_args(argv)
@@ -277,7 +282,10 @@
tt_argv.append('-s')
testtool_py_args_v.append(tt_argv)
else:
- testtool_py_args_v = [o.split(" ") for o in opts.io_opts]
+ testtool_py_args_v = []
+ for o in opts.io_opts:
+ ttopts = [opt.strip() for opt in o.split(" ") if opt.strip() != ""]
+ testtool_py_args_v.append(ttopts)
for io_argv_list in testtool_py_args_v:
io_argv_list.extend(['--binary-path', dst_testtool_path])
@@ -286,11 +294,33 @@
testtool_py_args_v,
dst_testtool_path,
files_dir=opts.test_directory,
- rally_extra_opts=opts.rally_extra_opts,
- max_preparation_time=opts.max_preparation_time)
+ rally_extra_opts=opts.rally_extra_opts.split(" "),
+ max_preparation_time=opts.max_preparation_time,
+ keet_temp_files=opts.keet_temp_files)
- print "Results = ",
- pprint.pprint(res)
+ print "=" * 80
+ print pprint.pformat(res)
+ print "=" * 80
+
+ if len(res) != 0:
+ bw_mean = 0.0
+ for measurement in res:
+ bw_mean += measurement["bw_mean"]
+
+ bw_mean /= len(res)
+
+ it = ((bw_mean - measurement["bw_mean"]) ** 2 for measurement in res)
+ bw_dev = sum(it) ** 0.5
+
+ meta = res[0]['__meta__']
+ key = "{0} {1} {2}k".format(meta['action'],
+ 's' if meta['sync'] else 'a',
+ meta['blocksize'])
+
+ print
+ print "====> " + json.dumps({key: (int(bw_mean), int(bw_dev))})
+ print
+ print "=" * 80
return 0
@@ -300,6 +330,8 @@
# glance image-create --name 'ubuntu' --disk-format qcow2
# --container-format bare --is-public true --copy-from
# https://cloud-images.ubuntu.com/trusty/current/trusty-server-cloudimg-amd64-disk1.img
+# nova flavor-create ceph.512 ceph.512 512 50 1
+# nova server-group-create --policy anti-affinity ceph
if __name__ == '__main__':
exit(main(sys.argv[1:]))
diff --git a/storage_api.py b/storage_api.py
index 026a46d..7841297 100644
--- a/storage_api.py
+++ b/storage_api.py
@@ -1,11 +1,12 @@
from urlparse import urlparse
# from gspread import WorksheetNotFound, login
+# from gspread import login
import json
import os
-from gspread import login, WorksheetNotFound
+# from gspread import login, WorksheetNotFound
from config import ROW_COUNT, DOCUMENT_ID, WORK_SHEET
-TEST_PATH = os.environ.get("TEST_PATH", os.path.dirname(__file__) + "/test_results")
+# TEST_PATH = os.environ.get("TEST_PATH", os.path.dirname(__file__) + "/test_results")
def get_work_sheet(sheet, name, column_names):
@@ -58,7 +59,6 @@
def create_storage(url, email=None, password=None):
u = urlparse(url)
-
if u.scheme == 'file':
storage = DiskStorage(u.path)
else:
@@ -187,6 +187,6 @@
return result
-if __name__ == "__main__":
- storage = create_storage("file:///home/gstepanov/rally-results-processor/sample.json", "", "")
- print storage.recent_builds()
+#if __name__ == "__main__":
+# storage = create_storage("file:///home/gstepanov/rally-results-processor/sample.json", "", "")
+# print storage.recent_builds()