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 #ifndef FCP_BASE_WALL_CLOCK_STOPWATCH_H_ 18 #define FCP_BASE_WALL_CLOCK_STOPWATCH_H_ 19 20 #include <memory> 21 22 #include "absl/synchronization/mutex.h" 23 #include "absl/time/time.h" 24 25 namespace fcp { 26 27 namespace internal { 28 class RealWallClockStopwatch; 29 class NoopWallClockStopwatch; 30 } // namespace internal 31 32 // A utility for measuring wall clock time across multiple threads. 33 // 34 // This class is non-reentrant: `Start()` should only be called once per thread 35 // (but once `Stop()` has been called, `Start()` may be called again). 36 class WallClockStopwatch { 37 public: 38 static std::unique_ptr<WallClockStopwatch> Create(); 39 static std::unique_ptr<WallClockStopwatch> CreateNoop(); 40 // Disable copy and move semantics. 41 WallClockStopwatch(const WallClockStopwatch&) = delete; 42 WallClockStopwatch& operator=(const WallClockStopwatch&) = delete; 43 44 // A handle that stops the stopwatch once destroyed. 45 class Handle { 46 public: 47 // Disable copy and move semantics. 48 Handle(const Handle&) = delete; 49 Handle& operator=(const Handle&) = delete; 50 ~Handle(); 51 52 private: 53 // If `stopwatch` is a nullptr then the Handle that does nothing (for use in 54 // testing or flagging-off the measurement with a real stopwatch). 55 explicit Handle(WallClockStopwatch* stopwatch); 56 57 WallClockStopwatch* const stopwatch_; 58 friend internal::RealWallClockStopwatch; 59 friend internal::NoopWallClockStopwatch; 60 }; 61 62 // Start the stopwatch from this thread. If it wasn't running yet from any 63 // other thread, then time will start being accumulated from this point on. 64 // If it was already running from another thread then this call will have no 65 // immediate effect. 66 // 67 // Once the returned Handle is destroyed, the stopwatch is stopped from this 68 // thread. If it isn't running from any other thread, then time will stop 69 // being accumulated from that point on. If it still running from another 70 // thread then Handle destruction will have no immediate effect. 71 virtual Handle Start() = 0; 72 73 // Get the total duration of wall clock time that the stopwatch has run for, 74 // up until this moment (i.e. including any still-ongoing measurement). 75 virtual absl::Duration GetTotalDuration() const = 0; 76 77 virtual ~WallClockStopwatch() = default; 78 79 private: 80 WallClockStopwatch() = default; StartInternal()81 virtual void StartInternal() {} StopInternal()82 virtual void StopInternal() {} 83 friend internal::RealWallClockStopwatch; 84 friend internal::NoopWallClockStopwatch; 85 }; 86 87 } // namespace fcp 88 89 #endif // FCP_BASE_WALL_CLOCK_STOPWATCH_H_ 90