1*14675a02SAndroid Build Coastguard Worker /* 2*14675a02SAndroid Build Coastguard Worker * Copyright 2022 Google LLC 3*14675a02SAndroid Build Coastguard Worker * 4*14675a02SAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License"); 5*14675a02SAndroid Build Coastguard Worker * you may not use this file except in compliance with the License. 6*14675a02SAndroid Build Coastguard Worker * You may obtain a copy of the License at 7*14675a02SAndroid Build Coastguard Worker * 8*14675a02SAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0 9*14675a02SAndroid Build Coastguard Worker * 10*14675a02SAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software 11*14675a02SAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS, 12*14675a02SAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13*14675a02SAndroid Build Coastguard Worker * See the License for the specific language governing permissions and 14*14675a02SAndroid Build Coastguard Worker * limitations under the License. 15*14675a02SAndroid Build Coastguard Worker */ 16*14675a02SAndroid Build Coastguard Worker 17*14675a02SAndroid Build Coastguard Worker #include "fcp/base/wall_clock_stopwatch.h" 18*14675a02SAndroid Build Coastguard Worker 19*14675a02SAndroid Build Coastguard Worker #include <memory> 20*14675a02SAndroid Build Coastguard Worker 21*14675a02SAndroid Build Coastguard Worker #include "absl/synchronization/mutex.h" 22*14675a02SAndroid Build Coastguard Worker #include "absl/time/time.h" 23*14675a02SAndroid Build Coastguard Worker #include "fcp/base/monitoring.h" 24*14675a02SAndroid Build Coastguard Worker 25*14675a02SAndroid Build Coastguard Worker namespace fcp { 26*14675a02SAndroid Build Coastguard Worker 27*14675a02SAndroid Build Coastguard Worker namespace internal { 28*14675a02SAndroid Build Coastguard Worker class RealWallClockStopwatch : public WallClockStopwatch { 29*14675a02SAndroid Build Coastguard Worker public: 30*14675a02SAndroid Build Coastguard Worker RealWallClockStopwatch() = default; 31*14675a02SAndroid Build Coastguard Worker Start()32*14675a02SAndroid Build Coastguard Worker Handle Start() override ABSL_LOCKS_EXCLUDED(mutex_) { 33*14675a02SAndroid Build Coastguard Worker return WallClockStopwatch::Handle(this); 34*14675a02SAndroid Build Coastguard Worker } GetTotalDuration() const35*14675a02SAndroid Build Coastguard Worker absl::Duration GetTotalDuration() const override ABSL_LOCKS_EXCLUDED(mutex_) { 36*14675a02SAndroid Build Coastguard Worker absl::MutexLock lock(&mutex_); 37*14675a02SAndroid Build Coastguard Worker FCP_CHECK(started_count_ >= 0); 38*14675a02SAndroid Build Coastguard Worker if (latest_start_time_ == absl::InfiniteFuture()) { 39*14675a02SAndroid Build Coastguard Worker return previous_durations_; 40*14675a02SAndroid Build Coastguard Worker } 41*14675a02SAndroid Build Coastguard Worker return previous_durations_ + (absl::Now() - latest_start_time_); 42*14675a02SAndroid Build Coastguard Worker } 43*14675a02SAndroid Build Coastguard Worker 44*14675a02SAndroid Build Coastguard Worker private: StartInternal()45*14675a02SAndroid Build Coastguard Worker void StartInternal() override ABSL_LOCKS_EXCLUDED(mutex_) { 46*14675a02SAndroid Build Coastguard Worker absl::MutexLock lock(&mutex_); 47*14675a02SAndroid Build Coastguard Worker FCP_CHECK(started_count_ >= 0); 48*14675a02SAndroid Build Coastguard Worker started_count_++; 49*14675a02SAndroid Build Coastguard Worker if (started_count_ == 1) { 50*14675a02SAndroid Build Coastguard Worker latest_start_time_ = absl::Now(); 51*14675a02SAndroid Build Coastguard Worker } 52*14675a02SAndroid Build Coastguard Worker } StopInternal()53*14675a02SAndroid Build Coastguard Worker void StopInternal() override ABSL_LOCKS_EXCLUDED(mutex_) { 54*14675a02SAndroid Build Coastguard Worker absl::MutexLock lock(&mutex_); 55*14675a02SAndroid Build Coastguard Worker FCP_CHECK(started_count_ >= 1); 56*14675a02SAndroid Build Coastguard Worker started_count_--; 57*14675a02SAndroid Build Coastguard Worker if (started_count_ == 0) { 58*14675a02SAndroid Build Coastguard Worker previous_durations_ += absl::Now() - latest_start_time_; 59*14675a02SAndroid Build Coastguard Worker latest_start_time_ = absl::InfiniteFuture(); 60*14675a02SAndroid Build Coastguard Worker } 61*14675a02SAndroid Build Coastguard Worker } 62*14675a02SAndroid Build Coastguard Worker 63*14675a02SAndroid Build Coastguard Worker mutable absl::Mutex mutex_; 64*14675a02SAndroid Build Coastguard Worker int started_count_ ABSL_GUARDED_BY(mutex_) = 0; 65*14675a02SAndroid Build Coastguard Worker absl::Time latest_start_time_ ABSL_GUARDED_BY(mutex_) = 66*14675a02SAndroid Build Coastguard Worker absl::InfiniteFuture(); 67*14675a02SAndroid Build Coastguard Worker absl::Duration previous_durations_ ABSL_GUARDED_BY(mutex_) = 68*14675a02SAndroid Build Coastguard Worker absl::ZeroDuration(); 69*14675a02SAndroid Build Coastguard Worker }; 70*14675a02SAndroid Build Coastguard Worker 71*14675a02SAndroid Build Coastguard Worker // A noop stopwatch that does nothing (e.g. for use in tests or to 72*14675a02SAndroid Build Coastguard Worker // flag-off the measurement of something). 73*14675a02SAndroid Build Coastguard Worker class NoopWallClockStopwatch : public WallClockStopwatch { 74*14675a02SAndroid Build Coastguard Worker public: 75*14675a02SAndroid Build Coastguard Worker NoopWallClockStopwatch() = default; 76*14675a02SAndroid Build Coastguard Worker Start()77*14675a02SAndroid Build Coastguard Worker Handle Start() override { return Handle(nullptr); } GetTotalDuration() const78*14675a02SAndroid Build Coastguard Worker absl::Duration GetTotalDuration() const override { 79*14675a02SAndroid Build Coastguard Worker return absl::ZeroDuration(); 80*14675a02SAndroid Build Coastguard Worker } 81*14675a02SAndroid Build Coastguard Worker }; 82*14675a02SAndroid Build Coastguard Worker } // namespace internal 83*14675a02SAndroid Build Coastguard Worker Handle(WallClockStopwatch * stopwatch)84*14675a02SAndroid Build Coastguard WorkerWallClockStopwatch::Handle::Handle(WallClockStopwatch* stopwatch) 85*14675a02SAndroid Build Coastguard Worker : stopwatch_(stopwatch) { 86*14675a02SAndroid Build Coastguard Worker if (stopwatch_ != nullptr) { 87*14675a02SAndroid Build Coastguard Worker stopwatch_->StartInternal(); 88*14675a02SAndroid Build Coastguard Worker } 89*14675a02SAndroid Build Coastguard Worker } 90*14675a02SAndroid Build Coastguard Worker ~Handle()91*14675a02SAndroid Build Coastguard WorkerWallClockStopwatch::Handle::~Handle() { 92*14675a02SAndroid Build Coastguard Worker if (stopwatch_ != nullptr) { 93*14675a02SAndroid Build Coastguard Worker stopwatch_->StopInternal(); 94*14675a02SAndroid Build Coastguard Worker } 95*14675a02SAndroid Build Coastguard Worker } 96*14675a02SAndroid Build Coastguard Worker Create()97*14675a02SAndroid Build Coastguard Workerstd::unique_ptr<WallClockStopwatch> WallClockStopwatch::Create() { 98*14675a02SAndroid Build Coastguard Worker return std::make_unique<internal::RealWallClockStopwatch>(); 99*14675a02SAndroid Build Coastguard Worker } 100*14675a02SAndroid Build Coastguard Worker CreateNoop()101*14675a02SAndroid Build Coastguard Workerstd::unique_ptr<WallClockStopwatch> WallClockStopwatch::CreateNoop() { 102*14675a02SAndroid Build Coastguard Worker return std::make_unique<internal::NoopWallClockStopwatch>(); 103*14675a02SAndroid Build Coastguard Worker } 104*14675a02SAndroid Build Coastguard Worker 105*14675a02SAndroid Build Coastguard Worker } // namespace fcp 106