oe-build-perf-test 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  1. #!/usr/bin/python3
  2. #
  3. # Build performance test script
  4. #
  5. # Copyright (c) 2016, Intel Corporation.
  6. #
  7. # This program is free software; you can redistribute it and/or modify it
  8. # under the terms and conditions of the GNU General Public License,
  9. # version 2, as published by the Free Software Foundation.
  10. #
  11. # This program is distributed in the hope it will be useful, but WITHOUT
  12. # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13. # FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
  14. # more details.
  15. #
  16. """Build performance test script"""
  17. import argparse
  18. import errno
  19. import fcntl
  20. import logging
  21. import os
  22. import shutil
  23. import sys
  24. import unittest
  25. from datetime import datetime
  26. sys.path.insert(0, os.path.dirname(os.path.realpath(__file__)) + '/lib')
  27. import scriptpath
  28. scriptpath.add_oe_lib_path()
  29. import oeqa.buildperf
  30. from oeqa.buildperf import (BuildPerfTestLoader, BuildPerfTestResult,
  31. BuildPerfTestRunner, KernelDropCaches)
  32. from oeqa.utils.commands import runCmd
  33. # Set-up logging
  34. LOG_FORMAT = '[%(asctime)s] %(levelname)s: %(message)s'
  35. logging.basicConfig(level=logging.INFO, format=LOG_FORMAT,
  36. datefmt='%Y-%m-%d %H:%M:%S')
  37. log = logging.getLogger()
  38. def acquire_lock(lock_f):
  39. """Acquire flock on file"""
  40. log.debug("Acquiring lock %s", os.path.abspath(lock_f.name))
  41. try:
  42. fcntl.flock(lock_f, fcntl.LOCK_EX | fcntl.LOCK_NB)
  43. except IOError as err:
  44. if err.errno == errno.EAGAIN:
  45. return False
  46. raise
  47. log.debug("Lock acquired")
  48. return True
  49. def pre_run_sanity_check():
  50. """Sanity check of build environment"""
  51. build_dir = os.environ.get("BUILDDIR")
  52. if not build_dir:
  53. log.error("BUILDDIR not set. Please run the build environmnent setup "
  54. "script.")
  55. return False
  56. if os.getcwd() != build_dir:
  57. log.error("Please run this script under BUILDDIR (%s)", build_dir)
  58. return False
  59. ret = runCmd('which bitbake', ignore_status=True)
  60. if ret.status:
  61. log.error("bitbake command not found")
  62. return False
  63. return True
  64. def setup_file_logging(log_file):
  65. """Setup loggin to file"""
  66. log_dir = os.path.dirname(log_file)
  67. if not os.path.exists(log_dir):
  68. os.makedirs(log_dir)
  69. formatter = logging.Formatter(LOG_FORMAT)
  70. handler = logging.FileHandler(log_file)
  71. handler.setFormatter(formatter)
  72. log.addHandler(handler)
  73. def archive_build_conf(out_dir):
  74. """Archive build/conf to test results"""
  75. src_dir = os.path.join(os.environ['BUILDDIR'], 'conf')
  76. tgt_dir = os.path.join(out_dir, 'build', 'conf')
  77. os.makedirs(os.path.dirname(tgt_dir))
  78. shutil.copytree(src_dir, tgt_dir)
  79. def parse_args(argv):
  80. """Parse command line arguments"""
  81. parser = argparse.ArgumentParser(
  82. formatter_class=argparse.ArgumentDefaultsHelpFormatter)
  83. parser.add_argument('-D', '--debug', action='store_true',
  84. help='Enable debug level logging')
  85. parser.add_argument('--globalres-file',
  86. type=os.path.abspath,
  87. help="Append results to 'globalres' csv file")
  88. parser.add_argument('--lock-file', default='./oe-build-perf.lock',
  89. metavar='FILENAME', type=os.path.abspath,
  90. help="Lock file to use")
  91. parser.add_argument('-o', '--out-dir', default='results-{date}',
  92. type=os.path.abspath,
  93. help="Output directory for test results")
  94. parser.add_argument('--run-tests', nargs='+', metavar='TEST',
  95. help="List of tests to run")
  96. return parser.parse_args(argv)
  97. def main(argv=None):
  98. """Script entry point"""
  99. args = parse_args(argv)
  100. # Set-up log file
  101. out_dir = args.out_dir.format(date=datetime.now().strftime('%Y%m%d%H%M%S'))
  102. setup_file_logging(os.path.join(out_dir, 'output.log'))
  103. if args.debug:
  104. log.setLevel(logging.DEBUG)
  105. lock_f = open(args.lock_file, 'w')
  106. if not acquire_lock(lock_f):
  107. log.error("Another instance of this script is running, exiting...")
  108. return 1
  109. if not pre_run_sanity_check():
  110. return 1
  111. # Check our capability to drop caches and ask pass if needed
  112. KernelDropCaches.check()
  113. # Load build perf tests
  114. loader = BuildPerfTestLoader()
  115. if args.run_tests:
  116. suite = loader.loadTestsFromNames(args.run_tests, oeqa.buildperf)
  117. else:
  118. suite = loader.loadTestsFromModule(oeqa.buildperf)
  119. archive_build_conf(out_dir)
  120. runner = BuildPerfTestRunner(out_dir, verbosity=2)
  121. # Suppress logger output to stderr so that the output from unittest
  122. # is not mixed with occasional logger output
  123. log.handlers[0].setLevel(logging.CRITICAL)
  124. # Run actual tests
  125. result = runner.run(suite)
  126. # Restore logger output to stderr
  127. log.handlers[0].setLevel(log.level)
  128. if result.wasSuccessful():
  129. if args.globalres_file:
  130. result.update_globalres_file(args.globalres_file)
  131. return 0
  132. return 1
  133. if __name__ == '__main__':
  134. sys.exit(main())