xref: /aosp_15_r20/external/federated-compute/fcp/base/wall_clock_stopwatch.cc (revision 14675a029014e728ec732f129a32e299b2da0601)
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)84 WallClockStopwatch::Handle::Handle(WallClockStopwatch* stopwatch)
85     : stopwatch_(stopwatch) {
86   if (stopwatch_ != nullptr) {
87     stopwatch_->StartInternal();
88   }
89 }
90 
~Handle()91 WallClockStopwatch::Handle::~Handle() {
92   if (stopwatch_ != nullptr) {
93     stopwatch_->StopInternal();
94   }
95 }
96 
Create()97 std::unique_ptr<WallClockStopwatch> WallClockStopwatch::Create() {
98   return std::make_unique<internal::RealWallClockStopwatch>();
99 }
100 
CreateNoop()101 std::unique_ptr<WallClockStopwatch> WallClockStopwatch::CreateNoop() {
102   return std::make_unique<internal::NoopWallClockStopwatch>();
103 }
104 
105 }  // namespace fcp
106