1*cff6d3caSVladimir Sementsov-Ogievskiy#!/usr/bin/env python3 2*cff6d3caSVladimir Sementsov-Ogievskiy# 3*cff6d3caSVladimir Sementsov-Ogievskiy# Benchmark preallocate filter 4*cff6d3caSVladimir Sementsov-Ogievskiy# 5*cff6d3caSVladimir Sementsov-Ogievskiy# Copyright (c) 2020 Virtuozzo International GmbH. 6*cff6d3caSVladimir Sementsov-Ogievskiy# 7*cff6d3caSVladimir Sementsov-Ogievskiy# This program is free software; you can redistribute it and/or modify 8*cff6d3caSVladimir Sementsov-Ogievskiy# it under the terms of the GNU General Public License as published by 9*cff6d3caSVladimir Sementsov-Ogievskiy# the Free Software Foundation; either version 2 of the License, or 10*cff6d3caSVladimir Sementsov-Ogievskiy# (at your option) any later version. 11*cff6d3caSVladimir Sementsov-Ogievskiy# 12*cff6d3caSVladimir Sementsov-Ogievskiy# This program is distributed in the hope that it will be useful, 13*cff6d3caSVladimir Sementsov-Ogievskiy# but WITHOUT ANY WARRANTY; without even the implied warranty of 14*cff6d3caSVladimir Sementsov-Ogievskiy# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15*cff6d3caSVladimir Sementsov-Ogievskiy# GNU General Public License for more details. 16*cff6d3caSVladimir Sementsov-Ogievskiy# 17*cff6d3caSVladimir Sementsov-Ogievskiy# You should have received a copy of the GNU General Public License 18*cff6d3caSVladimir Sementsov-Ogievskiy# along with this program. If not, see <http://www.gnu.org/licenses/>. 19*cff6d3caSVladimir Sementsov-Ogievskiy# 20*cff6d3caSVladimir Sementsov-Ogievskiy 21*cff6d3caSVladimir Sementsov-Ogievskiy 22*cff6d3caSVladimir Sementsov-Ogievskiyimport sys 23*cff6d3caSVladimir Sementsov-Ogievskiyimport os 24*cff6d3caSVladimir Sementsov-Ogievskiyimport subprocess 25*cff6d3caSVladimir Sementsov-Ogievskiyimport re 26*cff6d3caSVladimir Sementsov-Ogievskiyimport json 27*cff6d3caSVladimir Sementsov-Ogievskiy 28*cff6d3caSVladimir Sementsov-Ogievskiyimport simplebench 29*cff6d3caSVladimir Sementsov-Ogievskiyfrom results_to_text import results_to_text 30*cff6d3caSVladimir Sementsov-Ogievskiy 31*cff6d3caSVladimir Sementsov-Ogievskiy 32*cff6d3caSVladimir Sementsov-Ogievskiydef qemu_img_bench(args): 33*cff6d3caSVladimir Sementsov-Ogievskiy p = subprocess.run(args, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, 34*cff6d3caSVladimir Sementsov-Ogievskiy universal_newlines=True) 35*cff6d3caSVladimir Sementsov-Ogievskiy 36*cff6d3caSVladimir Sementsov-Ogievskiy if p.returncode == 0: 37*cff6d3caSVladimir Sementsov-Ogievskiy try: 38*cff6d3caSVladimir Sementsov-Ogievskiy m = re.search(r'Run completed in (\d+.\d+) seconds.', p.stdout) 39*cff6d3caSVladimir Sementsov-Ogievskiy return {'seconds': float(m.group(1))} 40*cff6d3caSVladimir Sementsov-Ogievskiy except Exception: 41*cff6d3caSVladimir Sementsov-Ogievskiy return {'error': f'failed to parse qemu-img output: {p.stdout}'} 42*cff6d3caSVladimir Sementsov-Ogievskiy else: 43*cff6d3caSVladimir Sementsov-Ogievskiy return {'error': f'qemu-img failed: {p.returncode}: {p.stdout}'} 44*cff6d3caSVladimir Sementsov-Ogievskiy 45*cff6d3caSVladimir Sementsov-Ogievskiy 46*cff6d3caSVladimir Sementsov-Ogievskiydef bench_func(env, case): 47*cff6d3caSVladimir Sementsov-Ogievskiy fname = f"{case['dir']}/prealloc-test.qcow2" 48*cff6d3caSVladimir Sementsov-Ogievskiy try: 49*cff6d3caSVladimir Sementsov-Ogievskiy os.remove(fname) 50*cff6d3caSVladimir Sementsov-Ogievskiy except OSError: 51*cff6d3caSVladimir Sementsov-Ogievskiy pass 52*cff6d3caSVladimir Sementsov-Ogievskiy 53*cff6d3caSVladimir Sementsov-Ogievskiy subprocess.run([env['qemu-img-binary'], 'create', '-f', 'qcow2', fname, 54*cff6d3caSVladimir Sementsov-Ogievskiy '16G'], stdout=subprocess.DEVNULL, 55*cff6d3caSVladimir Sementsov-Ogievskiy stderr=subprocess.DEVNULL, check=True) 56*cff6d3caSVladimir Sementsov-Ogievskiy 57*cff6d3caSVladimir Sementsov-Ogievskiy args = [env['qemu-img-binary'], 'bench', '-c', str(case['count']), 58*cff6d3caSVladimir Sementsov-Ogievskiy '-d', '64', '-s', case['block-size'], '-t', 'none', '-n', '-w'] 59*cff6d3caSVladimir Sementsov-Ogievskiy if env['prealloc']: 60*cff6d3caSVladimir Sementsov-Ogievskiy args += ['--image-opts', 61*cff6d3caSVladimir Sementsov-Ogievskiy 'driver=qcow2,file.driver=preallocate,file.file.driver=file,' 62*cff6d3caSVladimir Sementsov-Ogievskiy f'file.file.filename={fname}'] 63*cff6d3caSVladimir Sementsov-Ogievskiy else: 64*cff6d3caSVladimir Sementsov-Ogievskiy args += ['-f', 'qcow2', fname] 65*cff6d3caSVladimir Sementsov-Ogievskiy 66*cff6d3caSVladimir Sementsov-Ogievskiy return qemu_img_bench(args) 67*cff6d3caSVladimir Sementsov-Ogievskiy 68*cff6d3caSVladimir Sementsov-Ogievskiy 69*cff6d3caSVladimir Sementsov-Ogievskiydef auto_count_bench_func(env, case): 70*cff6d3caSVladimir Sementsov-Ogievskiy case['count'] = 100 71*cff6d3caSVladimir Sementsov-Ogievskiy while True: 72*cff6d3caSVladimir Sementsov-Ogievskiy res = bench_func(env, case) 73*cff6d3caSVladimir Sementsov-Ogievskiy if 'error' in res: 74*cff6d3caSVladimir Sementsov-Ogievskiy return res 75*cff6d3caSVladimir Sementsov-Ogievskiy 76*cff6d3caSVladimir Sementsov-Ogievskiy if res['seconds'] >= 1: 77*cff6d3caSVladimir Sementsov-Ogievskiy break 78*cff6d3caSVladimir Sementsov-Ogievskiy 79*cff6d3caSVladimir Sementsov-Ogievskiy case['count'] *= 10 80*cff6d3caSVladimir Sementsov-Ogievskiy 81*cff6d3caSVladimir Sementsov-Ogievskiy if res['seconds'] < 5: 82*cff6d3caSVladimir Sementsov-Ogievskiy case['count'] = round(case['count'] * 5 / res['seconds']) 83*cff6d3caSVladimir Sementsov-Ogievskiy res = bench_func(env, case) 84*cff6d3caSVladimir Sementsov-Ogievskiy if 'error' in res: 85*cff6d3caSVladimir Sementsov-Ogievskiy return res 86*cff6d3caSVladimir Sementsov-Ogievskiy 87*cff6d3caSVladimir Sementsov-Ogievskiy res['iops'] = case['count'] / res['seconds'] 88*cff6d3caSVladimir Sementsov-Ogievskiy return res 89*cff6d3caSVladimir Sementsov-Ogievskiy 90*cff6d3caSVladimir Sementsov-Ogievskiy 91*cff6d3caSVladimir Sementsov-Ogievskiyif __name__ == '__main__': 92*cff6d3caSVladimir Sementsov-Ogievskiy if len(sys.argv) < 2: 93*cff6d3caSVladimir Sementsov-Ogievskiy print(f'USAGE: {sys.argv[0]} <qemu-img binary> ' 94*cff6d3caSVladimir Sementsov-Ogievskiy 'DISK_NAME:DIR_PATH ...') 95*cff6d3caSVladimir Sementsov-Ogievskiy exit(1) 96*cff6d3caSVladimir Sementsov-Ogievskiy 97*cff6d3caSVladimir Sementsov-Ogievskiy qemu_img = sys.argv[1] 98*cff6d3caSVladimir Sementsov-Ogievskiy 99*cff6d3caSVladimir Sementsov-Ogievskiy envs = [ 100*cff6d3caSVladimir Sementsov-Ogievskiy { 101*cff6d3caSVladimir Sementsov-Ogievskiy 'id': 'no-prealloc', 102*cff6d3caSVladimir Sementsov-Ogievskiy 'qemu-img-binary': qemu_img, 103*cff6d3caSVladimir Sementsov-Ogievskiy 'prealloc': False 104*cff6d3caSVladimir Sementsov-Ogievskiy }, 105*cff6d3caSVladimir Sementsov-Ogievskiy { 106*cff6d3caSVladimir Sementsov-Ogievskiy 'id': 'prealloc', 107*cff6d3caSVladimir Sementsov-Ogievskiy 'qemu-img-binary': qemu_img, 108*cff6d3caSVladimir Sementsov-Ogievskiy 'prealloc': True 109*cff6d3caSVladimir Sementsov-Ogievskiy } 110*cff6d3caSVladimir Sementsov-Ogievskiy ] 111*cff6d3caSVladimir Sementsov-Ogievskiy 112*cff6d3caSVladimir Sementsov-Ogievskiy aligned_cases = [] 113*cff6d3caSVladimir Sementsov-Ogievskiy unaligned_cases = [] 114*cff6d3caSVladimir Sementsov-Ogievskiy 115*cff6d3caSVladimir Sementsov-Ogievskiy for disk in sys.argv[2:]: 116*cff6d3caSVladimir Sementsov-Ogievskiy name, path = disk.split(':') 117*cff6d3caSVladimir Sementsov-Ogievskiy aligned_cases.append({ 118*cff6d3caSVladimir Sementsov-Ogievskiy 'id': f'{name}, aligned sequential 16k', 119*cff6d3caSVladimir Sementsov-Ogievskiy 'block-size': '16k', 120*cff6d3caSVladimir Sementsov-Ogievskiy 'dir': path 121*cff6d3caSVladimir Sementsov-Ogievskiy }) 122*cff6d3caSVladimir Sementsov-Ogievskiy unaligned_cases.append({ 123*cff6d3caSVladimir Sementsov-Ogievskiy 'id': f'{name}, unaligned sequential 64k', 124*cff6d3caSVladimir Sementsov-Ogievskiy 'block-size': '16k', 125*cff6d3caSVladimir Sementsov-Ogievskiy 'dir': path 126*cff6d3caSVladimir Sementsov-Ogievskiy }) 127*cff6d3caSVladimir Sementsov-Ogievskiy 128*cff6d3caSVladimir Sementsov-Ogievskiy result = simplebench.bench(auto_count_bench_func, envs, 129*cff6d3caSVladimir Sementsov-Ogievskiy aligned_cases + unaligned_cases, count=5) 130*cff6d3caSVladimir Sementsov-Ogievskiy print(results_to_text(result)) 131*cff6d3caSVladimir Sementsov-Ogievskiy with open('results.json', 'w') as f: 132*cff6d3caSVladimir Sementsov-Ogievskiy json.dump(result, f, indent=4) 133