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