replay_kernel.py 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110
  1. # Record/replay test that boots a Linux kernel
  2. #
  3. # Copyright (c) 2020 ISP RAS
  4. #
  5. # Author:
  6. # Pavel Dovgalyuk <Pavel.Dovgaluk@ispras.ru>
  7. #
  8. # This work is licensed under the terms of the GNU GPL, version 2 or
  9. # later. See the COPYING file in the top-level directory.
  10. import os
  11. import lzma
  12. import shutil
  13. import logging
  14. import time
  15. import subprocess
  16. from avocado import skip
  17. from avocado import skipUnless
  18. from avocado import skipUnless
  19. from avocado_qemu import wait_for_console_pattern
  20. from avocado.utils import archive
  21. from avocado.utils import process
  22. from boot_linux_console import LinuxKernelTest
  23. class ReplayKernelBase(LinuxKernelTest):
  24. """
  25. Boots a Linux kernel in record mode and checks that the console
  26. is operational and the kernel command line is properly passed
  27. from QEMU to the kernel.
  28. Then replays the same scenario and verifies, that QEMU correctly
  29. terminates.
  30. """
  31. timeout = 180
  32. KERNEL_COMMON_COMMAND_LINE = 'printk.time=1 panic=-1 '
  33. def run_vm(self, kernel_path, kernel_command_line, console_pattern,
  34. record, shift, args, replay_path):
  35. # icount requires TCG to be available
  36. self.require_accelerator('tcg')
  37. logger = logging.getLogger('replay')
  38. start_time = time.time()
  39. vm = self.get_vm()
  40. vm.set_console()
  41. if record:
  42. logger.info('recording the execution...')
  43. mode = 'record'
  44. else:
  45. logger.info('replaying the execution...')
  46. mode = 'replay'
  47. vm.add_args('-icount', 'shift=%s,rr=%s,rrfile=%s' %
  48. (shift, mode, replay_path),
  49. '-kernel', kernel_path,
  50. '-append', kernel_command_line,
  51. '-net', 'none',
  52. '-no-reboot')
  53. if args:
  54. vm.add_args(*args)
  55. vm.launch()
  56. self.wait_for_console_pattern(console_pattern, vm)
  57. if record:
  58. vm.shutdown()
  59. logger.info('finished the recording with log size %s bytes'
  60. % os.path.getsize(replay_path))
  61. self.run_replay_dump(replay_path)
  62. logger.info('successfully tested replay-dump.py')
  63. else:
  64. vm.wait()
  65. logger.info('successfully finished the replay')
  66. elapsed = time.time() - start_time
  67. logger.info('elapsed time %.2f sec' % elapsed)
  68. return elapsed
  69. def run_replay_dump(self, replay_path):
  70. try:
  71. subprocess.check_call(["./scripts/replay-dump.py",
  72. "-f", replay_path],
  73. stdout=subprocess.DEVNULL)
  74. except subprocess.CalledProcessError:
  75. self.fail('replay-dump.py failed')
  76. def run_rr(self, kernel_path, kernel_command_line, console_pattern,
  77. shift=7, args=None):
  78. replay_path = os.path.join(self.workdir, 'replay.bin')
  79. t1 = self.run_vm(kernel_path, kernel_command_line, console_pattern,
  80. True, shift, args, replay_path)
  81. t2 = self.run_vm(kernel_path, kernel_command_line, console_pattern,
  82. False, shift, args, replay_path)
  83. logger = logging.getLogger('replay')
  84. logger.info('replay overhead {:.2%}'.format(t2 / t1 - 1))
  85. class ReplayKernelNormal(ReplayKernelBase):
  86. def test_i386_pc(self):
  87. """
  88. :avocado: tags=arch:i386
  89. :avocado: tags=machine:pc
  90. """
  91. kernel_url = ('https://storage.tuxboot.com/20230331/i386/bzImage')
  92. kernel_hash = 'a3e5b32a354729e65910f5a1ffcda7c14a6c12a55e8213fb86e277f1b76ed956'
  93. kernel_path = self.fetch_asset(kernel_url,
  94. asset_hash=kernel_hash,
  95. algorithm = "sha256")
  96. kernel_command_line = self.KERNEL_COMMON_COMMAND_LINE + 'console=ttyS0'
  97. console_pattern = 'VFS: Cannot open root device'
  98. self.run_rr(kernel_path, kernel_command_line, console_pattern, shift=5)