Merge remote-tracking branch 'remotes/dgilbert-gitlab/tags/pull-virtiofs-20210315...
[qemu/ar7.git] / scripts / simplebench / bench_write_req.py
blobda601ea2fe508615fb63e07210032f6f4b4a4344
1 #!/usr/bin/env python3
3 # Test to compare performance of write requests for two qemu-img binary files.
5 # The idea of the test comes from intention to check the benefit of c8bb23cbdbe
6 # "qcow2: skip writing zero buffers to empty COW areas".
8 # Copyright (c) 2020 Virtuozzo International GmbH.
10 # This program is free software; you can redistribute it and/or modify
11 # it under the terms of the GNU General Public License as published by
12 # the Free Software Foundation; either version 2 of the License, or
13 # (at your option) any later version.
15 # This program is distributed in the hope that it will be useful,
16 # but WITHOUT ANY WARRANTY; without even the implied warranty of
17 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 # GNU General Public License for more details.
20 # You should have received a copy of the GNU General Public License
21 # along with this program. If not, see <http://www.gnu.org/licenses/>.
25 import sys
26 import os
27 import subprocess
28 import simplebench
29 from results_to_text import results_to_text
32 def bench_func(env, case):
33 """ Handle one "cell" of benchmarking table. """
34 return bench_write_req(env['qemu_img'], env['image_name'],
35 case['block_size'], case['block_offset'],
36 case['cluster_size'])
39 def qemu_img_pipe(*args):
40 '''Run qemu-img and return its output'''
41 subp = subprocess.Popen(list(args),
42 stdout=subprocess.PIPE,
43 stderr=subprocess.STDOUT,
44 universal_newlines=True)
45 exitcode = subp.wait()
46 if exitcode < 0:
47 sys.stderr.write('qemu-img received signal %i: %s\n'
48 % (-exitcode, ' '.join(list(args))))
49 return subp.communicate()[0]
52 def bench_write_req(qemu_img, image_name, block_size, block_offset,
53 cluster_size):
54 """Benchmark write requests
56 The function creates a QCOW2 image with the given path/name. Then it runs
57 the 'qemu-img bench' command and makes series of write requests on the
58 image clusters. Finally, it returns the total time of the write operations
59 on the disk.
61 qemu_img -- path to qemu_img executable file
62 image_name -- QCOW2 image name to create
63 block_size -- size of a block to write to clusters
64 block_offset -- offset of the block in clusters
65 cluster_size -- size of the image cluster
67 Returns {'seconds': int} on success and {'error': str} on failure.
68 Return value is compatible with simplebench lib.
69 """
71 if not os.path.isfile(qemu_img):
72 print(f'File not found: {qemu_img}')
73 sys.exit(1)
75 image_dir = os.path.dirname(os.path.abspath(image_name))
76 if not os.path.isdir(image_dir):
77 print(f'Path not found: {image_name}')
78 sys.exit(1)
80 image_size = 1024 * 1024 * 1024
82 args_create = [qemu_img, 'create', '-f', 'qcow2', '-o',
83 f'cluster_size={cluster_size}',
84 image_name, str(image_size)]
86 count = int(image_size / cluster_size) - 1
87 step = str(cluster_size)
89 args_bench = [qemu_img, 'bench', '-w', '-n', '-t', 'none', '-c',
90 str(count), '-s', f'{block_size}', '-o', str(block_offset),
91 '-S', step, '-f', 'qcow2', image_name]
93 try:
94 qemu_img_pipe(*args_create)
95 except OSError as e:
96 os.remove(image_name)
97 return {'error': 'qemu_img create failed: ' + str(e)}
99 try:
100 ret = qemu_img_pipe(*args_bench)
101 except OSError as e:
102 os.remove(image_name)
103 return {'error': 'qemu_img bench failed: ' + str(e)}
105 os.remove(image_name)
107 if 'seconds' in ret:
108 ret_list = ret.split()
109 index = ret_list.index('seconds.')
110 return {'seconds': float(ret_list[index-1])}
111 else:
112 return {'error': 'qemu_img bench failed: ' + ret}
115 if __name__ == '__main__':
117 if len(sys.argv) < 4:
118 program = os.path.basename(sys.argv[0])
119 print(f'USAGE: {program} <path to qemu-img binary file> '
120 '<path to another qemu-img to compare performance with> '
121 '<full or relative name for QCOW2 image to create>')
122 exit(1)
124 # Test-cases are "rows" in benchmark resulting table, 'id' is a caption
125 # for the row, other fields are handled by bench_func.
126 test_cases = [
128 'id': '<cluster front>',
129 'block_size': 4096,
130 'block_offset': 0,
131 'cluster_size': 1048576
134 'id': '<cluster middle>',
135 'block_size': 4096,
136 'block_offset': 524288,
137 'cluster_size': 1048576
140 'id': '<cross cluster>',
141 'block_size': 1048576,
142 'block_offset': 4096,
143 'cluster_size': 1048576
146 'id': '<cluster 64K>',
147 'block_size': 4096,
148 'block_offset': 0,
149 'cluster_size': 65536
153 # Test-envs are "columns" in benchmark resulting table, 'id is a caption
154 # for the column, other fields are handled by bench_func.
155 # Set the paths below to desired values
156 test_envs = [
158 'id': '<qemu-img binary 1>',
159 'qemu_img': f'{sys.argv[1]}',
160 'image_name': f'{sys.argv[3]}'
163 'id': '<qemu-img binary 2>',
164 'qemu_img': f'{sys.argv[2]}',
165 'image_name': f'{sys.argv[3]}'
169 result = simplebench.bench(bench_func, test_envs, test_cases, count=3,
170 initial_run=False)
171 print(results_to_text(result))