1*5b3f7daaSVladimir Sementsov-Ogievskiy#!/usr/bin/env python3 2*5b3f7daaSVladimir Sementsov-Ogievskiy# 3*5b3f7daaSVladimir Sementsov-Ogievskiy# Process img-bench test templates 4*5b3f7daaSVladimir Sementsov-Ogievskiy# 5*5b3f7daaSVladimir Sementsov-Ogievskiy# Copyright (c) 2021 Virtuozzo International GmbH. 6*5b3f7daaSVladimir Sementsov-Ogievskiy# 7*5b3f7daaSVladimir Sementsov-Ogievskiy# This program is free software; you can redistribute it and/or modify 8*5b3f7daaSVladimir Sementsov-Ogievskiy# it under the terms of the GNU General Public License as published by 9*5b3f7daaSVladimir Sementsov-Ogievskiy# the Free Software Foundation; either version 2 of the License, or 10*5b3f7daaSVladimir Sementsov-Ogievskiy# (at your option) any later version. 11*5b3f7daaSVladimir Sementsov-Ogievskiy# 12*5b3f7daaSVladimir Sementsov-Ogievskiy# This program is distributed in the hope that it will be useful, 13*5b3f7daaSVladimir Sementsov-Ogievskiy# but WITHOUT ANY WARRANTY; without even the implied warranty of 14*5b3f7daaSVladimir Sementsov-Ogievskiy# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15*5b3f7daaSVladimir Sementsov-Ogievskiy# GNU General Public License for more details. 16*5b3f7daaSVladimir Sementsov-Ogievskiy# 17*5b3f7daaSVladimir Sementsov-Ogievskiy# You should have received a copy of the GNU General Public License 18*5b3f7daaSVladimir Sementsov-Ogievskiy# along with this program. If not, see <http://www.gnu.org/licenses/>. 19*5b3f7daaSVladimir Sementsov-Ogievskiy# 20*5b3f7daaSVladimir Sementsov-Ogievskiy 21*5b3f7daaSVladimir Sementsov-Ogievskiy 22*5b3f7daaSVladimir Sementsov-Ogievskiyimport sys 23*5b3f7daaSVladimir Sementsov-Ogievskiyimport subprocess 24*5b3f7daaSVladimir Sementsov-Ogievskiyimport re 25*5b3f7daaSVladimir Sementsov-Ogievskiyimport json 26*5b3f7daaSVladimir Sementsov-Ogievskiy 27*5b3f7daaSVladimir Sementsov-Ogievskiyimport simplebench 28*5b3f7daaSVladimir Sementsov-Ogievskiyfrom results_to_text import results_to_text 29*5b3f7daaSVladimir Sementsov-Ogievskiyfrom table_templater import Templater 30*5b3f7daaSVladimir Sementsov-Ogievskiy 31*5b3f7daaSVladimir Sementsov-Ogievskiy 32*5b3f7daaSVladimir Sementsov-Ogievskiydef bench_func(env, case): 33*5b3f7daaSVladimir Sementsov-Ogievskiy test = templater.gen(env['data'], case['data']) 34*5b3f7daaSVladimir Sementsov-Ogievskiy 35*5b3f7daaSVladimir Sementsov-Ogievskiy p = subprocess.run(test, shell=True, stdout=subprocess.PIPE, 36*5b3f7daaSVladimir Sementsov-Ogievskiy stderr=subprocess.STDOUT, universal_newlines=True) 37*5b3f7daaSVladimir Sementsov-Ogievskiy 38*5b3f7daaSVladimir Sementsov-Ogievskiy if p.returncode == 0: 39*5b3f7daaSVladimir Sementsov-Ogievskiy try: 40*5b3f7daaSVladimir Sementsov-Ogievskiy m = re.search(r'Run completed in (\d+.\d+) seconds.', p.stdout) 41*5b3f7daaSVladimir Sementsov-Ogievskiy return {'seconds': float(m.group(1))} 42*5b3f7daaSVladimir Sementsov-Ogievskiy except Exception: 43*5b3f7daaSVladimir Sementsov-Ogievskiy return {'error': f'failed to parse qemu-img output: {p.stdout}'} 44*5b3f7daaSVladimir Sementsov-Ogievskiy else: 45*5b3f7daaSVladimir Sementsov-Ogievskiy return {'error': f'qemu-img failed: {p.returncode}: {p.stdout}'} 46*5b3f7daaSVladimir Sementsov-Ogievskiy 47*5b3f7daaSVladimir Sementsov-Ogievskiy 48*5b3f7daaSVladimir Sementsov-Ogievskiyif __name__ == '__main__': 49*5b3f7daaSVladimir Sementsov-Ogievskiy if len(sys.argv) > 1: 50*5b3f7daaSVladimir Sementsov-Ogievskiy print(""" 51*5b3f7daaSVladimir Sementsov-OgievskiyUsage: img_bench_templater.py < path/to/test-template.sh 52*5b3f7daaSVladimir Sementsov-Ogievskiy 53*5b3f7daaSVladimir Sementsov-OgievskiyThis script generates performance tests from a test template (example below), 54*5b3f7daaSVladimir Sementsov-Ogievskiyruns them, and displays the results in a table. The template is read from 55*5b3f7daaSVladimir Sementsov-Ogievskiystdin. It must be written in bash and end with a `qemu-img bench` invocation 56*5b3f7daaSVladimir Sementsov-Ogievskiy(whose result is parsed to get the test instance’s result). 57*5b3f7daaSVladimir Sementsov-Ogievskiy 58*5b3f7daaSVladimir Sementsov-OgievskiyUse the following syntax in the template to create the various different test 59*5b3f7daaSVladimir Sementsov-Ogievskiyinstances: 60*5b3f7daaSVladimir Sementsov-Ogievskiy 61*5b3f7daaSVladimir Sementsov-Ogievskiy column templating: {var1|var2|...} - test will use different values in 62*5b3f7daaSVladimir Sementsov-Ogievskiy different columns. You may use several {} constructions in the test, in this 63*5b3f7daaSVladimir Sementsov-Ogievskiy case product of all choice-sets will be used. 64*5b3f7daaSVladimir Sementsov-Ogievskiy 65*5b3f7daaSVladimir Sementsov-Ogievskiy row templating: [var1|var2|...] - similar thing to define rows (test-cases) 66*5b3f7daaSVladimir Sementsov-Ogievskiy 67*5b3f7daaSVladimir Sementsov-OgievskiyTest template example: 68*5b3f7daaSVladimir Sementsov-Ogievskiy 69*5b3f7daaSVladimir Sementsov-OgievskiyAssume you want to compare two qemu-img binaries, called qemu-img-old and 70*5b3f7daaSVladimir Sementsov-Ogievskiyqemu-img-new in your build directory in two test-cases with 4K writes and 64K 71*5b3f7daaSVladimir Sementsov-Ogievskiywrites. The template may look like this: 72*5b3f7daaSVladimir Sementsov-Ogievskiy 73*5b3f7daaSVladimir Sementsov-Ogievskiyqemu_img=/path/to/qemu/build/qemu-img-{old|new} 74*5b3f7daaSVladimir Sementsov-Ogievskiy$qemu_img create -f qcow2 /ssd/x.qcow2 1G 75*5b3f7daaSVladimir Sementsov-Ogievskiy$qemu_img bench -c 100 -d 8 [-s 4K|-s 64K] -w -t none -n /ssd/x.qcow2 76*5b3f7daaSVladimir Sementsov-Ogievskiy 77*5b3f7daaSVladimir Sementsov-OgievskiyWhen passing this to stdin of img_bench_templater.py, the resulting comparison 78*5b3f7daaSVladimir Sementsov-Ogievskiytable will contain two columns (for two binaries) and two rows (for two 79*5b3f7daaSVladimir Sementsov-Ogievskiytest-cases). 80*5b3f7daaSVladimir Sementsov-Ogievskiy 81*5b3f7daaSVladimir Sementsov-OgievskiyIn addition to displaying the results, script also stores results in JSON 82*5b3f7daaSVladimir Sementsov-Ogievskiyformat into results.json file in current directory. 83*5b3f7daaSVladimir Sementsov-Ogievskiy""") 84*5b3f7daaSVladimir Sementsov-Ogievskiy sys.exit() 85*5b3f7daaSVladimir Sementsov-Ogievskiy 86*5b3f7daaSVladimir Sementsov-Ogievskiy templater = Templater(sys.stdin.read()) 87*5b3f7daaSVladimir Sementsov-Ogievskiy 88*5b3f7daaSVladimir Sementsov-Ogievskiy envs = [{'id': ' / '.join(x), 'data': x} for x in templater.columns] 89*5b3f7daaSVladimir Sementsov-Ogievskiy cases = [{'id': ' / '.join(x), 'data': x} for x in templater.rows] 90*5b3f7daaSVladimir Sementsov-Ogievskiy 91*5b3f7daaSVladimir Sementsov-Ogievskiy result = simplebench.bench(bench_func, envs, cases, count=5, 92*5b3f7daaSVladimir Sementsov-Ogievskiy initial_run=False) 93*5b3f7daaSVladimir Sementsov-Ogievskiy print(results_to_text(result)) 94*5b3f7daaSVladimir Sementsov-Ogievskiy with open('results.json', 'w') as f: 95*5b3f7daaSVladimir Sementsov-Ogievskiy json.dump(result, f, indent=4) 96