1 /* 2 * Copyright (C) 2018 The Android Open Source Project 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 INCLUDE_PERFETTO_BASE_WATCHDOG_POSIX_H_ 18 #define INCLUDE_PERFETTO_BASE_WATCHDOG_POSIX_H_ 19 20 #include "perfetto/base/thread_checker.h" 21 22 #include <atomic> 23 #include <condition_variable> 24 #include <mutex> 25 #include <thread> 26 27 namespace perfetto { 28 namespace base { 29 30 // Ensures that the calling program does not exceed certain hard limits on 31 // resource usage e.g. time, memory and CPU. If exceeded, the program is 32 // crashed. 33 class Watchdog { 34 public: 35 // Handle to the timer set to crash the program. If the handle is dropped, 36 // the timer is removed so the program does not crash. 37 class Timer { 38 public: 39 ~Timer(); 40 Timer(Timer&&) noexcept; 41 42 private: 43 friend class Watchdog; 44 45 explicit Timer(uint32_t ms); 46 Timer(const Timer&) = delete; 47 Timer& operator=(const Timer&) = delete; 48 49 timer_t timerid_ = nullptr; 50 }; 51 virtual ~Watchdog(); 52 53 static Watchdog* GetInstance(); 54 55 // Sets a timer which will crash the program in |ms| milliseconds if the 56 // returned handle is not destroyed before this point. 57 Timer CreateFatalTimer(uint32_t ms); 58 59 // Starts the watchdog thread which monitors the memory and CPU usage 60 // of the program. 61 void Start(); 62 63 // Sets a limit on the memory (defined as the RSS) used by the program 64 // averaged over the last |window_ms| milliseconds. If |kb| is 0, any 65 // existing limit is removed. 66 // Note: |window_ms| has to be a multiple of |polling_interval_ms_|. 67 void SetMemoryLimit(uint64_t bytes, uint32_t window_ms); 68 69 // Sets a limit on the CPU usage used by the program averaged over the last 70 // |window_ms| milliseconds. If |percentage| is 0, any existing limit is 71 // removed. 72 // Note: |window_ms| has to be a multiple of |polling_interval_ms_|. 73 void SetCpuLimit(uint32_t percentage, uint32_t window_ms); 74 75 protected: 76 // Protected for testing. 77 Watchdog(uint32_t polling_interval_ms); 78 79 private: 80 // Represents a ring buffer in which integer values can be stored. 81 class WindowedInterval { 82 public: 83 // Pushes a new value into a ring buffer wrapping if necessary and returns 84 // whether the ring buffer is full. 85 bool Push(uint64_t sample); 86 87 // Returns the mean of the values in the buffer. 88 double Mean() const; 89 90 // Clears the ring buffer while keeping the existing size. 91 void Clear(); 92 93 // Resets the size of the buffer as well as clearing it. 94 void Reset(size_t new_size); 95 96 // Gets the oldest value inserted in the buffer. The buffer must be full 97 // (i.e. Push returned true) before this method can be called. OldestWhenFull()98 uint64_t OldestWhenFull() const { 99 PERFETTO_CHECK(filled_); 100 return buffer_[position_]; 101 } 102 103 // Gets the newest value inserted in the buffer. The buffer must be full 104 // (i.e. Push returned true) before this method can be called. NewestWhenFull()105 uint64_t NewestWhenFull() const { 106 PERFETTO_CHECK(filled_); 107 return buffer_[(position_ + size_ - 1) % size_]; 108 } 109 110 // Returns the size of the ring buffer. size()111 size_t size() const { return size_; } 112 113 private: 114 bool filled_ = false; 115 size_t position_ = 0; 116 size_t size_ = 0; 117 std::unique_ptr<uint64_t[]> buffer_; 118 }; 119 120 explicit Watchdog(const Watchdog&) = delete; 121 Watchdog& operator=(const Watchdog&) = delete; 122 123 // Main method for the watchdog thread. 124 void ThreadMain(); 125 126 // Check each type of resource every |polling_interval_ms_| miillis. 127 void CheckMemory(uint64_t rss_bytes); 128 void CheckCpu(uint64_t cpu_time); 129 130 // Computes the time interval spanned by a given ring buffer with respect 131 // to |polling_interval_ms_|. 132 uint32_t WindowTimeForRingBuffer(const WindowedInterval& window); 133 134 const uint32_t polling_interval_ms_; 135 std::atomic<bool> enabled_{false}; 136 std::thread thread_; 137 std::condition_variable exit_signal_; 138 139 // --- Begin lock-protected members --- 140 141 std::mutex mutex_; 142 143 uint64_t memory_limit_bytes_ = 0; 144 WindowedInterval memory_window_bytes_; 145 146 uint32_t cpu_limit_percentage_ = 0; 147 WindowedInterval cpu_window_time_ticks_; 148 149 // --- End lock-protected members --- 150 }; 151 152 } // namespace base 153 } // namespace perfetto 154 #endif // INCLUDE_PERFETTO_BASE_WATCHDOG_POSIX_H_ 155