• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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