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