blob: ef7c9d7fac258f6aa1d14f7d6b4e1779e0ad7e37 [file] [log] [blame]
Alex Perrycb7da4b2019-08-28 19:35:56 -07001#include "aos/realtime.h"
2
Austin Schuhcc6070c2020-10-10 20:25:56 -07003#include <errno.h>
4#include <malloc.h>
5#include <sched.h>
6#include <stdint.h>
Alex Perrycb7da4b2019-08-28 19:35:56 -07007#include <stdio.h>
Austin Schuhcc6070c2020-10-10 20:25:56 -07008#include <stdlib.h>
Alex Perrycb7da4b2019-08-28 19:35:56 -07009#include <string.h>
10#include <sys/mman.h>
Austin Schuhcc6070c2020-10-10 20:25:56 -070011#include <sys/prctl.h>
Alex Perrycb7da4b2019-08-28 19:35:56 -070012#include <sys/resource.h>
13#include <sys/types.h>
14#include <unistd.h>
Alex Perrycb7da4b2019-08-28 19:35:56 -070015
Austin Schuhcc6070c2020-10-10 20:25:56 -070016#include "aos/thread_local.h"
Alex Perrycb7da4b2019-08-28 19:35:56 -070017#include "glog/logging.h"
18
Austin Schuh27553152020-11-18 21:26:37 -080019DEFINE_bool(skip_realtime_scheduler, false,
20 "If true, skip changing the scheduler. Pretend that we changed "
21 "the scheduler instead.");
22DEFINE_bool(skip_locking_memory, false,
23 "If true, skip locking memory. Pretend that we did it instead.");
24
Alex Perrycb7da4b2019-08-28 19:35:56 -070025namespace FLAG__namespace_do_not_use_directly_use_DECLARE_double_instead {
26extern double FLAGS_tcmalloc_release_rate __attribute__((weak));
27}
28using FLAG__namespace_do_not_use_directly_use_DECLARE_double_instead::
29 FLAGS_tcmalloc_release_rate;
30
31namespace aos {
32namespace logging {
33namespace internal {
34
35// Implemented in aos/logging/context.cc.
36void ReloadThreadName() __attribute__((weak));
37
38} // namespace internal
39} // namespace logging
40
41namespace {
42
Austin Schuh27553152020-11-18 21:26:37 -080043enum class SetLimitForRoot { kYes, kNo };
James Kuszmaulb4874eb2020-01-18 17:50:35 -080044
Austin Schuh27553152020-11-18 21:26:37 -080045enum class AllowSoftLimitDecrease { kYes, kNo };
James Kuszmaulb4874eb2020-01-18 17:50:35 -080046
47void SetSoftRLimit(
48 int resource, rlim64_t soft, SetLimitForRoot set_for_root,
Austin Schuh27553152020-11-18 21:26:37 -080049 std::string_view help_string,
James Kuszmaulb4874eb2020-01-18 17:50:35 -080050 AllowSoftLimitDecrease allow_decrease = AllowSoftLimitDecrease::kYes) {
Alex Perrycb7da4b2019-08-28 19:35:56 -070051 bool am_root = getuid() == 0;
James Kuszmaulb4874eb2020-01-18 17:50:35 -080052 if (set_for_root == SetLimitForRoot::kYes || !am_root) {
Alex Perrycb7da4b2019-08-28 19:35:56 -070053 struct rlimit64 rlim;
54 PCHECK(getrlimit64(resource, &rlim) == 0)
Brian Silverman6a54ff32020-04-28 16:41:39 -070055 << ": getting limit for " << resource;
Alex Perrycb7da4b2019-08-28 19:35:56 -070056
James Kuszmaulb4874eb2020-01-18 17:50:35 -080057 if (allow_decrease == AllowSoftLimitDecrease::kYes) {
58 rlim.rlim_cur = soft;
59 } else {
60 rlim.rlim_cur = std::max(rlim.rlim_cur, soft);
61 }
Alex Perrycb7da4b2019-08-28 19:35:56 -070062 rlim.rlim_max = ::std::max(rlim.rlim_max, soft);
63
64 PCHECK(setrlimit64(resource, &rlim) == 0)
Brian Silverman6a54ff32020-04-28 16:41:39 -070065 << ": changing limit for " << resource << " to " << rlim.rlim_cur
Austin Schuh27553152020-11-18 21:26:37 -080066 << " with max of " << rlim.rlim_max << help_string;
Alex Perrycb7da4b2019-08-28 19:35:56 -070067 }
68}
69
70} // namespace
71
72void LockAllMemory() {
Austin Schuhcc6070c2020-10-10 20:25:56 -070073 CheckNotRealtime();
Alex Perrycb7da4b2019-08-28 19:35:56 -070074 // Allow locking as much as we want into RAM.
Austin Schuh27553152020-11-18 21:26:37 -080075 SetSoftRLimit(RLIMIT_MEMLOCK, RLIM_INFINITY, SetLimitForRoot::kNo,
76 "use --skip_locking_memory to not lock memory.");
Alex Perrycb7da4b2019-08-28 19:35:56 -070077
78 WriteCoreDumps();
Austin Schuh27553152020-11-18 21:26:37 -080079 PCHECK(mlockall(MCL_CURRENT | MCL_FUTURE) == 0)
80 << ": Failed to lock memory, use --skip_locking_memory to bypass this. "
81 "Bypassing will impact RT performance.";
Alex Perrycb7da4b2019-08-28 19:35:56 -070082
Brian Silverman4dbbcce2020-09-18 15:27:38 -070083#if !__has_feature(address_sanitizer) && !__has_feature(memory_sanitizer)
Alex Perrycb7da4b2019-08-28 19:35:56 -070084 // Don't give freed memory back to the OS.
85 CHECK_EQ(1, mallopt(M_TRIM_THRESHOLD, -1));
86 // Don't use mmap for large malloc chunks.
87 CHECK_EQ(1, mallopt(M_MMAP_MAX, 0));
Austin Schuh85faf672020-09-10 22:58:46 -070088#endif
Alex Perrycb7da4b2019-08-28 19:35:56 -070089
90 if (&FLAGS_tcmalloc_release_rate) {
91 // Tell tcmalloc not to return memory.
92 FLAGS_tcmalloc_release_rate = 0.0;
93 }
94
95 // Forces the memory pages for all the stack space that we're ever going to
96 // use to be loaded into memory (so it can be locked there).
97 uint8_t data[4096 * 8];
98 // Not 0 because linux might optimize that to a 0-filled page.
99 memset(data, 1, sizeof(data));
Austin Schuh27553152020-11-18 21:26:37 -0800100 __asm__ __volatile__("" ::"m"(data));
Alex Perrycb7da4b2019-08-28 19:35:56 -0700101
102 static const size_t kHeapPreallocSize = 512 * 1024;
103 char *const heap_data = static_cast<char *>(malloc(kHeapPreallocSize));
104 memset(heap_data, 1, kHeapPreallocSize);
Austin Schuh27553152020-11-18 21:26:37 -0800105 __asm__ __volatile__("" ::"m"(heap_data));
Alex Perrycb7da4b2019-08-28 19:35:56 -0700106 free(heap_data);
107}
108
109void InitRT() {
Austin Schuh27553152020-11-18 21:26:37 -0800110 if (FLAGS_skip_locking_memory) {
111 LOG(WARNING) << "Ignoring request to lock all memory due to "
112 "--skip_locking_memory.";
113 return;
114 }
115
Austin Schuhcc6070c2020-10-10 20:25:56 -0700116 CheckNotRealtime();
Alex Perrycb7da4b2019-08-28 19:35:56 -0700117 LockAllMemory();
118
Austin Schuh27553152020-11-18 21:26:37 -0800119 if (FLAGS_skip_realtime_scheduler) {
120 return;
121 }
Alex Perrycb7da4b2019-08-28 19:35:56 -0700122 // Only let rt processes run for 3 seconds straight.
Austin Schuh27553152020-11-18 21:26:37 -0800123 SetSoftRLimit(
124 RLIMIT_RTTIME, 3000000, SetLimitForRoot::kYes,
125 ", use --skip_realtime_scheduler to stay non-rt and bypass this "
126 "warning.");
Alex Perrycb7da4b2019-08-28 19:35:56 -0700127
128 // Allow rt processes up to priority 40.
Austin Schuh27553152020-11-18 21:26:37 -0800129 SetSoftRLimit(
130 RLIMIT_RTPRIO, 40, SetLimitForRoot::kNo,
131 ", use --skip_realtime_scheduler to stay non-rt and bypass this "
132 "warning.");
Alex Perrycb7da4b2019-08-28 19:35:56 -0700133}
134
135void UnsetCurrentThreadRealtimePriority() {
136 struct sched_param param;
137 param.sched_priority = 0;
Brian Silverman6a54ff32020-04-28 16:41:39 -0700138 PCHECK(sched_setscheduler(0, SCHED_OTHER, &param) == 0);
Austin Schuhcc6070c2020-10-10 20:25:56 -0700139 MarkRealtime(false);
Brian Silverman6a54ff32020-04-28 16:41:39 -0700140}
141
142void SetCurrentThreadAffinity(const cpu_set_t &cpuset) {
143 PCHECK(sched_setaffinity(0, sizeof(cpuset), &cpuset) == 0);
Alex Perrycb7da4b2019-08-28 19:35:56 -0700144}
145
James Kuszmaul57c2baa2020-01-19 14:52:52 -0800146void SetCurrentThreadName(const std::string_view name) {
Alex Perrycb7da4b2019-08-28 19:35:56 -0700147 CHECK_LE(name.size(), 16u) << ": thread name '" << name << "' too long";
148 VLOG(1) << "This thread is changing to '" << name << "'";
James Kuszmaul57c2baa2020-01-19 14:52:52 -0800149 std::string string_name(name);
Brian Silverman6a54ff32020-04-28 16:41:39 -0700150 PCHECK(prctl(PR_SET_NAME, string_name.c_str()) == 0)
151 << ": changing name to " << string_name;
Alex Perrycb7da4b2019-08-28 19:35:56 -0700152 if (&logging::internal::ReloadThreadName != nullptr) {
153 logging::internal::ReloadThreadName();
154 }
155}
156
157void SetCurrentThreadRealtimePriority(int priority) {
Austin Schuh27553152020-11-18 21:26:37 -0800158 if (FLAGS_skip_realtime_scheduler) {
159 LOG(WARNING) << "Ignoring request to switch to the RT scheduler due to "
160 "--skip_realtime_scheduler.";
161 return;
162 }
Alex Perrycb7da4b2019-08-28 19:35:56 -0700163 // Make sure we will only be allowed to run for 3 seconds straight.
Austin Schuh27553152020-11-18 21:26:37 -0800164 SetSoftRLimit(
165 RLIMIT_RTTIME, 3000000, SetLimitForRoot::kYes,
166 ", use --skip_realtime_scheduler to stay non-rt and bypass this "
167 "warning.");
Alex Perrycb7da4b2019-08-28 19:35:56 -0700168
Brian Silvermanb3826f52020-07-02 19:41:18 -0700169 // Raise our soft rlimit if necessary.
Austin Schuh27553152020-11-18 21:26:37 -0800170 SetSoftRLimit(
171 RLIMIT_RTPRIO, priority, SetLimitForRoot::kNo,
172 ", use --skip_realtime_scheduler to stay non-rt and bypass this "
173 "warning.",
174 AllowSoftLimitDecrease::kNo);
Brian Silvermanb3826f52020-07-02 19:41:18 -0700175
Alex Perrycb7da4b2019-08-28 19:35:56 -0700176 struct sched_param param;
177 param.sched_priority = priority;
Austin Schuhcc6070c2020-10-10 20:25:56 -0700178 MarkRealtime(true);
Alex Perrycb7da4b2019-08-28 19:35:56 -0700179 PCHECK(sched_setscheduler(0, SCHED_FIFO, &param) == 0)
Austin Schuh27553152020-11-18 21:26:37 -0800180 << ": changing to SCHED_FIFO with " << priority
181 << ", if you want to bypass this check for testing, use "
182 "--skip_realtime_scheduler";
Alex Perrycb7da4b2019-08-28 19:35:56 -0700183}
184
185void WriteCoreDumps() {
186 // Do create core files of unlimited size.
Austin Schuh27553152020-11-18 21:26:37 -0800187 SetSoftRLimit(RLIMIT_CORE, RLIM_INFINITY, SetLimitForRoot::kYes, "");
James Kuszmaulb4874eb2020-01-18 17:50:35 -0800188}
189
190void ExpandStackSize() {
Austin Schuh27553152020-11-18 21:26:37 -0800191 SetSoftRLimit(RLIMIT_STACK, 1000000, SetLimitForRoot::kYes, "",
James Kuszmaulb4874eb2020-01-18 17:50:35 -0800192 AllowSoftLimitDecrease::kNo);
Alex Perrycb7da4b2019-08-28 19:35:56 -0700193}
194
Austin Schuhcc6070c2020-10-10 20:25:56 -0700195namespace {
196AOS_THREAD_LOCAL bool is_realtime = false;
197}
198
199bool MarkRealtime(bool realtime) {
200 const bool prior = is_realtime;
201 is_realtime = realtime;
202 return prior;
203}
204
205void CheckRealtime() { CHECK(is_realtime); }
206
207void CheckNotRealtime() { CHECK(!is_realtime); }
208
209ScopedRealtimeRestorer::ScopedRealtimeRestorer() : prior_(is_realtime) {}
210
Alex Perrycb7da4b2019-08-28 19:35:56 -0700211} // namespace aos