benchmark_ci.py 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  1. #!/usr/bin/env python3
  2. # Copyright (c) 2011-present, Facebook, Inc. All rights reserved.
  3. # This source code is licensed under both the GPLv2 (found in the
  4. # COPYING file in the root directory) and Apache 2.0 License
  5. # (found in the LICENSE.Apache file in the root directory).
  6. """Run benchmark_compare.sh on the most recent build, for CI
  7. """
  8. import argparse
  9. import glob
  10. import logging
  11. import os
  12. import re
  13. import shutil
  14. import subprocess
  15. import sys
  16. logging.basicConfig(level=logging.INFO)
  17. class Config:
  18. def __init__(self, args):
  19. self.version_file = "./include/rocksdb/version.h"
  20. self.data_dir = os.path.expanduser(f"{args.db_dir}")
  21. self.results_dir = os.path.expanduser(f"{args.output_dir}")
  22. self.benchmark_script = f"{os.getcwd()}/tools/benchmark_compare.sh"
  23. self.benchmark_cwd = f"{os.getcwd()}/tools"
  24. benchmark_env_keys = [
  25. "LD_LIBRARY_PATH",
  26. "NUM_KEYS",
  27. "KEY_SIZE",
  28. "VALUE_SIZE",
  29. "CACHE_SIZE_MB",
  30. "DURATION_RW",
  31. "DURATION_RO",
  32. "MB_WRITE_PER_SEC",
  33. "NUM_THREADS",
  34. "COMPRESSION_TYPE",
  35. "MIN_LEVEL_TO_COMPRESS",
  36. "WRITE_BUFFER_SIZE_MB",
  37. "TARGET_FILE_SIZE_BASE_MB",
  38. "MAX_BYTES_FOR_LEVEL_BASE_MB",
  39. "MAX_BACKGROUND_JOBS",
  40. "CACHE_INDEX_AND_FILTER_BLOCKS",
  41. "USE_O_DIRECT",
  42. "STATS_INTERVAL_SECONDS",
  43. "SUBCOMPACTIONS",
  44. "COMPACTION_STYLE",
  45. "CI_TESTS_ONLY",
  46. ]
  47. def read_version(config):
  48. majorRegex = re.compile(r"#define ROCKSDB_MAJOR\s([0-9]+)")
  49. minorRegex = re.compile(r"#define ROCKSDB_MINOR\s([0-9]+)")
  50. patchRegex = re.compile(r"#define ROCKSDB_PATCH\s([0-9]+)")
  51. with open(config.version_file) as reader:
  52. major = None
  53. minor = None
  54. patch = None
  55. for line in reader:
  56. if major is None:
  57. major = majorRegex.match(line)
  58. elif minor is None:
  59. minor = minorRegex.match(line)
  60. elif patch is None:
  61. patch = patchRegex.match(line)
  62. if patch is not None:
  63. break
  64. if patch is not None:
  65. return (major.group(1), minor.group(1), patch.group(1))
  66. # Didn't complete a match
  67. return None
  68. def prepare(version_str, config):
  69. old_files = glob.glob(f"{config.results_dir}/{version_str}/**", recursive=True)
  70. for f in old_files:
  71. if os.path.isfile(f):
  72. logging.debug(f"remove file {f}")
  73. os.remove(f)
  74. for f in old_files:
  75. if os.path.isdir(f):
  76. logging.debug(f"remove dir {f}")
  77. os.rmdir(f)
  78. db_bench_vers = f"{config.benchmark_cwd}/db_bench.{version_str}"
  79. # Create a symlink to the db_bench executable
  80. os.symlink(f"{os.getcwd()}/db_bench", db_bench_vers)
  81. def results(version_str, config):
  82. # Copy the report TSV file back to the top level of results
  83. shutil.copyfile(
  84. f"{config.results_dir}/{version_str}/report.tsv",
  85. f"{config.results_dir}/report.tsv",
  86. )
  87. def cleanup(version_str, config):
  88. # Remove the symlink to the db_bench executable
  89. db_bench_vers = f"{config.benchmark_cwd}/db_bench.{version_str}"
  90. os.remove(db_bench_vers)
  91. def get_benchmark_env():
  92. env = []
  93. for key in Config.benchmark_env_keys:
  94. value = os.getenv(key)
  95. if value is not None:
  96. env.append((key, value))
  97. return env
  98. def main():
  99. """Tool for running benchmark_compare.sh on the most recent build, for CI
  100. This tool will
  101. (1) Work out the current version of RocksDB
  102. (2) Run benchmark_compare with that version alone
  103. """
  104. parser = argparse.ArgumentParser(
  105. description="benchmark_compare.sh Python wrapper for CI."
  106. )
  107. # --tsvfile is the name of the file to read results from
  108. # --esdocument is the ElasticSearch document to push these results into
  109. #
  110. parser.add_argument(
  111. "--db_dir",
  112. default="~/tmp/rocksdb-benchmark-datadir",
  113. help="Database directory hierarchy to use",
  114. )
  115. parser.add_argument(
  116. "--output_dir",
  117. default="~/tmp/benchmark-results",
  118. help="Benchmark output goes here",
  119. )
  120. parser.add_argument(
  121. "--num_keys",
  122. default="10000",
  123. help="Number of database keys to use in benchmark test(s) (determines size of test job)",
  124. )
  125. args = parser.parse_args()
  126. config = Config(args)
  127. version = read_version(config)
  128. if version is None:
  129. raise Exception(f"Could not read RocksDB version from {config.version_file}")
  130. version_str = f"{version[0]}.{version[1]}.{version[2]}"
  131. logging.info(f"Run benchmark_ci with RocksDB version {version_str}")
  132. prepare(version_str, config)
  133. try:
  134. env = get_benchmark_env()
  135. env.append(("NUM_KEYS", args.num_keys))
  136. cmd = [
  137. config.benchmark_script,
  138. config.data_dir,
  139. config.results_dir,
  140. version_str,
  141. ]
  142. logging.info(f"Run {cmd} env={env} cwd={config.benchmark_cwd}")
  143. subprocess.run(cmd, env=dict(env), cwd=config.benchmark_cwd)
  144. results(version_str, config)
  145. finally:
  146. cleanup(version_str, config)
  147. return 0
  148. if __name__ == "__main__":
  149. sys.exit(main())