1 /* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */ 2 /* 3 * Copyright 2018 Couchbase, Inc 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18 #include <chrono> 19 20 #include "phosphor.h" 21 #include "trace_log.h" 22 23 namespace phosphor { 24 struct tracepoint_info; 25 26 /** 27 * RAII-style object which captures the arguments for a scoped event. 28 * 29 * If enabled==true, saves the time of object creation; upon destruction 30 * records end time and logs an event. 31 * If !enabled; then no times are recorded and no event logged. 32 */ 33 template <typename T, typename U> 34 struct ScopedEventGuard { ScopedEventGuardphosphor::ScopedEventGuard35 ScopedEventGuard(const tracepoint_info* tpi_, 36 bool enabled_, 37 T arg1_, 38 U arg2_) 39 : tpi(tpi_), enabled(enabled_), arg1(arg1_), arg2(arg2_) { 40 if (enabled) { 41 start = std::chrono::steady_clock::now(); 42 } 43 } 44 ~ScopedEventGuardphosphor::ScopedEventGuard45 ~ScopedEventGuard() { 46 if (enabled) { 47 const auto end = std::chrono::steady_clock::now(); 48 TraceLog::getInstance().logEvent( 49 tpi, start, end - start, arg1, arg2); 50 } 51 } 52 53 const tracepoint_info* tpi; 54 const bool enabled; 55 const T arg1; 56 const U arg2; 57 std::chrono::steady_clock::time_point start; 58 }; 59 60 /** 61 * RAII-style object to record events for acquiring and locking a mutex. 62 * Locks the underlying mutex on construction, unlocks when it goes out of 63 * scope; measuring two timespans: 64 * 1. Time taken to acquire the mutex. 65 * 2. Time the mutex is held for. 66 * 67 * @tparam Mutex Type of mutex to guard. 68 */ 69 template <class Mutex> 70 class MutexEventGuard { 71 public: 72 /** 73 * Acquires ownership of the specified mutex. 74 * 75 * If enabled is true, records the time spent waiting for the lock. Upon 76 * destruction, events will be logged with the specified details. 77 * @threshold Minimum duration that either the lock or acquire span must 78 * take for events to be logged. 79 */ MutexEventGuard(const tracepoint_info* tpiWait_, const tracepoint_info* tpiHeld_, bool enabled_, Mutex& mutex_, std::chrono::steady_clock::duration threshold_ = std::chrono::steady_clock::duration::zero())80 MutexEventGuard(const tracepoint_info* tpiWait_, 81 const tracepoint_info* tpiHeld_, 82 bool enabled_, 83 Mutex& mutex_, 84 std::chrono::steady_clock::duration threshold_ = 85 std::chrono::steady_clock::duration::zero()) 86 : tpiWait(tpiWait_), 87 tpiHeld(tpiHeld_), 88 enabled(enabled_), 89 mutex(mutex_), 90 threshold(threshold_) { 91 if (enabled) { 92 start = std::chrono::steady_clock::now(); 93 mutex.lock(); 94 lockedAt = std::chrono::steady_clock::now(); 95 } else { 96 mutex.lock(); 97 } 98 } 99 100 /// Unlocks the mutex, and records trace events if enabled. ~MutexEventGuard()101 ~MutexEventGuard() { 102 mutex.unlock(); 103 if (enabled) { 104 releasedAt = std::chrono::steady_clock::now(); 105 const auto waitTime = lockedAt - start; 106 const auto heldTime = releasedAt - lockedAt; 107 if (waitTime > threshold || heldTime > threshold) { 108 auto& traceLog = TraceLog::getInstance(); 109 traceLog.logEvent(tpiWait, 110 start, 111 waitTime, 112 reinterpret_cast<void*>(&mutex), 113 NoneType()); 114 traceLog.logEvent(tpiHeld, 115 lockedAt, 116 heldTime, 117 reinterpret_cast<void*>(&mutex), 118 NoneType()); 119 } 120 } 121 } 122 123 private: 124 const tracepoint_info* tpiWait; 125 const tracepoint_info* tpiHeld; 126 const bool enabled; 127 Mutex& mutex; 128 const std::chrono::steady_clock::duration threshold; 129 std::chrono::steady_clock::time_point start; 130 std::chrono::steady_clock::time_point lockedAt; 131 std::chrono::steady_clock::time_point releasedAt; 132 }; 133 134 } // namespace phosphor 135