blob: 1bbca2cb9848ba8e020542a283a1351abd83acb7 [file] [log] [blame]
Alex Perrycb7da4b2019-08-28 19:35:56 -07001#include "aos/events/shm_event_loop.h"
Parker Schuhe4a70d62017-12-27 20:10:20 -08002
Austin Schuh5f1cc5c2019-12-01 18:01:11 -08003#include <string_view>
4
Alex Perrycb7da4b2019-08-28 19:35:56 -07005#include "aos/events/event_loop_param_test.h"
6#include "glog/logging.h"
Parker Schuhe4a70d62017-12-27 20:10:20 -08007#include "gtest/gtest.h"
8
Alex Perrycb7da4b2019-08-28 19:35:56 -07009#include "aos/events/test_message_generated.h"
10
11DECLARE_string(shm_base);
12
Parker Schuhe4a70d62017-12-27 20:10:20 -080013namespace aos {
14namespace testing {
15namespace {
Austin Schuh3115a202019-05-27 21:02:14 -070016namespace chrono = ::std::chrono;
Parker Schuhe4a70d62017-12-27 20:10:20 -080017
18class ShmEventLoopTestFactory : public EventLoopTestFactory {
19 public:
Alex Perrycb7da4b2019-08-28 19:35:56 -070020 ShmEventLoopTestFactory() {
21 // Put all the queue files in ${TEST_TMPDIR} if it is set, otherwise
22 // everything will be reusing /dev/shm when sharded.
23 char *test_tmpdir = getenv("TEST_TMPDIR");
24 if (test_tmpdir != nullptr) {
25 FLAGS_shm_base = std::string(test_tmpdir) + "/aos";
26 }
27
28 // Clean up anything left there before.
Austin Schuhde8a8ff2019-11-30 15:25:36 -080029 unlink((FLAGS_shm_base + "/test/aos.TestMessage.v0").c_str());
30 unlink((FLAGS_shm_base + "/test1/aos.TestMessage.v0").c_str());
31 unlink((FLAGS_shm_base + "/test2/aos.TestMessage.v0").c_str());
32 unlink((FLAGS_shm_base + "/test2/aos.TestMessage.v0").c_str());
Austin Schuh39788ff2019-12-01 18:22:57 -080033 unlink((FLAGS_shm_base + "/aos/aos.timing.Report.v0").c_str());
Alex Perrycb7da4b2019-08-28 19:35:56 -070034 }
35
Austin Schuh5f1cc5c2019-12-01 18:01:11 -080036 ::std::unique_ptr<EventLoop> Make(std::string_view name) override {
37 ::std::unique_ptr<EventLoop> loop(new ShmEventLoop(configuration()));
38 loop->set_name(name);
39 return loop;
Parker Schuhe4a70d62017-12-27 20:10:20 -080040 }
41
Austin Schuh5f1cc5c2019-12-01 18:01:11 -080042 ::std::unique_ptr<EventLoop> MakePrimary(std::string_view name) override {
Austin Schuh44019f92019-05-19 19:58:27 -070043 ::std::unique_ptr<ShmEventLoop> loop =
Alex Perrycb7da4b2019-08-28 19:35:56 -070044 ::std::unique_ptr<ShmEventLoop>(new ShmEventLoop(configuration()));
Austin Schuh44019f92019-05-19 19:58:27 -070045 primary_event_loop_ = loop.get();
Austin Schuh5f1cc5c2019-12-01 18:01:11 -080046 loop->set_name(name);
47 return std::move(loop);
Austin Schuh44019f92019-05-19 19:58:27 -070048 }
49
Alex Perrycb7da4b2019-08-28 19:35:56 -070050 void Run() override { CHECK_NOTNULL(primary_event_loop_)->Run(); }
Austin Schuh44019f92019-05-19 19:58:27 -070051
Alex Perrycb7da4b2019-08-28 19:35:56 -070052 void Exit() override { CHECK_NOTNULL(primary_event_loop_)->Exit(); }
Austin Schuh9fe68f72019-08-10 19:32:03 -070053
Austin Schuh52d325c2019-06-23 18:59:06 -070054 void SleepFor(::std::chrono::nanoseconds duration) override {
55 ::std::this_thread::sleep_for(duration);
56 }
57
Austin Schuh44019f92019-05-19 19:58:27 -070058 private:
Austin Schuh44019f92019-05-19 19:58:27 -070059 ::aos::ShmEventLoop *primary_event_loop_;
Parker Schuhe4a70d62017-12-27 20:10:20 -080060};
61
62INSTANTIATE_TEST_CASE_P(ShmEventLoopTest, AbstractEventLoopTest,
63 ::testing::Values([]() {
64 return new ShmEventLoopTestFactory();
65 }));
66
Austin Schuh6b6dfa52019-06-12 20:16:20 -070067INSTANTIATE_TEST_CASE_P(ShmEventLoopDeathTest, AbstractEventLoopDeathTest,
68 ::testing::Values([]() {
69 return new ShmEventLoopTestFactory();
70 }));
71
Parker Schuhe4a70d62017-12-27 20:10:20 -080072} // namespace
James Kuszmaulc79768b2019-02-18 15:08:44 -080073
Austin Schuh3115a202019-05-27 21:02:14 -070074bool IsRealtime() {
75 int scheduler;
Alex Perrycb7da4b2019-08-28 19:35:56 -070076 PCHECK((scheduler = sched_getscheduler(0)) != -1);
77
78 LOG(INFO) << "scheduler is " << scheduler;
Austin Schuh3115a202019-05-27 21:02:14 -070079 return scheduler == SCHED_FIFO || scheduler == SCHED_RR;
80}
James Kuszmaulc79768b2019-02-18 15:08:44 -080081
Austin Schuh3115a202019-05-27 21:02:14 -070082// Tests that every handler type is realtime and runs. There are threads
83// involved and it's easy to miss one.
84TEST(ShmEventLoopTest, AllHandlersAreRealtime) {
85 ShmEventLoopTestFactory factory;
Austin Schuh5f1cc5c2019-12-01 18:01:11 -080086 auto loop = factory.MakePrimary("primary");
87 auto loop2 = factory.Make("loop2");
Austin Schuh3115a202019-05-27 21:02:14 -070088
89 loop->SetRuntimeRealtimePriority(1);
90
91 auto sender = loop2->MakeSender<TestMessage>("/test");
92
93 bool did_onrun = false;
94 bool did_timer = false;
95 bool did_watcher = false;
96
Alex Perrycb7da4b2019-08-28 19:35:56 -070097 auto timer = loop->AddTimer([&did_timer, &factory]() {
Austin Schuh3115a202019-05-27 21:02:14 -070098 EXPECT_TRUE(IsRealtime());
99 did_timer = true;
Austin Schuh9fe68f72019-08-10 19:32:03 -0700100 factory.Exit();
Austin Schuh3115a202019-05-27 21:02:14 -0700101 });
102
103 loop->MakeWatcher("/test", [&did_watcher](const TestMessage &) {
104 EXPECT_TRUE(IsRealtime());
105 did_watcher = true;
106 });
107
108 loop->OnRun([&loop, &did_onrun, &sender, timer]() {
109 EXPECT_TRUE(IsRealtime());
110 did_onrun = true;
111 timer->Setup(loop->monotonic_now() + chrono::milliseconds(100));
Alex Perrycb7da4b2019-08-28 19:35:56 -0700112
113 aos::Sender<TestMessage>::Builder msg = sender.MakeBuilder();
114 TestMessage::Builder builder = msg.MakeBuilder<TestMessage>();
115 builder.add_value(200);
116 msg.Send(builder.Finish());
Austin Schuh3115a202019-05-27 21:02:14 -0700117 });
James Kuszmaulc79768b2019-02-18 15:08:44 -0800118
Austin Schuh3115a202019-05-27 21:02:14 -0700119 factory.Run();
James Kuszmaulc79768b2019-02-18 15:08:44 -0800120
Austin Schuh3115a202019-05-27 21:02:14 -0700121 EXPECT_TRUE(did_onrun);
122 EXPECT_TRUE(did_timer);
123 EXPECT_TRUE(did_watcher);
James Kuszmaulc79768b2019-02-18 15:08:44 -0800124}
Austin Schuh52d325c2019-06-23 18:59:06 -0700125
126// Tests that missing a deadline inside the function still results in PhasedLoop
127// running at the right offset.
128TEST(ShmEventLoopTest, DelayedPhasedLoop) {
129 ShmEventLoopTestFactory factory;
Austin Schuh5f1cc5c2019-12-01 18:01:11 -0800130 auto loop1 = factory.MakePrimary("primary");
Austin Schuh52d325c2019-06-23 18:59:06 -0700131
132 ::std::vector<::aos::monotonic_clock::time_point> times;
133
134 constexpr chrono::milliseconds kOffset = chrono::milliseconds(400);
135
136 loop1->AddPhasedLoop(
Austin Schuh9fe68f72019-08-10 19:32:03 -0700137 [&times, &loop1, &kOffset, &factory](int count) {
Austin Schuh52d325c2019-06-23 18:59:06 -0700138 const ::aos::monotonic_clock::time_point monotonic_now =
139 loop1->monotonic_now();
140
141 // Compute our offset.
142 const ::aos::monotonic_clock::duration remainder =
143 monotonic_now.time_since_epoch() -
144 chrono::duration_cast<chrono::seconds>(
145 monotonic_now.time_since_epoch());
146
147 // Make sure we we are called near where we should be even when we
148 // delay.
149 constexpr chrono::milliseconds kEpsilon(200);
150 EXPECT_LT(remainder, kOffset + kEpsilon);
151 EXPECT_GT(remainder, kOffset - kEpsilon);
152
153 // Confirm that we see the missed count when we sleep.
154 if (times.size() == 0) {
Austin Schuhde8a8ff2019-11-30 15:25:36 -0800155 CHECK_EQ(count, 1);
Austin Schuh52d325c2019-06-23 18:59:06 -0700156 } else {
Austin Schuhde8a8ff2019-11-30 15:25:36 -0800157 CHECK_EQ(count, 3);
Austin Schuh52d325c2019-06-23 18:59:06 -0700158 }
159
160 times.push_back(loop1->monotonic_now());
161 if (times.size() == 2) {
Austin Schuh9fe68f72019-08-10 19:32:03 -0700162 factory.Exit();
Austin Schuh52d325c2019-06-23 18:59:06 -0700163 }
164
165 // Now, add a large delay. This should push us up to 3 cycles.
166 ::std::this_thread::sleep_for(chrono::milliseconds(2500));
167 },
168 chrono::seconds(1), kOffset);
169
170 factory.Run();
171
172 EXPECT_EQ(times.size(), 2u);
173}
174
Austin Schuh39788ff2019-12-01 18:22:57 -0800175// TODO(austin): Test that missing a deadline with a timer recovers as expected.
176
Parker Schuhe4a70d62017-12-27 20:10:20 -0800177} // namespace testing
178} // namespace aos