b1a79aa01b
PiperOrigin-RevId: 476492651 Change-Id: I310a21a73a65da3a5939f5cb8a1c8a67c8595863
218 lines
7.4 KiB
Python
Executable File
218 lines
7.4 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
# Copyright 2021 DeepMind Technologies Limited
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
# you may not use this file except in compliance with the License.
|
|
# You may obtain a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
# See the License for the specific language governing permissions and
|
|
# limitations under the License.
|
|
|
|
"""A script for running step_benchmark_test for a variety of build settings."""
|
|
|
|
import argparse
|
|
import os
|
|
import re
|
|
import shutil
|
|
import subprocess
|
|
import sys
|
|
from typing import NamedTuple, Tuple
|
|
|
|
|
|
class _Setting(NamedTuple):
|
|
name: str
|
|
cmake_args: Tuple[str]
|
|
|
|
|
|
def run_benchmark_variants(output_directory: str, build_directory: str,
|
|
benchmark_repetitions: int, delete_build: bool):
|
|
"""Builds different variants of the benchmark test, and runs them."""
|
|
# For each of the settings, the first option is what we use as a baseline.
|
|
# We chose to pick the settings that were likely best (so this is an ablation
|
|
# study), so interactions between settings are tested.
|
|
settings_ranges = {
|
|
"avx": [
|
|
_Setting("on", ("-DMUJOCO_ENABLE_AVX=ON",)),
|
|
_Setting("off", ("-DMUJOCO_ENABLE_AVX=OFF",))
|
|
],
|
|
"avx_intrinsics": [
|
|
_Setting("on", ("-DMUJOCO_ENABLE_AVX_INTRINSICS=ON",)),
|
|
_Setting("off", ("-DMUJOCO_ENABLE_AVX_INTRINSICS=OFF",))
|
|
],
|
|
"lto": [
|
|
_Setting("on", ("-DCMAKE_INTERPROCEDURAL_OPTIMIZATION=ON",)),
|
|
_Setting("off", ("-DCMAKE_INTERPROCEDURAL_OPTIMIZATION=OFF",)),
|
|
],
|
|
"compiler": compiler_cmake_flags_variants(),
|
|
}
|
|
|
|
baseline_settings = {
|
|
key: value[0] for key, value in settings_ranges.items()
|
|
}
|
|
run_benchmark(
|
|
f"{sys.platform}_baseline",
|
|
baseline_settings,
|
|
output_directory=output_directory,
|
|
build_directory=f"{build_directory}_baseline",
|
|
benchmark_repetitions=benchmark_repetitions,
|
|
delete_build=delete_build,
|
|
)
|
|
|
|
for key in sorted(settings_ranges):
|
|
settings = baseline_settings.copy()
|
|
for setting in settings_ranges[key][1:]:
|
|
settings[key] = setting
|
|
run_benchmark(
|
|
f"{sys.platform}_{key}_{setting.name}",
|
|
settings,
|
|
output_directory=output_directory,
|
|
build_directory=f"{build_directory}_{key}_{setting.name}",
|
|
benchmark_repetitions=benchmark_repetitions,
|
|
delete_build=delete_build,
|
|
)
|
|
|
|
|
|
def run_benchmark(name, settings, output_directory: str, build_directory: str,
|
|
benchmark_repetitions: int, delete_build: bool):
|
|
"""Builds and runs a single benchmark."""
|
|
current_dir = os.getcwd()
|
|
try:
|
|
if delete_build:
|
|
shutil.rmtree(build_directory, ignore_errors=True)
|
|
os.makedirs(build_directory, exist_ok=True)
|
|
os.makedirs(output_directory, exist_ok=True)
|
|
os.chdir(build_directory)
|
|
cmake_args = [
|
|
"cmake", "..", "-DMUJOCO_BUILD_TESTS=ON", "-DCMAKE_BUILD_TYPE=Release"
|
|
]
|
|
cmake_args.extend(os_specific_cmake_flags())
|
|
for _, setting in sorted(settings.items()):
|
|
cmake_args.extend(setting.cmake_args)
|
|
|
|
print(f"Running ({name}):", " ".join(cmake_args))
|
|
subprocess.check_call(cmake_args)
|
|
subprocess.check_call([
|
|
"cmake", "--build", ".", "-j8", "--config=Release", "-t",
|
|
"step_benchmark_test"
|
|
])
|
|
output_path = os.path.join(output_directory, f"{name}.json")
|
|
|
|
os.chdir("../mujoco/test")
|
|
if sys.platform == "win32":
|
|
cygwin_run_benchmark(build_directory, output_path, benchmark_repetitions)
|
|
else:
|
|
binary_path = os.path.join(build_directory, "bin", "step_benchmark_test")
|
|
subprocess.check_call([
|
|
binary_path,
|
|
"--benchmark_filter=all",
|
|
"--benchmark_enable_random_interleaving=true",
|
|
"--benchmark_min_time=0.5",
|
|
f"--benchmark_repetitions={benchmark_repetitions}",
|
|
"--benchmark_format=json",
|
|
f"--benchmark_out={output_path}",
|
|
])
|
|
finally:
|
|
os.chdir(current_dir)
|
|
|
|
|
|
def os_specific_cmake_flags():
|
|
"""CMake args that should be passed to all benchmarks on current OS."""
|
|
if sys.platform == "win32":
|
|
return ("-A", "x64", "-Thost=x86",
|
|
"-DCMAKE_MSVC_RUNTIME_LIBRARY=MultiThreaded",
|
|
"-DCMAKE_SYSTEM_VERSION=10.0.19041.0")
|
|
elif sys.platform.startswith("linux"):
|
|
return ()
|
|
elif sys.platform == "darwin":
|
|
# macOS
|
|
return ()
|
|
else:
|
|
raise ValueError(f"Unknown OS: {sys.platform}")
|
|
|
|
|
|
def compiler_cmake_flags_variants():
|
|
"""Returns a list of benchmark settings for different compilers."""
|
|
if sys.platform == "win32":
|
|
return [
|
|
_Setting("VS2022", ("-G", "Visual Studio 17 2022")),
|
|
# MSVC 2017 doesn't seem to support C17 standard.
|
|
# _Setting("VS2017", ("-G", "Visual Studio 15 2017")),
|
|
]
|
|
elif sys.platform.startswith("linux"):
|
|
return [
|
|
_Setting("clang-11",
|
|
("-DCMAKE_C_COMPILER=clang-11",
|
|
"-DCMAKE_CXX_COMPILER=clang++-11", "-DCMAKE_LINKER=lld-11")),
|
|
_Setting("clang-8",
|
|
("-DCMAKE_C_COMPILER=clang-8",
|
|
"-DCMAKE_CXX_COMPILER=clang++-8", "-DCMAKE_LINKER=lld-8")),
|
|
]
|
|
elif sys.platform == "darwin":
|
|
# macOS
|
|
return [_Setting("clang", ())]
|
|
else:
|
|
raise ValueError(f"Unknown OS: {sys.platform}")
|
|
|
|
|
|
def cygwin_run_benchmark(build_directory, output_path, benchmark_repetitions):
|
|
"""Runs the benchmark command under the cygwin environment."""
|
|
# The subprocess module interacts badly with cygwin.
|
|
# Rather than trying to run the binary directly through Popen, use bash on
|
|
# cygwin.
|
|
lib_path = cygwin_path(os.path.join(build_directory, "lib", "Release"))
|
|
binary_path = cygwin_path(
|
|
os.path.join(build_directory, "bin", "Release",
|
|
"step_benchmark_test"))
|
|
cygwin = subprocess.Popen(["bash"], stdin=subprocess.PIPE)
|
|
command = (
|
|
f'PATH="$PATH:{lib_path}" {binary_path} --benchmark_filter=all '
|
|
"--benchmark_enable_random_interleaving=true ",
|
|
"--benchmark_min_time=0.5 "
|
|
f"--benchmark_repetitions={benchmark_repetitions} "
|
|
"--benchmark_format=json "
|
|
f"--benchmark_out='{output_path}'")
|
|
cygwin.communicate(input=bytes(command, "utf-8"))
|
|
if cygwin.returncode:
|
|
raise ValueError(f"Benchmark returned error code: {cygwin.returncode}")
|
|
|
|
|
|
def cygwin_path(windows_path):
|
|
path = windows_path.replace("\\", "/")
|
|
path = re.sub(r".*cygwin64", "", path)
|
|
return path
|
|
|
|
|
|
def main(argv):
|
|
parser = argparse.ArgumentParser()
|
|
parser.add_argument("-o", "--output_directory", default="benchmark_results")
|
|
parser.add_argument(
|
|
"-b",
|
|
"--build_directory",
|
|
default="build",
|
|
help="Base path for build directories. Benchmark names will be appended."
|
|
)
|
|
parser.add_argument("-n", "--repetitions", type=int, default=30)
|
|
parser.add_argument(
|
|
"-d",
|
|
"--delete_build",
|
|
nargs="?",
|
|
type=bool,
|
|
const=True,
|
|
default=False,
|
|
help="Delete the build directory before building benchmark.")
|
|
args = parser.parse_args(argv[1:])
|
|
run_benchmark_variants(
|
|
output_directory=os.path.abspath(args.output_directory),
|
|
build_directory=os.path.abspath(args.build_directory),
|
|
delete_build=args.delete_build,
|
|
benchmark_repetitions=args.repetitions)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main(sys.argv)
|