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