'block_offset': 4096, 'cluster_size': 1048576 }, { 'id': '<cluster 64K>', 'block_size': 4096, 'block_offset': 0, 'cluster_size': 65536 }, ] # Test-envs are "columns" in benchmark resulting table, 'id is a caption # for the column, other fields are handled by bench_func. # Set the paths below to desired values test_envs = [ { 'id': '<qemu-img binary 1>', 'qemu_img': f'{sys.argv[1]}', 'image_name': f'{sys.argv[3]}' }, { 'id': '<qemu-img binary 2>', 'qemu_img': f'{sys.argv[2]}', 'image_name': f'{sys.argv[3]}' }, ] result = simplebench.bench(bench_func, test_envs, test_cases, count=3, initial_run=False) print(simplebench.ascii(result))
def bench(args): test_cases = [] sources = {} targets = {} for d in args.dir: label, path = d.split(':') # paths with colon not supported sources[label] = drv_file(path + '/test-source') targets[label] = drv_file(path + '/test-target') if args.nbd: nbd = args.nbd.split(':') host = nbd[0] port = '10809' if len(nbd) == 1 else nbd[1] drv = drv_nbd(host, port) sources['nbd'] = drv targets['nbd'] = drv for t in args.test: src, dst = t.split(':') test_cases.append({ 'id': t, 'source': sources[src], 'target': targets[dst] }) binaries = [] # list of (<label>, <path>, [<options>]) for i, q in enumerate(args.env): name_path = q.split(':') if len(name_path) == 1: label = f'q{i}' path_opts = name_path[0].split(',') else: assert len(name_path) == 2 # paths with colon not supported label = name_path[0] path_opts = name_path[1].split(',') binaries.append((label, path_opts[0], path_opts[1:])) test_envs = [] bin_paths = {} for i, q in enumerate(args.env): opts = q.split(',') label_path = opts[0] opts = opts[1:] if ':' in label_path: # path with colon inside is not supported label, path = label_path.split(':') bin_paths[label] = path elif label_path in bin_paths: label = label_path path = bin_paths[label] else: path = label_path label = f'q{i}' bin_paths[label] = path x_perf = {} is_mirror = False for opt in opts: if opt == 'mirror': is_mirror = True elif opt == 'copy-range=on': x_perf['use-copy-range'] = True elif opt == 'copy-range=off': x_perf['use-copy-range'] = False elif opt.startswith('max-workers='): x_perf['max-workers'] = int(opt.split('=')[1]) if is_mirror: assert not x_perf test_envs.append({ 'id': f'mirror({label})', 'cmd': 'blockdev-mirror', 'qemu-binary': path }) else: test_envs.append({ 'id': f'backup({label})\n' + '\n'.join(opts), 'cmd': 'blockdev-backup', 'cmd-options': { 'x-perf': x_perf } if x_perf else {}, 'qemu-binary': path }) result = simplebench.bench(bench_func, test_envs, test_cases, count=3) with open('results.json', 'w') as f: json.dump(result, f, indent=4) print(results_to_text(result))
Assume you want to compare two qemu-img binaries, called qemu-img-old and qemu-img-new in your build directory in two test-cases with 4K writes and 64K writes. The template may look like this: qemu_img=/path/to/qemu/build/qemu-img-{old|new} $qemu_img create -f qcow2 /ssd/x.qcow2 1G $qemu_img bench -c 100 -d 8 [-s 4K|-s 64K] -w -t none -n /ssd/x.qcow2 When passing this to stdin of img_bench_templater.py, the resulting comparison table will contain two columns (for two binaries) and two rows (for two test-cases). In addition to displaying the results, script also stores results in JSON format into results.json file in current directory. """) sys.exit() templater = Templater(sys.stdin.read()) envs = [{'id': ' / '.join(x), 'data': x} for x in templater.columns] cases = [{'id': ' / '.join(x), 'data': x} for x in templater.rows] result = simplebench.bench(bench_func, envs, cases, count=5, initial_run=False) print(results_to_text(result)) with open('results.json', 'w') as f: json.dump(result, f, indent=4)
{ 'id': 'ssd -> hdd', 'source': drv_file(ssd_source), 'target': drv_file(hdd_target) }, { 'id': 'ssd -> nbd', 'source': drv_file(ssd_source), 'target': drv_nbd(nbd_ip, nbd_port) }, ] # Test-envs are "columns" in benchmark resulting table, 'id is a caption for # the column, other fields are handled by bench_func. test_envs = [{ 'id': 'backup-1', 'cmd': 'blockdev-backup', 'qemu_binary': '/path-to-qemu-binary-1' }, { 'id': 'backup-2', 'cmd': 'blockdev-backup', 'qemu_binary': '/path-to-qemu-binary-2' }, { 'id': 'mirror', 'cmd': 'blockdev-mirror', 'qemu_binary': '/path-to-qemu-binary-1' }] result = simplebench.bench(bench_func, test_envs, test_cases, count=3) print(simplebench.ascii(result))
'prealloc': False }, { 'id': 'prealloc', 'qemu-img-binary': qemu_img, 'prealloc': True }] aligned_cases = [] unaligned_cases = [] for disk in sys.argv[2:]: name, path = disk.split(':') aligned_cases.append({ 'id': f'{name}, aligned sequential 16k', 'block-size': '16k', 'dir': path }) unaligned_cases.append({ 'id': f'{name}, unaligned sequential 64k', 'block-size': '16k', 'dir': path }) result = simplebench.bench(auto_count_bench_func, envs, aligned_cases + unaligned_cases, count=5) print(results_to_text(result)) with open('results.json', 'w') as f: json.dump(result, f, indent=4)
def bench(args): test_cases = [] # paths with colon not supported, so we just split by ':' dirs = dict(d.split(':') for d in args.dir) nbd_drv = None if args.nbd: nbd = args.nbd.split(':') host = nbd[0] port = '10809' if len(nbd) == 1 else nbd[1] nbd_drv = drv_nbd(host, port) for t in args.test: src, dst = t.split(':') if src == 'nbd' and dst == 'nbd': raise ValueError("Can't use 'nbd' label for both src and dst") if (src == 'nbd' or dst == 'nbd') and not nbd_drv: raise ValueError("'nbd' label used but --nbd is not given") if src == 'nbd': source = nbd_drv elif args.qcow2_sources: source = drv_qcow2(drv_file(dirs[src] + '/test-source.qcow2')) else: source = drv_file(dirs[src] + '/test-source') if dst == 'nbd': test_cases.append({'id': t, 'source': source, 'target': nbd_drv}) continue if args.target_cache == 'both': target_caches = ['direct', 'cached'] else: target_caches = [args.target_cache] for c in target_caches: o_direct = c == 'direct' fname = dirs[dst] + '/test-target' if args.compressed: fname += '.qcow2' target = drv_file(fname, o_direct=o_direct) if args.compressed: target = drv_qcow2(target) test_id = t if args.target_cache == 'both': test_id += f'({c})' test_cases.append({ 'id': test_id, 'source': source, 'target': target }) binaries = [] # list of (<label>, <path>, [<options>]) for i, q in enumerate(args.env): name_path = q.split(':') if len(name_path) == 1: label = f'q{i}' path_opts = name_path[0].split(',') else: assert len(name_path) == 2 # paths with colon not supported label = name_path[0] path_opts = name_path[1].split(',') binaries.append((label, path_opts[0], path_opts[1:])) test_envs = [] bin_paths = {} for i, q in enumerate(args.env): opts = q.split(',') label_path = opts[0] opts = opts[1:] if ':' in label_path: # path with colon inside is not supported label, path = label_path.split(':') bin_paths[label] = path elif label_path in bin_paths: label = label_path path = bin_paths[label] else: path = label_path label = f'q{i}' bin_paths[label] = path x_perf = {} is_mirror = False for opt in opts: if opt == 'mirror': is_mirror = True elif opt == 'copy-range=on': x_perf['use-copy-range'] = True elif opt == 'copy-range=off': x_perf['use-copy-range'] = False elif opt.startswith('max-workers='): x_perf['max-workers'] = int(opt.split('=')[1]) backup_options = {} if x_perf: backup_options['x-perf'] = x_perf if args.compressed: backup_options['compress'] = True if is_mirror: assert not x_perf test_envs.append({ 'id': f'mirror({label})', 'cmd': 'blockdev-mirror', 'qemu-binary': path }) else: test_envs.append({ 'id': f'backup({label})\n' + '\n'.join(opts), 'cmd': 'blockdev-backup', 'cmd-options': backup_options, 'qemu-binary': path }) result = simplebench.bench(bench_func, test_envs, test_cases, count=args.count, initial_run=args.initial_run, drop_caches=args.drop_caches) with open('results.json', 'w') as f: json.dump(result, f, indent=4) print(results_to_text(result))