bench_prealloc.py 3.7 KB

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