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