diff options
author | aarongreen <aarongreen@google.com> | 2023-11-10 22:56:41 +0000 |
---|---|---|
committer | CQ Bot Account <pigweed-scoped@luci-project-accounts.iam.gserviceaccount.com> | 2023-11-10 22:56:41 +0000 |
commit | e596056be5c19aaed103d20669f54c3801dc840f (patch) | |
tree | ce0644ea0fdfdd909cd02c4fe71b5c3765c4c74a | |
parent | 998bcf980e9d1e2cc3e3ca298620c86a3fb3271c (diff) | |
download | pigweed-e596056be5c19aaed103d20669f54c3801dc840f.tar.gz |
pw_perf_test: Reogranize source files
This CL moves `internal::Framework`, `internal::TestInfo`, and `State`
out of pw_perf_test.h and into their own separate files.
It also moves performance_test_generic.cc to
examples/example_perf_test.cc.
Finally, it removes perf_test_test.cc as this file created a no-op unit
test.
Change-Id: Id5e984cdf80bb7ed801be1f81ebb8cba8c05b91b
Reviewed-on: https://pigweed-review.googlesource.com/c/pigweed/pigweed/+/178914
Reviewed-by: Armando Montanez <amontanez@google.com>
Commit-Queue: Aaron Green <aarongreen@google.com>
-rw-r--r-- | BUILD.gn | 2 | ||||
-rw-r--r-- | pw_perf_test/BUILD.bazel | 157 | ||||
-rw-r--r-- | pw_perf_test/BUILD.gn | 160 | ||||
-rw-r--r-- | pw_perf_test/CMakeLists.txt | 118 | ||||
-rw-r--r-- | pw_perf_test/examples/example_perf_test.cc (renamed from pw_perf_test/performance_test_generic.cc) | 0 | ||||
-rw-r--r-- | pw_perf_test/framework.cc | 53 | ||||
-rw-r--r-- | pw_perf_test/perf_test.cc | 80 | ||||
-rw-r--r-- | pw_perf_test/perf_test_test.cc | 43 | ||||
-rw-r--r-- | pw_perf_test/public/pw_perf_test/internal/framework.h | 57 | ||||
-rw-r--r-- | pw_perf_test/public/pw_perf_test/internal/test_info.h | 50 | ||||
-rw-r--r-- | pw_perf_test/public/pw_perf_test/perf_test.h | 141 | ||||
-rw-r--r-- | pw_perf_test/public/pw_perf_test/state.h | 87 | ||||
-rw-r--r-- | pw_perf_test/state.cc | 66 | ||||
-rw-r--r-- | pw_perf_test/state_test.cc | 3 | ||||
-rw-r--r-- | pw_perf_test/test_info.cc | 28 |
15 files changed, 588 insertions, 457 deletions
@@ -646,7 +646,7 @@ if (current_toolchain != default_toolchain) { pw_test_group("pw_perf_tests") { tests = [ "$dir_pw_checksum:perf_tests", - "$dir_pw_perf_test:perf_test_tests_test", + "$dir_pw_perf_test:examples", "$dir_pw_protobuf:perf_tests", ] output_metadata = true diff --git a/pw_perf_test/BUILD.bazel b/pw_perf_test/BUILD.bazel index 7b0a8fa11..75998ad69 100644 --- a/pw_perf_test/BUILD.bazel +++ b/pw_perf_test/BUILD.bazel @@ -29,47 +29,50 @@ package(default_visibility = ["//visibility:public"]) licenses(["notice"]) pw_cc_library( - name = "duration_unit", - hdrs = [ - "public/pw_perf_test/internal/duration_unit.h", + name = "pw_perf_test", + srcs = [ + "framework.cc", + "perf_test.cc", + "test_info.cc", ], - includes = ["public"], - visibility = ["//visibility:private"], -) - -pw_cc_facade( - name = "timer_interface_facade", hdrs = [ - "public/pw_perf_test/internal/timer.h", + "public/pw_perf_test/internal/framework.h", + "public/pw_perf_test/internal/test_info.h", + "public/pw_perf_test/perf_test.h", ], includes = ["public"], - visibility = ["//visibility:private"], deps = [ - ":duration_unit", + ":event_handler", + ":state", + ":timer", + "//pw_preprocessor", ], ) pw_cc_library( - name = "timer", + name = "state", + srcs = [ + "state.cc", + ], hdrs = [ - "public/pw_perf_test/internal/timer.h", + "public/pw_perf_test/state.h", ], includes = ["public"], deps = [ - ":duration_unit", - "@pigweed//targets:pw_perf_test_timer_backend", + ":event_handler", + ":timer", + "//pw_assert", + "//pw_log", ], ) -pw_cc_library( - name = "timer_multiplexer", - visibility = ["@pigweed//targets:__pkg__"], - deps = select({ - "//conditions:default": [":chrono_timer"], - }), +pw_cc_test( + name = "state_test", + srcs = ["state_test.cc"], + deps = [":pw_perf_test"], ) -# EventHandler Configuraitions +# Event handlers pw_cc_library( name = "event_handler", @@ -79,19 +82,6 @@ pw_cc_library( ) pw_cc_library( - name = "pw_perf_test", - srcs = ["perf_test.cc"], - hdrs = ["public/pw_perf_test/perf_test.h"], - includes = ["public"], - deps = [ - ":event_handler", - ":timer", - "//pw_assert", - "//pw_log", - ], -) - -pw_cc_library( name = "google_test_style_event_strings", hdrs = ["public/pw_perf_test/googletest_style_event_handler.h"], ) @@ -119,52 +109,61 @@ pw_cc_library( ], ) -pw_cc_perf_test( - name = "generic_test", - srcs = ["performance_test_generic.cc"], -) +# Timer facade -# Test Declarations +pw_cc_library( + name = "duration_unit", + hdrs = [ + "public/pw_perf_test/internal/duration_unit.h", + ], + includes = ["public"], + visibility = ["//visibility:private"], +) -pw_cc_test( - name = "perf_test_test", - srcs = ["perf_test_test.cc"], - deps = [":pw_perf_test"], +pw_cc_facade( + name = "timer_interface_facade", + hdrs = [ + "public/pw_perf_test/internal/timer.h", + ], + includes = ["public"], + visibility = ["//visibility:private"], + deps = [ + ":duration_unit", + ], ) -pw_cc_test( - name = "timer_test", - srcs = ["timer_test.cc"], +pw_cc_library( + name = "timer", + hdrs = [ + "public/pw_perf_test/internal/timer.h", + ], + includes = ["public"], deps = [ - ":timer", - "//pw_chrono:system_clock", - "//pw_thread:sleep", + ":duration_unit", + "@pigweed//targets:pw_perf_test_timer_backend", ], ) +pw_cc_library( + name = "timer_multiplexer", + visibility = ["@pigweed//targets:__pkg__"], + deps = select({ + "//conditions:default": [":chrono_timer"], + }), +) + pw_cc_test( - name = "chrono_timer_test", - srcs = ["chrono_test.cc"], + name = "timer_test", + srcs = ["timer_test.cc"], deps = [ - ":chrono_timer", + ":timer", "//pw_chrono:system_clock", "//pw_thread:sleep", ], ) -pw_cc_test( - name = "state_test", - srcs = ["state_test.cc"], - deps = [":pw_perf_test"], -) - -# Bazel does not yet support building docs. -filegroup( - name = "docs", - srcs = ["docs.rst"], -) +# Chrono timer facade implementation -# Chrono Implementation pw_cc_library( name = "chrono_timer", hdrs = [ @@ -183,7 +182,18 @@ pw_cc_library( ], ) -# ARM Cortex Implementation +pw_cc_test( + name = "chrono_timer_test", + srcs = ["chrono_test.cc"], + deps = [ + ":chrono_timer", + "//pw_chrono:system_clock", + "//pw_thread:sleep", + ], +) + +# ARM Cortex timer facade implementation + pw_cc_library( name = "arm_cortex_timer", hdrs = [ @@ -200,3 +210,16 @@ pw_cc_library( ":timer_interface_facade", ], ) + +# Module-level targets + +pw_cc_perf_test( + name = "example_perf_test", + srcs = ["examples/example_perf_test.cc"], +) + +# Bazel does not yet support building docs. +filegroup( + name = "docs", + srcs = ["docs.rst"], +) diff --git a/pw_perf_test/BUILD.gn b/pw_perf_test/BUILD.gn index 81ee5d930..8772591c4 100644 --- a/pw_perf_test/BUILD.gn +++ b/pw_perf_test/BUILD.gn @@ -26,63 +26,51 @@ config("public_include_path") { visibility = [ ":*" ] } -config("arm_config") { - include_dirs = [ "arm_cortex_cyccnt_public_overrides" ] - visibility = [ ":*" ] -} - -config("chrono_config") { - include_dirs = [ "chrono_public_overrides" ] - visibility = [ ":*" ] -} - -pw_test_group("tests") { - tests = [ - ":perf_test_test", - ":timer_facade_test", - ":chrono_timer_test", - ":state_test", +pw_source_set("pw_perf_test") { + public_configs = [ ":public_include_path" ] + public = [ + "public/pw_perf_test/internal/framework.h", + "public/pw_perf_test/internal/test_info.h", + "public/pw_perf_test/perf_test.h", + ] + public_deps = [ + ":event_handler", + ":state", + ":timer_interface", + dir_pw_preprocessor, + ] + sources = [ + "framework.cc", + "perf_test.cc", + "test_info.cc", ] } -group("perf_test_tests_test") { - deps = [ ":generic_perf_test" ] -} - -# Timing interface variables - -pw_source_set("duration_unit") { - public = [ "public/pw_perf_test/internal/duration_unit.h" ] +pw_source_set("state") { public_configs = [ ":public_include_path" ] - visibility = [ ":*" ] + public = [ "public/pw_perf_test/state.h" ] + public_deps = [ + ":event_handler", + ":timer_interface", + dir_pw_assert, + ] + deps = [ dir_pw_log ] + sources = [ "state.cc" ] } -pw_facade("timer_interface") { - backend = pw_perf_test_TIMER_INTERFACE_BACKEND - public = [ "public/pw_perf_test/internal/timer.h" ] - public_deps = [ ":duration_unit" ] - visibility = [ ":*" ] +pw_test("state_test") { + enable_if = pw_perf_test_TIMER_INTERFACE_BACKEND != "" + sources = [ "state_test.cc" ] + deps = [ ":state" ] } -# Event Handler Configurations +# Event handlers pw_source_set("event_handler") { public_configs = [ ":public_include_path" ] public = [ "public/pw_perf_test/event_handler.h" ] } -pw_source_set("pw_perf_test") { - public_configs = [ ":public_include_path" ] - public = [ "public/pw_perf_test/perf_test.h" ] - public_deps = [ - ":event_handler", - ":timer_interface", - dir_pw_assert, - ] - deps = [ dir_pw_log ] - sources = [ "perf_test.cc" ] -} - pw_source_set("googletest_style_event_handler") { public_configs = [ ":public_include_path" ] public = [ "public/pw_perf_test/googletest_style_event_handler.h" ] @@ -105,48 +93,34 @@ pw_source_set("log_perf_handler_main") { sources = [ "log_perf_handler_main.cc" ] } -pw_perf_test("generic_perf_test") { - enable_if = pw_perf_test_TIMER_INTERFACE_BACKEND != "" - sources = [ "performance_test_generic.cc" ] -} +# Timer facade -# Declaring module tests +pw_source_set("duration_unit") { + public = [ "public/pw_perf_test/internal/duration_unit.h" ] + public_configs = [ ":public_include_path" ] + visibility = [ ":*" ] +} -pw_test("perf_test_test") { - enable_if = pw_perf_test_TIMER_INTERFACE_BACKEND != "" - sources = [ "perf_test_test.cc" ] - deps = [ ":pw_perf_test" ] +pw_facade("timer_interface") { + backend = pw_perf_test_TIMER_INTERFACE_BACKEND + public = [ "public/pw_perf_test/internal/timer.h" ] + public_deps = [ ":duration_unit" ] + visibility = [ ":*" ] } pw_test("timer_facade_test") { enable_if = pw_perf_test_TIMER_INTERFACE_BACKEND != "" sources = [ "timer_test.cc" ] - public_deps = [ ":timer_interface" ] -} - -pw_test("chrono_timer_test") { - enable_if = pw_chrono_SYSTEM_TIMER_BACKEND != "" - sources = [ "chrono_test.cc" ] - public_deps = [ - ":chrono_timer", - "$dir_pw_chrono:system_timer", - "$dir_pw_thread:sleep", - ] -} - -pw_test("state_test") { - enable_if = pw_perf_test_TIMER_INTERFACE_BACKEND != "" - sources = [ "state_test.cc" ] - public_deps = [ ":pw_perf_test" ] + deps = [ ":timer_interface" ] } -# Documentation declaration +# Chrono timer facade implementation -pw_doc_group("docs") { - sources = [ "docs.rst" ] +config("chrono_config") { + include_dirs = [ "chrono_public_overrides" ] + visibility = [ ":*" ] } -# Chrono Implementation pw_source_set("pw_perf_test_chrono") { public_configs = [ ":chrono_config" ] public = [ "chrono_public_overrides/pw_perf_test_timer_backend/timer.h" ] @@ -166,7 +140,22 @@ pw_source_set("chrono_timer") { visibility = [ ":*" ] } -# ARM Cortex Implementation +pw_test("chrono_timer_test") { + enable_if = pw_chrono_SYSTEM_TIMER_BACKEND != "" + sources = [ "chrono_test.cc" ] + deps = [ + ":chrono_timer", + "$dir_pw_chrono:system_timer", + "$dir_pw_thread:sleep", + ] +} + +# ARM Cortex timer facade implementation + +config("arm_config") { + include_dirs = [ "arm_cortex_cyccnt_public_overrides" ] + visibility = [ ":*" ] +} pw_source_set("arm_cortex_timer") { public_configs = [ @@ -185,3 +174,26 @@ pw_source_set("pw_perf_test_arm_cortex") { ] public_deps = [ ":arm_cortex_timer" ] } + +# Module-level targets + +pw_perf_test("example_perf_test") { + enable_if = pw_perf_test_TIMER_INTERFACE_BACKEND != "" + sources = [ "examples/example_perf_test.cc" ] +} + +group("examples") { + deps = [ ":example_perf_test" ] +} + +pw_test_group("tests") { + tests = [ + ":chrono_timer_test", + ":state_test", + ":timer_facade_test", + ] +} + +pw_doc_group("docs") { + sources = [ "docs.rst" ] +} diff --git a/pw_perf_test/CMakeLists.txt b/pw_perf_test/CMakeLists.txt index 80f4487a2..3f5c5c782 100644 --- a/pw_perf_test/CMakeLists.txt +++ b/pw_perf_test/CMakeLists.txt @@ -16,44 +16,58 @@ include($ENV{PW_ROOT}/pw_build/pigweed.cmake) include($ENV{PW_ROOT}/pw_perf_test/backend.cmake) include($ENV{PW_ROOT}/pw_protobuf_compiler/proto.cmake) -pw_add_library(pw_perf_test.duration_unit INTERFACE - HEADERS - public/pw_perf_test/internal/duration_unit.h +pw_add_library(pw_perf_test STATIC PUBLIC_INCLUDES public -) - -pw_add_facade(pw_perf_test.timer INTERFACE - BACKEND - pw_perf_test.TIMER_INTERFACE_BACKEND HEADERS - public/pw_perf_test/internal/timer.h - PUBLIC_INCLUDES - public + public/pw_perf_test/internal/framework.h + public/pw_perf_test/internal/test_info.h + public/pw_perf_test/perf_test.h PUBLIC_DEPS - pw_perf_test.duration_unit -) - -pw_add_library(pw_perf_test.event_handler INTERFACE - HEADERS - public/pw_perf_test/event_handler.h - PUBLIC_INCLUDES - public + pw_perf_test.event_handler + pw_perf_test.state + pw_perf_test.timer + SOURCES + framework.cc + perf_test.cc + test_info.cc ) -pw_add_library(pw_perf_test STATIC +pw_add_library(pw_perf_test.state STATIC PUBLIC_INCLUDES public HEADERS - public/pw_perf_test/perf_test.h + public/pw_perf_test/state.h PUBLIC_DEPS pw_perf_test.timer pw_perf_test.event_handler + pw_assert PRIVATE_DEPS pw_log - pw_assert SOURCES - perf_test.cc + state.cc +) + +if(NOT "${pw_perf_test.TIMER_INTERFACE_BACKEND}" STREQUAL "") + pw_add_test(pw_perf_test.state_test + SOURCES + state_test.cc + PRIVATE_DEPS + pw_assert.assert + pw_perf_test + GROUPS + modules + pw_perf_test + ) +endif() + +# Event handlers + +pw_add_library(pw_perf_test.event_handler INTERFACE + HEADERS + public/pw_perf_test/event_handler.h + PUBLIC_INCLUDES + public ) pw_add_library(pw_perf_test.googletest_style_event_handler INTERFACE @@ -85,15 +99,23 @@ pw_add_library(pw_perf_test.log_perf_handler_main STATIC log_perf_handler_main.cc ) -pw_add_library(pw_perf_test.chrono_timer INTERFACE +# Timer facade + +pw_add_library(pw_perf_test.duration_unit INTERFACE HEADERS - chrono_public_overrides/pw_perf_test_timer_backend/timer.h - public/pw_perf_test/internal/chrono_timer_interface.h + public/pw_perf_test/internal/duration_unit.h + PUBLIC_INCLUDES + public +) + +pw_add_facade(pw_perf_test.timer INTERFACE + BACKEND + pw_perf_test.TIMER_INTERFACE_BACKEND + HEADERS + public/pw_perf_test/internal/timer.h PUBLIC_INCLUDES - chrono_public_overrides public PUBLIC_DEPS - pw_chrono.system_clock pw_perf_test.duration_unit ) @@ -111,6 +133,20 @@ if(NOT "${pw_perf_test.TIMER_INTERFACE_BACKEND}" STREQUAL "") ) endif() +# Chrono timer facade implementation + +pw_add_library(pw_perf_test.chrono_timer INTERFACE + HEADERS + chrono_public_overrides/pw_perf_test_timer_backend/timer.h + public/pw_perf_test/internal/chrono_timer_interface.h + PUBLIC_INCLUDES + chrono_public_overrides + public + PUBLIC_DEPS + pw_chrono.system_clock + pw_perf_test.duration_unit +) + if(NOT "${pw_perf_test.TIMER_INTERFACE_BACKEND}" STREQUAL "pw_chrono.SYSTEM_CLOCK_BACKEND.NO_BACKEND_SET") pw_add_test(pw_perf_test.chrono_timer_test @@ -125,29 +161,3 @@ if(NOT "${pw_perf_test.TIMER_INTERFACE_BACKEND}" pw_perf_test ) endif() - -if(NOT "${pw_perf_test.TIMER_INTERFACE_BACKEND}" STREQUAL "") - pw_add_test(pw_perf_test.state_test - SOURCES - state_test.cc - PRIVATE_DEPS - pw_assert.assert - pw_perf_test - GROUPS - modules - pw_perf_test - ) -endif() - -if(NOT "${pw_perf_test.TIMER_INTERFACE_BACKEND}" STREQUAL "") - pw_add_test(pw_perf_test.perf_test_test - SOURCES - perf_test_test.cc - PRIVATE_DEPS - pw_assert.assert - pw_perf_test - GROUPS - modules - pw_perf_test - ) -endif() diff --git a/pw_perf_test/performance_test_generic.cc b/pw_perf_test/examples/example_perf_test.cc index b1318b062..b1318b062 100644 --- a/pw_perf_test/performance_test_generic.cc +++ b/pw_perf_test/examples/example_perf_test.cc diff --git a/pw_perf_test/framework.cc b/pw_perf_test/framework.cc new file mode 100644 index 000000000..ccfc9cc3f --- /dev/null +++ b/pw_perf_test/framework.cc @@ -0,0 +1,53 @@ +// Copyright 2023 The Pigweed Authors +// +// 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 +// +// https://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. + +#include "pw_perf_test/internal/framework.h" + +#include "pw_perf_test/internal/test_info.h" +#include "pw_perf_test/internal/timer.h" + +namespace pw::perf_test::internal { + +Framework Framework::framework_; + +int Framework::RunAllTests() { + if (!internal::TimerPrepare()) { + return false; + } + + event_handler_->RunAllTestsStart(run_info_); + + for (const TestInfo* test = tests_; test != nullptr; test = test->next()) { + State test_state = internal::CreateState( + kDefaultIterations, *event_handler_, test->test_name()); + test->Run(test_state); + } + internal::TimerCleanup(); + event_handler_->RunAllTestsEnd(); + return true; +} + +void Framework::RegisterTest(TestInfo& new_test) { + ++run_info_.total_tests; + if (tests_ == nullptr) { + tests_ = &new_test; + return; + } + TestInfo* info = tests_; + for (; info->next() != nullptr; info = info->next()) { + } + info->SetNext(&new_test); +} + +} // namespace pw::perf_test::internal diff --git a/pw_perf_test/perf_test.cc b/pw_perf_test/perf_test.cc index 0e2f8d1ee..3cbe0e2f1 100644 --- a/pw_perf_test/perf_test.cc +++ b/pw_perf_test/perf_test.cc @@ -16,89 +16,11 @@ #include "pw_perf_test/perf_test.h" -#include <cstdint> - -#include "pw_log/log.h" #include "pw_perf_test/event_handler.h" +#include "pw_perf_test/internal/framework.h" #include "pw_perf_test/internal/timer.h" namespace pw::perf_test { -namespace internal { - -Framework Framework::framework_; - -int Framework::RunAllTests() { - if (!internal::TimerPrepare()) { - return false; - } - - event_handler_->RunAllTestsStart(run_info_); - - for (const TestInfo* test = tests_; test != nullptr; test = test->next()) { - State test_state = - CreateState(kDefaultIterations, *event_handler_, test->test_name()); - test->Run(test_state); - } - internal::TimerCleanup(); - event_handler_->RunAllTestsEnd(); - return true; -} - -void Framework::RegisterTest(TestInfo& new_test) { - ++run_info_.total_tests; - if (tests_ == nullptr) { - tests_ = &new_test; - return; - } - TestInfo* info = tests_; - for (; info->next() != nullptr; info = info->next()) { - } - info->SetNext(&new_test); -} - -State CreateState(int durations, - EventHandler& event_handler, - const char* test_name) { - return State(durations, event_handler, test_name); -} -} // namespace internal - -bool State::KeepRunning() { - internal::Timestamp iteration_end = internal::GetCurrentTimestamp(); - if (current_iteration_ == -1) { - ++current_iteration_; - event_handler_->TestCaseStart(test_info); - iteration_start_ = internal::GetCurrentTimestamp(); - return true; - } - int64_t duration = internal::GetDuration(iteration_start_, iteration_end); - if (duration > max_) { - max_ = duration; - } - if (duration < min_) { - min_ = duration; - } - total_duration_ += duration; - ++current_iteration_; - PW_LOG_DEBUG("Iteration number: %d - Duration: %ld", - current_iteration_, - static_cast<long>(duration)); - event_handler_->TestCaseIteration({current_iteration_, duration}); - if (current_iteration_ == test_iterations_) { - PW_LOG_DEBUG("Total Duration: %ld Total Iterations: %d", - static_cast<long>(total_duration_), - test_iterations_); - mean_ = total_duration_ / test_iterations_; - PW_LOG_DEBUG("Mean: %ld: ", static_cast<long>(mean_)); - PW_LOG_DEBUG("Minimum: %ld", static_cast<long>(min_)); - PW_LOG_DEBUG("Maxmimum: %ld", static_cast<long>(max_)); - event_handler_->TestCaseEnd(test_info, - Results{mean_, max_, min_, test_iterations_}); - return false; - } - iteration_start_ = internal::GetCurrentTimestamp(); - return true; -} void RunAllTests(EventHandler& handler) { internal::Framework::Get().RegisterEventHandler(handler); diff --git a/pw_perf_test/perf_test_test.cc b/pw_perf_test/perf_test_test.cc deleted file mode 100644 index 2cdea93e1..000000000 --- a/pw_perf_test/perf_test_test.cc +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright 2022 The Pigweed Authors -// -// 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 -// -// https://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. - -#include "pw_perf_test/perf_test.h" - -#include "gtest/gtest.h" - -void TestingFunction(pw::perf_test::State& state) { - while (state.KeepRunning()) { - // Intentionally empty. - } -} - -// This function is intentionally left blank -void SimpleFunction() {} - -void SimpleFunctionWithArgs(int, bool) {} - -namespace pw::perf_test { -namespace { - -PW_PERF_TEST(TestingComponentRegistration, TestingFunction); - -PW_PERF_TEST_SIMPLE(TestingSimpleRegistration, SimpleFunction); - -PW_PERF_TEST_SIMPLE(TestingSimpleRegistrationArgs, - SimpleFunctionWithArgs, - 123, - false); - -} // namespace -} // namespace pw::perf_test diff --git a/pw_perf_test/public/pw_perf_test/internal/framework.h b/pw_perf_test/public/pw_perf_test/internal/framework.h new file mode 100644 index 000000000..bb3ebab22 --- /dev/null +++ b/pw_perf_test/public/pw_perf_test/internal/framework.h @@ -0,0 +1,57 @@ +// Copyright 2023 The Pigweed Authors +// +// 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 +// +// https://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. +#pragma once + +#include "pw_perf_test/event_handler.h" + +namespace pw::perf_test::internal { + +// Forward declaration. +class TestInfo; + +/// Singleton that manages and runs performance tests. +/// +/// This class mimics pw::unit_test::Framework. +class Framework { + public: + constexpr Framework() + : event_handler_(nullptr), + tests_(nullptr), + run_info_{.total_tests = 0, .default_iterations = kDefaultIterations} {} + + static Framework& Get() { return framework_; } + + void RegisterEventHandler(EventHandler& event_handler) { + event_handler_ = &event_handler; + } + + void RegisterTest(TestInfo&); + + int RunAllTests(); + + private: + static constexpr int kDefaultIterations = 10; + + EventHandler* event_handler_; + + // Pointer to the list of tests + TestInfo* tests_; + + TestRunInfo run_info_; + + // Singleton + static Framework framework_; +}; + +} // namespace pw::perf_test::internal diff --git a/pw_perf_test/public/pw_perf_test/internal/test_info.h b/pw_perf_test/public/pw_perf_test/internal/test_info.h new file mode 100644 index 000000000..fd776e9d4 --- /dev/null +++ b/pw_perf_test/public/pw_perf_test/internal/test_info.h @@ -0,0 +1,50 @@ +// Copyright 2023 The Pigweed Authors +// +// 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 +// +// https://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. +#pragma once + +#include "pw_perf_test/state.h" + +namespace pw::perf_test::internal { + +/// Represents a single test case. +/// +/// Each instance includes a pointer to a function which constructs and runs the +/// test class. These are statically allocated instead of the test classes, as +/// test classes can be very large. +/// +/// This class mimics pw::unit_test::TestInfo. +class TestInfo { + public: + TestInfo(const char* test_name, void (*function_body)(State&)); + + // Returns the next registered test + TestInfo* next() const { return next_; } + + void SetNext(TestInfo* next) { next_ = next; } + + void Run(State& state) const { run_(state); } + + const char* test_name() const { return test_name_; } + + private: + // Function pointer to the code that will be measured + void (*run_)(State&); + + // Intrusively linked list, this acts as a pointer to the next test + TestInfo* next_ = nullptr; + + const char* test_name_; +}; + +} // namespace pw::perf_test::internal diff --git a/pw_perf_test/public/pw_perf_test/perf_test.h b/pw_perf_test/public/pw_perf_test/perf_test.h index e092087f9..90efb0cb0 100644 --- a/pw_perf_test/public/pw_perf_test/perf_test.h +++ b/pw_perf_test/public/pw_perf_test/perf_test.h @@ -13,13 +13,9 @@ // the License. #pragma once -#include <cstdint> -#include <limits> - -#include "pw_assert/assert.h" #include "pw_perf_test/event_handler.h" -#include "pw_perf_test/internal/duration_unit.h" -#include "pw_perf_test/internal/timer.h" +#include "pw_perf_test/internal/test_info.h" +#include "pw_perf_test/state.h" #include "pw_preprocessor/arguments.h" #define PW_PERF_TEST(name, function, ...) \ @@ -42,137 +38,6 @@ namespace pw::perf_test { -class State; - -namespace internal { - -class TestInfo; - -// Allows access to the private State object constructor -State CreateState(int durations, - EventHandler& event_handler, - const char* test_name); - -class Framework { - public: - constexpr Framework() - : event_handler_(nullptr), - tests_(nullptr), - run_info_{.total_tests = 0, .default_iterations = kDefaultIterations} {} - - static Framework& Get() { return framework_; } - - void RegisterEventHandler(EventHandler& event_handler) { - event_handler_ = &event_handler; - } - - void RegisterTest(TestInfo&); - - int RunAllTests(); - - private: - static constexpr int kDefaultIterations = 10; - - EventHandler* event_handler_; - - // Pointer to the list of tests - TestInfo* tests_; - - TestRunInfo run_info_; - - static Framework framework_; -}; - -class TestInfo { - public: - TestInfo(const char* test_name, void (*function_body)(State&)) - : run_(function_body), test_name_(test_name) { - // Once a TestInfo object is created by the macro, this adds itself to the - // list of registered tests - Framework::Get().RegisterTest(*this); - } - - // Returns the next registered test - TestInfo* next() const { return next_; } - - void SetNext(TestInfo* next) { next_ = next; } - - void Run(State& state) const { run_(state); } - - const char* test_name() const { return test_name_; } - - private: - // Function pointer to the code that will be measured - void (*run_)(State&); - - // Intrusively linked list, this acts as a pointer to the next test - TestInfo* next_ = nullptr; - - const char* test_name_; -}; - -} // namespace internal - -class State { - public: - // KeepRunning() should be called in a while loop. Responsible for managing - // iterations and timestamps. - bool KeepRunning(); - - private: - // Allows the framework to create state objects and unit tests for the state - // class - friend State internal::CreateState(int durations, - EventHandler& event_handler, - const char* test_name); - - // Privated constructor to prevent unauthorized instances of the state class. - constexpr State(int iterations, - EventHandler& event_handler, - const char* test_name) - : mean_(-1), - test_iterations_(iterations), - total_duration_(0), - min_(std::numeric_limits<int64_t>::max()), - max_(std::numeric_limits<int64_t>::min()), - iteration_start_(), - current_iteration_(-1), - event_handler_(&event_handler), - test_info{.name = test_name} { - PW_ASSERT(test_iterations_ > 0); - } - // Set public after deciding how exactly to set user-defined iterations - void SetIterations(int iterations) { - PW_ASSERT(current_iteration_ == -1); - test_iterations_ = iterations; - PW_ASSERT(test_iterations_ > 0); - } - - int64_t mean_; - - // Stores the total number of iterations wanted - int test_iterations_; - - // Stores the total duration of the tests. - int64_t total_duration_; - - // Smallest value of the iterations - int64_t min_; - - // Largest value of the iterations - int64_t max_; - - // Time at the start of the iteration - internal::Timestamp iteration_start_; - - // The current iteration - int current_iteration_; - - EventHandler* event_handler_; - - TestCase test_info; -}; - -void RunAllTests(pw::perf_test::EventHandler& handler); +void RunAllTests(EventHandler& handler); } // namespace pw::perf_test diff --git a/pw_perf_test/public/pw_perf_test/state.h b/pw_perf_test/public/pw_perf_test/state.h new file mode 100644 index 000000000..cd0e04f0c --- /dev/null +++ b/pw_perf_test/public/pw_perf_test/state.h @@ -0,0 +1,87 @@ +// Copyright 2023 The Pigweed Authors +// +// 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 +// +// https://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. +#pragma once + +#include <cstdint> +#include <limits> + +#include "pw_assert/assert.h" +#include "pw_perf_test/event_handler.h" +#include "pw_perf_test/internal/timer.h" + +namespace pw::perf_test { + +// Forward declaration. +class State; + +namespace internal { + +// Allows access to the private State object constructor +State CreateState(int durations, + EventHandler& event_handler, + const char* test_name); + +} // namespace internal + +/// Records the performance of a test case over many iterations. +class State { + public: + // KeepRunning() should be called in a while loop. Responsible for managing + // iterations and timestamps. + bool KeepRunning(); + + private: + // Allows the framework to create state objects and unit tests for the state + // class + friend State internal::CreateState(int durations, + EventHandler& event_handler, + const char* test_name); + + // Privated constructor to prevent unauthorized instances of the state class. + constexpr State(int iterations, + EventHandler& event_handler, + const char* test_name) + : test_iterations_(iterations), + iteration_start_(), + event_handler_(&event_handler), + test_info{.name = test_name} { + PW_ASSERT(test_iterations_ > 0); + } + + int64_t mean_ = -1; + + // Stores the total number of iterations wanted + int test_iterations_; + + // Stores the total duration of the tests. + int64_t total_duration_ = 0; + + // Smallest value of the iterations + int64_t min_ = std::numeric_limits<int64_t>::max(); + + // Largest value of the iterations + int64_t max_ = std::numeric_limits<int64_t>::min(); + + // Time at the start of the iteration + internal::Timestamp iteration_start_; + + // The current iteration. + int current_iteration_ = -1; + + EventHandler* event_handler_; + + TestCase test_info; +}; + +} // namespace pw::perf_test diff --git a/pw_perf_test/state.cc b/pw_perf_test/state.cc new file mode 100644 index 000000000..7fde71adc --- /dev/null +++ b/pw_perf_test/state.cc @@ -0,0 +1,66 @@ +// Copyright 2023 The Pigweed Authors +// +// 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 +// +// https://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. + +#include "pw_perf_test/state.h" + +#include "pw_log/log.h" + +namespace pw::perf_test { +namespace internal { + +State CreateState(int durations, + EventHandler& event_handler, + const char* test_name) { + return State(durations, event_handler, test_name); +} +} // namespace internal + +bool State::KeepRunning() { + internal::Timestamp iteration_end = internal::GetCurrentTimestamp(); + if (current_iteration_ == -1) { + ++current_iteration_; + event_handler_->TestCaseStart(test_info); + iteration_start_ = internal::GetCurrentTimestamp(); + return true; + } + int64_t duration = internal::GetDuration(iteration_start_, iteration_end); + if (duration > max_) { + max_ = duration; + } + if (duration < min_) { + min_ = duration; + } + total_duration_ += duration; + ++current_iteration_; + PW_LOG_DEBUG("Iteration number: %d - Duration: %ld", + current_iteration_, + static_cast<long>(duration)); + event_handler_->TestCaseIteration({current_iteration_, duration}); + if (current_iteration_ == test_iterations_) { + PW_LOG_DEBUG("Total Duration: %ld Total Iterations: %d", + static_cast<long>(total_duration_), + test_iterations_); + mean_ = total_duration_ / test_iterations_; + PW_LOG_DEBUG("Mean: %ld: ", static_cast<long>(mean_)); + PW_LOG_DEBUG("Minimum: %ld", static_cast<long>(min_)); + PW_LOG_DEBUG("Maxmimum: %ld", static_cast<long>(max_)); + event_handler_->TestCaseEnd(test_info, + Results{mean_, max_, min_, test_iterations_}); + return false; + } + iteration_start_ = internal::GetCurrentTimestamp(); + return true; +} + +} // namespace pw::perf_test diff --git a/pw_perf_test/state_test.cc b/pw_perf_test/state_test.cc index 647e47a3b..bd3e87330 100644 --- a/pw_perf_test/state_test.cc +++ b/pw_perf_test/state_test.cc @@ -12,9 +12,10 @@ // License for the specific language governing permissions and limitations under // the License. +#include "pw_perf_test/state.h" + #include "gtest/gtest.h" #include "pw_perf_test/event_handler.h" -#include "pw_perf_test/perf_test.h" namespace pw::perf_test { namespace { diff --git a/pw_perf_test/test_info.cc b/pw_perf_test/test_info.cc new file mode 100644 index 000000000..91a390ef0 --- /dev/null +++ b/pw_perf_test/test_info.cc @@ -0,0 +1,28 @@ +// Copyright 2023 The Pigweed Authors +// +// 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 +// +// https://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. + +#include "pw_perf_test/internal/test_info.h" + +#include "pw_perf_test/internal/framework.h" + +namespace pw::perf_test::internal { + +TestInfo::TestInfo(const char* test_name, void (*function_body)(State&)) + : run_(function_body), test_name_(test_name) { + // Once a TestInfo object is created by the macro, this adds itself to the + // list of registered tests + Framework::Get().RegisterTest(*this); +} + +} // namespace pw::perf_test::internal |