2
0

img_bench_templater.py 3.3 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495
  1. #!/usr/bin/env python3
  2. #
  3. # Process img-bench test templates
  4. #
  5. # Copyright (c) 2021 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 subprocess
  22. import re
  23. import json
  24. import simplebench
  25. from results_to_text import results_to_text
  26. from table_templater import Templater
  27. def bench_func(env, case):
  28. test = templater.gen(env['data'], case['data'])
  29. p = subprocess.run(test, shell=True, stdout=subprocess.PIPE,
  30. stderr=subprocess.STDOUT, universal_newlines=True)
  31. if p.returncode == 0:
  32. try:
  33. m = re.search(r'Run completed in (\d+.\d+) seconds.', p.stdout)
  34. return {'seconds': float(m.group(1))}
  35. except Exception:
  36. return {'error': f'failed to parse qemu-img output: {p.stdout}'}
  37. else:
  38. return {'error': f'qemu-img failed: {p.returncode}: {p.stdout}'}
  39. if __name__ == '__main__':
  40. if len(sys.argv) > 1:
  41. print("""
  42. Usage: img_bench_templater.py < path/to/test-template.sh
  43. This script generates performance tests from a test template (example below),
  44. runs them, and displays the results in a table. The template is read from
  45. stdin. It must be written in bash and end with a `qemu-img bench` invocation
  46. (whose result is parsed to get the test instance’s result).
  47. Use the following syntax in the template to create the various different test
  48. instances:
  49. column templating: {var1|var2|...} - test will use different values in
  50. different columns. You may use several {} constructions in the test, in this
  51. case product of all choice-sets will be used.
  52. row templating: [var1|var2|...] - similar thing to define rows (test-cases)
  53. Test template example:
  54. Assume you want to compare two qemu-img binaries, called qemu-img-old and
  55. qemu-img-new in your build directory in two test-cases with 4K writes and 64K
  56. writes. The template may look like this:
  57. qemu_img=/path/to/qemu/build/qemu-img-{old|new}
  58. $qemu_img create -f qcow2 /ssd/x.qcow2 1G
  59. $qemu_img bench -c 100 -d 8 [-s 4K|-s 64K] -w -t none -n /ssd/x.qcow2
  60. When passing this to stdin of img_bench_templater.py, the resulting comparison
  61. table will contain two columns (for two binaries) and two rows (for two
  62. test-cases).
  63. In addition to displaying the results, script also stores results in JSON
  64. format into results.json file in current directory.
  65. """)
  66. sys.exit()
  67. templater = Templater(sys.stdin.read())
  68. envs = [{'id': ' / '.join(x), 'data': x} for x in templater.columns]
  69. cases = [{'id': ' / '.join(x), 'data': x} for x in templater.rows]
  70. result = simplebench.bench(bench_func, envs, cases, count=5,
  71. initial_run=False)
  72. print(results_to_text(result))
  73. with open('results.json', 'w') as f:
  74. json.dump(result, f, indent=4)