123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171 |
- #!/usr/bin/env python3
- #
- # Test to compare performance of write requests for two qemu-img binary files.
- #
- # The idea of the test comes from intention to check the benefit of c8bb23cbdbe
- # "qcow2: skip writing zero buffers to empty COW areas".
- #
- # Copyright (c) 2020 Virtuozzo International GmbH.
- #
- # This program is free software; you can redistribute it and/or modify
- # it under the terms of the GNU General Public License as published by
- # the Free Software Foundation; either version 2 of the License, or
- # (at your option) any later version.
- #
- # This program is distributed in the hope that it will be useful,
- # but WITHOUT ANY WARRANTY; without even the implied warranty of
- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- # GNU General Public License for more details.
- #
- # You should have received a copy of the GNU General Public License
- # along with this program. If not, see <http://www.gnu.org/licenses/>.
- #
- import sys
- import os
- import subprocess
- import simplebench
- from results_to_text import results_to_text
- def bench_func(env, case):
- """ Handle one "cell" of benchmarking table. """
- return bench_write_req(env['qemu_img'], env['image_name'],
- case['block_size'], case['block_offset'],
- case['cluster_size'])
- def qemu_img_pipe(*args):
- '''Run qemu-img and return its output'''
- subp = subprocess.Popen(list(args),
- stdout=subprocess.PIPE,
- stderr=subprocess.STDOUT,
- universal_newlines=True)
- exitcode = subp.wait()
- if exitcode < 0:
- sys.stderr.write('qemu-img received signal %i: %s\n'
- % (-exitcode, ' '.join(list(args))))
- return subp.communicate()[0]
- def bench_write_req(qemu_img, image_name, block_size, block_offset,
- cluster_size):
- """Benchmark write requests
- The function creates a QCOW2 image with the given path/name. Then it runs
- the 'qemu-img bench' command and makes series of write requests on the
- image clusters. Finally, it returns the total time of the write operations
- on the disk.
- qemu_img -- path to qemu_img executable file
- image_name -- QCOW2 image name to create
- block_size -- size of a block to write to clusters
- block_offset -- offset of the block in clusters
- cluster_size -- size of the image cluster
- Returns {'seconds': int} on success and {'error': str} on failure.
- Return value is compatible with simplebench lib.
- """
- if not os.path.isfile(qemu_img):
- print(f'File not found: {qemu_img}')
- sys.exit(1)
- image_dir = os.path.dirname(os.path.abspath(image_name))
- if not os.path.isdir(image_dir):
- print(f'Path not found: {image_name}')
- sys.exit(1)
- image_size = 1024 * 1024 * 1024
- args_create = [qemu_img, 'create', '-f', 'qcow2', '-o',
- f'cluster_size={cluster_size}',
- image_name, str(image_size)]
- count = int(image_size / cluster_size) - 1
- step = str(cluster_size)
- args_bench = [qemu_img, 'bench', '-w', '-n', '-t', 'none', '-c',
- str(count), '-s', f'{block_size}', '-o', str(block_offset),
- '-S', step, '-f', 'qcow2', image_name]
- try:
- qemu_img_pipe(*args_create)
- except OSError as e:
- os.remove(image_name)
- return {'error': 'qemu_img create failed: ' + str(e)}
- try:
- ret = qemu_img_pipe(*args_bench)
- except OSError as e:
- os.remove(image_name)
- return {'error': 'qemu_img bench failed: ' + str(e)}
- os.remove(image_name)
- if 'seconds' in ret:
- ret_list = ret.split()
- index = ret_list.index('seconds.')
- return {'seconds': float(ret_list[index-1])}
- else:
- return {'error': 'qemu_img bench failed: ' + ret}
- if __name__ == '__main__':
- if len(sys.argv) < 4:
- program = os.path.basename(sys.argv[0])
- print(f'USAGE: {program} <path to qemu-img binary file> '
- '<path to another qemu-img to compare performance with> '
- '<full or relative name for QCOW2 image to create>')
- exit(1)
- # Test-cases are "rows" in benchmark resulting table, 'id' is a caption
- # for the row, other fields are handled by bench_func.
- test_cases = [
- {
- 'id': '<cluster front>',
- 'block_size': 4096,
- 'block_offset': 0,
- 'cluster_size': 1048576
- },
- {
- 'id': '<cluster middle>',
- 'block_size': 4096,
- 'block_offset': 524288,
- 'cluster_size': 1048576
- },
- {
- 'id': '<cross cluster>',
- 'block_size': 1048576,
- '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(results_to_text(result))
|