run-tests.py 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  1. #!/usr/bin/env python
  2. import argparse
  3. import ConfigParser
  4. import sys
  5. import os
  6. import multiprocessing
  7. import subprocess
  8. from pprint import pprint
  9. from benchmark.benchmarker import Benchmarker
  10. from setup.linux.unbuffered import Unbuffered
  11. from setup.linux import setup_util
  12. ###################################################################################################
  13. # Main
  14. ###################################################################################################
  15. def main(argv=None):
  16. ''' Runs the program. There are three ways to pass arguments
  17. 1) environment variables TFB_*
  18. 2) configuration file benchmark.cfg
  19. 3) command line flags
  20. In terms of precedence, 3 > 2 > 1, so config file trumps environment variables
  21. but command line flags have the final say
  22. '''
  23. # Do argv default this way, as doing it in the functional declaration sets it at compile time
  24. if argv is None:
  25. argv = sys.argv
  26. # Enable unbuffered output so messages will appear in the proper order with subprocess output.
  27. sys.stdout=Unbuffered(sys.stdout)
  28. # Update python environment
  29. # 1) Ensure the current directory (which should be the benchmark home directory) is in the path so that the tests can be imported.
  30. sys.path.append('.')
  31. # 2) Ensure toolset/setup/linux is in the path so that the tests can "import setup_util".
  32. sys.path.append('toolset/setup/linux')
  33. # Update environment for shell scripts
  34. fwroot = setup_util.get_fwroot()
  35. if not fwroot:
  36. fwroot = os.getcwd()
  37. setup_util.replace_environ(config='config/benchmark_profile', root=fwroot)
  38. print "FWROOT is %s"%setup_util.get_fwroot()
  39. conf_parser = argparse.ArgumentParser(
  40. description=__doc__,
  41. formatter_class=argparse.RawDescriptionHelpFormatter,
  42. add_help=False)
  43. conf_parser.add_argument('--conf_file', default='benchmark.cfg', metavar='FILE', help='Optional configuration file to provide argument defaults. All config options can be overridden using the command line.')
  44. args, remaining_argv = conf_parser.parse_known_args()
  45. try:
  46. with open (args.conf_file):
  47. config = ConfigParser.SafeConfigParser()
  48. config.read([os.getcwd() + '/' + args.conf_file])
  49. defaults = dict(config.items("Defaults"))
  50. except IOError:
  51. if args.conf_file != 'benchmark.cfg':
  52. print 'Configuration file not found!'
  53. defaults = { "client-host":"localhost"}
  54. ##########################################################
  55. # Set up default values
  56. ##########################################################
  57. serverHost = os.environ.get('TFB_SERVER_HOST')
  58. clientHost = os.environ.get('TFB_CLIENT_HOST')
  59. clientUser = os.environ.get('TFB_CLIENT_USER')
  60. clientIden = os.environ.get('TFB_CLIENT_IDENTITY_FILE')
  61. databaHost = os.getenv('TFB_DATABASE_HOST', clientHost)
  62. databaUser = os.getenv('TFB_DATABASE_USER', clientUser)
  63. dbIdenFile = os.getenv('TFB_DATABASE_IDENTITY_FILE', clientIden)
  64. maxThreads = 8
  65. try:
  66. maxThreads = multiprocessing.cpu_count()
  67. except:
  68. pass
  69. ##########################################################
  70. # Set up argument parser
  71. ##########################################################
  72. parser = argparse.ArgumentParser(description='Run the Framework Benchmarking test suite.',
  73. parents=[conf_parser],
  74. formatter_class=argparse.ArgumentDefaultsHelpFormatter)
  75. # SSH options
  76. parser.add_argument('-s', '--server-host', default=serverHost, help='The application server.')
  77. parser.add_argument('-c', '--client-host', default=clientHost, help='The client / load generation server.')
  78. parser.add_argument('-u', '--client-user', default=clientUser, help='The username to use for SSH to the client instance.')
  79. parser.add_argument('-i', '--client-identity-file', dest='client_identity_file', default=clientIden,
  80. help='The key to use for SSH to the client instance.')
  81. parser.add_argument('-d', '--database-host', default=databaHost,
  82. help='The database server. If not provided, defaults to the value of --client-host.')
  83. parser.add_argument('--database-user', default=databaUser,
  84. help='The username to use for SSH to the database instance. If not provided, defaults to the value of --client-user.')
  85. parser.add_argument('--database-identity-file', default=dbIdenFile, dest='database_identity_file',
  86. help='The key to use for SSH to the database instance. If not provided, defaults to the value of --client-identity-file.')
  87. parser.add_argument('-p', dest='password_prompt', action='store_true', help='Prompt for password')
  88. # Install options
  89. parser.add_argument('--install', choices=['client', 'database', 'server', 'all'], default=None,
  90. help='Runs installation script(s) before continuing on to execute the tests.')
  91. parser.add_argument('--install-error-action', choices=['abort', 'continue'], default='continue', help='action to take in case of error during installation')
  92. parser.add_argument('--install-strategy', choices=['unified', 'pertest'], default='pertest',
  93. help='''Affects `--install server`: With unified, all server software is installed into a single directory.
  94. With pertest each test gets its own installs directory, but installation takes longer''')
  95. # Test options
  96. parser.add_argument('--test', nargs='+', help='names of tests to run')
  97. parser.add_argument('--exclude', nargs='+', help='names of tests to exclude')
  98. parser.add_argument('--type', choices=['all', 'json', 'db', 'query', 'fortune', 'update', 'plaintext'], default='all', help='which type of test to run')
  99. parser.add_argument('-m', '--mode', choices=['benchmark', 'verify'], default='benchmark', help='verify mode will only start up the tests, curl the urls and shutdown')
  100. parser.add_argument('--list-tests', action='store_true', default=False, help='lists all the known tests that can run')
  101. parser.add_argument('--list-test-metadata', action='store_true', default=False, help='writes all the test metadata as a JSON file in the results directory')
  102. parser.add_argument('--name', default="ec2", help='The name to give this test. Results will be placed in a folder using this name.')
  103. parser.add_argument('--os', choices=['linux', 'windows'], default='linux', help='The operating system of the application/framework server (the one running' +
  104. 'this binary')
  105. parser.add_argument('--database-os', choices=['linux', 'windows'], default='linux', help='The operating system of the database server.')
  106. # Benchmark options
  107. parser.add_argument('--max-concurrency', default=256, help='the maximum number of HTTP connections that wrk will keep open. The query tests will run at this maximum', type=int)
  108. parser.add_argument('--max-queries', default=20, help='The maximum number of queries to run during the query test', type=int)
  109. parser.add_argument('--query-interval', default=5, type=int, help='Query tests will go from 1 query to max queries in increments of interval queries')
  110. parser.add_argument('--max-threads', default=maxThreads, help='The max number of threads to run wrk at. This should be set to the number of cores for your client system.', type=int)
  111. parser.add_argument('--duration', default=15, help='Time in seconds that each test should run for.')
  112. parser.add_argument('--starting-concurrency', default=8, type=int)
  113. parser.add_argument('--sleep', type=int, default=60, help='the amount of time to sleep after starting each test to allow the server to start up.')
  114. # Misc Options
  115. parser.add_argument('--parse', help='Parses the results of the given timestamp and merges that with the latest results')
  116. parser.add_argument('-v', '--verbose', action='store_true', default=False, help='Causes the configuration to print before any other commands are executed.')
  117. parser.set_defaults(**defaults) # Must do this after add, or each option's default will override the configuration file default
  118. args = parser.parse_args(remaining_argv)
  119. # Verify and massage options
  120. if args.client_user is None:
  121. print 'Usernames (e.g. --client-user and --database-user) are required!'
  122. print 'The system will SSH into the client and the database for the install stage'
  123. print 'Aborting'
  124. exit(1)
  125. if args.database_user is None:
  126. args.database_user = args.client_user
  127. if args.database_host is None:
  128. args.database_host = args.client_host
  129. if args.verbose:
  130. print 'Configuration options: '
  131. pprint(args)
  132. benchmarker = Benchmarker(vars(args))
  133. # Run the benchmarker in the specified mode
  134. if benchmarker.list_tests:
  135. benchmarker.run_list_tests()
  136. elif benchmarker.list_test_metadata:
  137. benchmarker.run_list_test_metadata()
  138. elif benchmarker.parse != None:
  139. benchmarker.parse_timestamp()
  140. else:
  141. return benchmarker.run()
  142. if __name__ == "__main__":
  143. sys.exit(main())