From 758e227ee68b3089152b20d979c235908708b318 Mon Sep 17 00:00:00 2001 From: Aiden Grossman Date: Mon, 30 Dec 2024 00:59:06 +0000 Subject: [PATCH] Plumb pinned core through benchmarking abstractions This patch does the necessary plumbing to enable setting the benchmarking core from the Python wrapper around exegesis that is used for benchmarking. Pull Request: https://github.com/google/gematria/pull/272 --- gematria/datasets/exegesis_benchmark.cc | 3 ++- gematria/datasets/exegesis_benchmark_lib.cc | 6 +++--- gematria/datasets/exegesis_benchmark_lib.h | 4 +++- .../datasets/exegesis_benchmark_lib_test.cc | 5 +++-- .../datasets/python/exegesis_benchmark.cc | 11 +++++++++-- .../python/exegesis_benchmark_test.py | 19 ++++++++++++++++++- 6 files changed, 38 insertions(+), 10 deletions(-) diff --git a/gematria/datasets/exegesis_benchmark.cc b/gematria/datasets/exegesis_benchmark.cc index 33baffb1..c53e9f26 100644 --- a/gematria/datasets/exegesis_benchmark.cc +++ b/gematria/datasets/exegesis_benchmark.cc @@ -113,7 +113,8 @@ int main(int Argc, char *Argv[]) { Benchmark->parseJSONBlock(*AnnotatedBlockObject, BlockIndex)); double Throughput = exitOnFileError( - AnnotatedBlocksJson, Benchmark->benchmarkBasicBlock(BenchCode)); + AnnotatedBlocksJson, + Benchmark->benchmarkBasicBlock(BenchCode, std::nullopt)); std::optional HexValue = AnnotatedBlockObject->getString("Hex"); // The block has already been parsed previously, and thus should have thrown diff --git a/gematria/datasets/exegesis_benchmark_lib.cc b/gematria/datasets/exegesis_benchmark_lib.cc index af079b82..1927141f 100644 --- a/gematria/datasets/exegesis_benchmark_lib.cc +++ b/gematria/datasets/exegesis_benchmark_lib.cc @@ -341,7 +341,7 @@ Expected ExegesisBenchmark::processAnnotatedBlock( } Expected ExegesisBenchmark::benchmarkBasicBlock( - const BenchmarkCode &BenchCode) { + const BenchmarkCode &BenchCode, std::optional BenchmarkProcessCPU) { std::unique_ptr SnipRepetitor = SnippetRepetitor::Create(Benchmark::RepetitionModeE::MiddleHalfLoop, ExegesisState, BenchCode.Key.LoopRegister); @@ -355,7 +355,7 @@ Expected ExegesisBenchmark::benchmarkBasicBlock( if (!RC2) return RC2.takeError(); std::pair BenchmarkResultAOrErr = - BenchRunner->runConfiguration(std::move(*RC1), {}, std::nullopt); + BenchRunner->runConfiguration(std::move(*RC1), {}, BenchmarkProcessCPU); if (std::get<0>(BenchmarkResultAOrErr)) return std::move(std::get<0>(BenchmarkResultAOrErr)); @@ -363,7 +363,7 @@ Expected ExegesisBenchmark::benchmarkBasicBlock( AllResults.push_back(std::move(std::get<1>(BenchmarkResultAOrErr))); std::pair BenchmarkResultBOrErr = - BenchRunner->runConfiguration(std::move(*RC2), {}, std::nullopt); + BenchRunner->runConfiguration(std::move(*RC2), {}, BenchmarkProcessCPU); if (std::get<0>(BenchmarkResultBOrErr)) return std::move(std::get<0>(BenchmarkResultBOrErr)); diff --git a/gematria/datasets/exegesis_benchmark_lib.h b/gematria/datasets/exegesis_benchmark_lib.h index 1e2504a7..41d01fb5 100644 --- a/gematria/datasets/exegesis_benchmark_lib.h +++ b/gematria/datasets/exegesis_benchmark_lib.h @@ -14,6 +14,7 @@ #include #include +#include #include #include "gematria/proto/execution_annotation.pb.h" @@ -46,7 +47,8 @@ class ExegesisBenchmark { std::string_view BlockHex, const ExecutionAnnotations &Annotations); llvm::Expected benchmarkBasicBlock( - const llvm::exegesis::BenchmarkCode &BenchCode); + const llvm::exegesis::BenchmarkCode &BenchCode, + std::optional BenchmarkProcessCPU); private: // This is a simple wrapper around functionality in ExegesisState that maps diff --git a/gematria/datasets/exegesis_benchmark_lib_test.cc b/gematria/datasets/exegesis_benchmark_lib_test.cc index df8675de..a71b32fa 100644 --- a/gematria/datasets/exegesis_benchmark_lib_test.cc +++ b/gematria/datasets/exegesis_benchmark_lib_test.cc @@ -15,6 +15,7 @@ #include "gematria/datasets/exegesis_benchmark_lib.h" #include +#include #include #include "gematria/proto/execution_annotation.pb.h" @@ -92,7 +93,7 @@ class ExegesisBenchmarkTest : public testing::Test { Benchmark->parseJSONBlock(*BlockValue->getAsObject(), 0); if (!BenchCode) return BenchCode.takeError(); - return Benchmark->benchmarkBasicBlock(*BenchCode); + return Benchmark->benchmarkBasicBlock(*BenchCode, std::nullopt); } }; @@ -441,7 +442,7 @@ TEST_F(ExegesisBenchmarkTest, TestBenchmarkFromAnnotatedBlock) { ASSERT_TRUE(static_cast(BenchmarkConfiguration)); Expected BenchmarkResult = - Benchmark->benchmarkBasicBlock(*BenchmarkConfiguration); + Benchmark->benchmarkBasicBlock(*BenchmarkConfiguration, std::nullopt); EXPECT_LT(*BenchmarkResult, 10); } diff --git a/gematria/datasets/python/exegesis_benchmark.cc b/gematria/datasets/python/exegesis_benchmark.cc index 378e54bc..cff191a4 100644 --- a/gematria/datasets/python/exegesis_benchmark.cc +++ b/gematria/datasets/python/exegesis_benchmark.cc @@ -13,6 +13,7 @@ // limitations under the License. #include +#include #include "absl/status/statusor.h" #include "gematria/datasets/bhive_to_exegesis.h" @@ -26,6 +27,8 @@ #include "pybind11/cast.h" #include "pybind11/detail/common.h" #include "pybind11/pybind11.h" +#include "pybind11/pytypes.h" +#include "pybind11/stl.h" // IWYU pragma: keep #include "pybind11_abseil/import_status_module.h" #include "pybind11_abseil/status_casters.h" // IWYU pragma: keep #include "pybind11_protobuf/native_proto_caster.h" // IWYU pragma: keep @@ -116,11 +119,13 @@ PYBIND11_MODULE(exegesis_benchmark, m) { )") .def( "benchmark_basic_block", - [](ExegesisBenchmark& Self, const BenchmarkCode& InputBenchmark) { + [](ExegesisBenchmark& Self, const BenchmarkCode& InputBenchmark, + std::optional BenchmarkProcessCPU) { return LlvmExpectedToStatusOr( - Self.benchmarkBasicBlock(InputBenchmark)); + Self.benchmarkBasicBlock(InputBenchmark, BenchmarkProcessCPU)); }, py::arg("input_benchmark"), + py::arg("benchmark_process_cpu") = py::none(), R"(Benchmarks a block in the form of a BenchmarkCode instance. Takes a BenchmarkCode instance and then executes it, collecting @@ -129,6 +134,8 @@ PYBIND11_MODULE(exegesis_benchmark, m) { Args: input_benchmark: The BenchmarkCode instance formed from the block and annotations of interest that should be benchmarked. + benchmark_process_cpu: An optional integer specifying the CPU ID + that the benchmarking subprocess should be pinned to. Returns: A floating point value representing the inverse throughput (i.e., diff --git a/gematria/datasets/python/exegesis_benchmark_test.py b/gematria/datasets/python/exegesis_benchmark_test.py index 61c85405..ce89de38 100644 --- a/gematria/datasets/python/exegesis_benchmark_test.py +++ b/gematria/datasets/python/exegesis_benchmark_test.py @@ -12,6 +12,8 @@ # See the License for the specific language governing permissions and # limitations under the License. +import os + from absl.testing import absltest from gematria.datasets.python import bhive_to_exegesis @@ -31,7 +33,7 @@ def setUp(self): ) self.exegesis_benchmark = exegesis_benchmark.ExegesisBenchmark.create() - def test_benchmarking(self): + def _get_block_for_benchmarking(self) -> exegesis_benchmark.BenchmarkCode: execution_annotations = self.bhive_to_exegesis.annotate_basic_block( "4829d38b44246c8b54246848c1fb034829d04839c3", bhive_to_exegesis.AnnotatorType.fast, @@ -49,12 +51,27 @@ def test_benchmarking(self): block_with_annotations ) + return benchmark_code + + def test_benchmarking(self): + benchmark_code = self._get_block_for_benchmarking() + block_measurement = self.exegesis_benchmark.benchmark_basic_block( benchmark_code ) self.assertLess(block_measurement, 10) + def test_benchmarking_pinned_core(self): + benchmark_code = self._get_block_for_benchmarking() + benchmark_core = os.sched_getaffinity(0).pop() + + block_measurement = self.exegesis_benchmark.benchmark_basic_block( + benchmark_code, benchmark_core + ) + + self.assertLess(block_measurement, 10) + if __name__ == "__main__": absltest.main()