| /* |
| * Copyright 2019 The Android Open Source Project |
| * |
| * 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. |
| */ |
| |
| #include <chrono> |
| #include <future> |
| #include <unordered_map> |
| |
| #include "benchmark/benchmark.h" |
| |
| #include "os/alarm.h" |
| #include "os/repeating_alarm.h" |
| #include "os/thread.h" |
| |
| using ::benchmark::State; |
| using ::bluetooth::os::Alarm; |
| using ::bluetooth::os::RepeatingAlarm; |
| using ::bluetooth::os::Thread; |
| |
| class BM_ReactableAlarm : public ::benchmark::Fixture { |
| protected: |
| void SetUp(State& st) override { |
| ::benchmark::Fixture::SetUp(st); |
| thread_ = std::make_unique<Thread>("timer_benchmark", Thread::Priority::REAL_TIME); |
| alarm_ = std::make_unique<Alarm>(thread_.get()); |
| repeating_alarm_ = std::make_unique<RepeatingAlarm>(thread_.get()); |
| map_.clear(); |
| scheduled_tasks_ = 0; |
| task_length_ = 0; |
| task_interval_ = 0; |
| task_counter_ = 0; |
| promise_ = std::promise<void>(); |
| } |
| |
| void TearDown(State& st) override { |
| alarm_ = nullptr; |
| repeating_alarm_ = nullptr; |
| thread_->Stop(); |
| thread_ = nullptr; |
| ::benchmark::Fixture::TearDown(st); |
| } |
| |
| void AlarmSleepAndCountDelayedTime() { |
| auto end_time = std::chrono::steady_clock::now(); |
| auto duration_since_start = std::chrono::duration_cast<std::chrono::milliseconds>(end_time - start_time_); |
| task_counter_++; |
| map_[duration_since_start.count() - task_counter_ * task_interval_]++; |
| std::this_thread::sleep_for(std::chrono::milliseconds(task_length_)); |
| if (task_counter_ >= scheduled_tasks_) { |
| promise_.set_value(); |
| } |
| } |
| |
| void TimerFire() { |
| promise_.set_value(); |
| } |
| |
| int64_t scheduled_tasks_; |
| int64_t task_length_; |
| int64_t task_interval_; |
| int task_counter_; |
| std::unordered_map<int, int> map_; |
| std::promise<void> promise_; |
| std::chrono::time_point<std::chrono::steady_clock> start_time_; |
| std::unique_ptr<Thread> thread_; |
| std::unique_ptr<Alarm> alarm_; |
| std::unique_ptr<RepeatingAlarm> repeating_alarm_; |
| }; |
| |
| BENCHMARK_DEFINE_F(BM_ReactableAlarm, timer_performance_ms)(State& state) { |
| auto milliseconds = static_cast<int>(state.range(0)); |
| for (auto _ : state) { |
| auto start_time_point = std::chrono::steady_clock::now(); |
| alarm_->Schedule([this] { return TimerFire(); }, std::chrono::milliseconds(milliseconds)); |
| promise_.get_future().get(); |
| auto end_time_point = std::chrono::steady_clock::now(); |
| auto duration = std::chrono::duration_cast<std::chrono::nanoseconds>(end_time_point - start_time_point); |
| state.SetIterationTime(static_cast<double>(duration.count()) * 1e-6); |
| alarm_->Cancel(); |
| } |
| }; |
| |
| BENCHMARK_REGISTER_F(BM_ReactableAlarm, timer_performance_ms) |
| ->Arg(1) |
| ->Arg(5) |
| ->Arg(10) |
| ->Arg(20) |
| ->Arg(100) |
| ->Arg(1000) |
| ->Arg(2000) |
| ->Iterations(1) |
| ->UseRealTime(); |
| |
| BENCHMARK_DEFINE_F(BM_ReactableAlarm, periodic_accuracy)(State& state) { |
| for (auto _ : state) { |
| scheduled_tasks_ = state.range(0); |
| task_length_ = state.range(1); |
| task_interval_ = state.range(2); |
| start_time_ = std::chrono::steady_clock::now(); |
| repeating_alarm_->Schedule([this] { AlarmSleepAndCountDelayedTime(); }, std::chrono::milliseconds(task_interval_)); |
| promise_.get_future().get(); |
| repeating_alarm_->Cancel(); |
| } |
| for (const auto& delay : map_) { |
| state.counters[std::to_string(delay.first)] = delay.second; |
| } |
| }; |
| |
| BENCHMARK_REGISTER_F(BM_ReactableAlarm, periodic_accuracy) |
| ->Args({2000, 1, 5}) |
| ->Args({2000, 3, 5}) |
| ->Args({2000, 1, 7}) |
| ->Args({2000, 3, 7}) |
| ->Args({2000, 1, 20}) |
| ->Args({2000, 5, 20}) |
| ->Args({2000, 10, 20}) |
| ->Args({2000, 15, 20}) |
| ->Iterations(1) |
| ->UseRealTime(); |