From 7b4b6da3838b27d3f8fa1206a05e9785268ff7ee Mon Sep 17 00:00:00 2001 From: Jeremy Nimmer Date: Thu, 5 May 2022 10:32:52 -0700 Subject: [PATCH] [tools] Add opt-in build flags (and unit test) for OpenMP At the moment '--config omp' is not covered by CI. Soon it will become part of the "Everything" builds. --- common/BUILD.bazel | 15 ++++++ common/test/openmp_test.cc | 55 ++++++++++++++++++++ doc/_pages/bazel.md | 19 +++++++ tools/ubuntu-focal.bazelrc | 5 ++ tools/workspace/libcmaes/package.BUILD.bazel | 1 + tools/workspace/scs/package.BUILD.bazel | 1 + 6 files changed, 96 insertions(+) create mode 100644 common/test/openmp_test.cc diff --git a/common/BUILD.bazel b/common/BUILD.bazel index 351fa1a9d52f..e2e3bea0655f 100644 --- a/common/BUILD.bazel +++ b/common/BUILD.bazel @@ -1105,6 +1105,21 @@ drake_cc_googletest( ], ) +drake_cc_googletest( + name = "openmp_test", + # TODO(jwnimmer-tri) Encapsulate unit test concurrency configuration into + # Drake's starlark macros, so that we don't have to repeat ourselves here. + env = { + "OMP_NUM_THREADS": "2", + }, + tags = [ + "cpu:2", + ], + deps = [ + "//common:essential", + ], +) + drake_cc_googletest( name = "polynomial_test", deps = [ diff --git a/common/test/openmp_test.cc b/common/test/openmp_test.cc new file mode 100644 index 000000000000..ca89e69a43f8 --- /dev/null +++ b/common/test/openmp_test.cc @@ -0,0 +1,55 @@ +#include +#include + +#include +#include + +#if defined(_OPENMP) +#include +#endif + +#include "drake/common/text_logging.h" + +namespace drake { +namespace { + +#if defined(_OPENMP) +constexpr bool kHasOpenmp = true; +#else +constexpr bool kHasOpenmp = false; +// TODO(jwnimmer-tri) This should be a Drake helper function wrapper that +// abstracts away this difference. The openmp_helpers.hpp wrapper from +// common_robotics_utilities is a likely candidate to delegate to, or at +// least take as inspiration. +int omp_get_thread_num() { return 0; } +#endif + +// Mostly, this just checks for compilation failures. +GTEST_TEST(OpenmpTest, ParallelFor) { + drake::log()->info("Using kHasOpenmp = {}", kHasOpenmp); + + // Allocate storage for one integer result per loop. + constexpr int num_outputs = 100; + std::vector outputs(static_cast(num_outputs), 0); + + // Populate the storage, in parallel. +#if defined(_OPENMP) +#pragma omp parallel for +#endif + for (int i = 0; i < num_outputs; ++i) { + outputs[i] = omp_get_thread_num(); + } + + // Our BUILD rule will run this program with a maximum of two threads. + // Confirm how many threads were used and that their thread numbers were the + // expected set of either {0, 1} (with OpenMP) or {0} (without OpenMP). + std::unordered_set thread_nums(outputs.begin(), outputs.end()); + if (kHasOpenmp) { + EXPECT_THAT(thread_nums, testing::UnorderedElementsAre(0, 1)); + } else { + EXPECT_THAT(thread_nums, testing::UnorderedElementsAre(0)); + } +} + +} // namespace +} // namespace drake diff --git a/doc/_pages/bazel.md b/doc/_pages/bazel.md index e77fd1bb994c..96f92ede8dfb 100644 --- a/doc/_pages/bazel.md +++ b/doc/_pages/bazel.md @@ -249,6 +249,25 @@ See [https://docs.bazel.build/versions/main/user-manual.html#bazelrc](https://do SNOPT support has some known problems on certain programs (see drake issue [#10422](https://github.com/RobotLocomotion/drake/issues/10422) for a summary). +# Other optional dependencies + +## OpenMP + +Drake is +[in the process](https://github.com/RobotLocomotion/drake/issues/14858) +of adding support for multiprocessing using +[OpenMP](https://en.wikipedia.org/wiki/OpenMP). +At the moment, that support is experimental and is not recommended for Drake's +users. + +For Drake Developers who wish to enable OpenMP, use this config switch: + +``` +bazel test --config omp //... +``` + +This switch is enabled in CI under the "Ubuntu Everything" build flavor. + # Optional Tools The Drake Bazel build system has integration support for some optional diff --git a/tools/ubuntu-focal.bazelrc b/tools/ubuntu-focal.bazelrc index b23f5802a9a2..316ee85081e8 100644 --- a/tools/ubuntu-focal.bazelrc +++ b/tools/ubuntu-focal.bazelrc @@ -17,6 +17,11 @@ build --action_env=PATH=/usr/bin:/bin build --action_env=PYTHONNOUSERSITE=1 build --test_env=PYTHONNOUSERSITE=1 +# Enable OpenMP (when requested via --config omp). +build:omp --copt=-DEIGEN_DONT_PARALLELIZE +build:omp --copt=-fopenmp +build:omp --linkopt=-fopenmp + # -- Options for explicitly using Clang. common:clang --repo_env=CC=clang-9 common:clang --repo_env=CXX=clang++-9 diff --git a/tools/workspace/libcmaes/package.BUILD.bazel b/tools/workspace/libcmaes/package.BUILD.bazel index ca8d21c128ee..423f49017dbb 100644 --- a/tools/workspace/libcmaes/package.BUILD.bazel +++ b/tools/workspace/libcmaes/package.BUILD.bazel @@ -60,6 +60,7 @@ cc_library( "surrogatestrategy.h", ]), copts = [ + "-fno-openmp", # Ignore OpenMP-related warnings. "-Wno-unknown-pragmas", ], diff --git a/tools/workspace/scs/package.BUILD.bazel b/tools/workspace/scs/package.BUILD.bazel index dafa4bf6c8b3..b18e0e768051 100644 --- a/tools/workspace/scs/package.BUILD.bazel +++ b/tools/workspace/scs/package.BUILD.bazel @@ -39,6 +39,7 @@ cc_library( ], copts = [ "-fvisibility=hidden", + "-fno-openmp", "-w", "-Werror=incompatible-pointer-types", ],