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