don't make so many clock_gettime syscalls
For all of the code that runs periodically for short periods of time,
making more than just 1 syscall to figure out what time it currently is
is pointless and a waste of CPU.
diff --git a/aos/common/controls/control_loop-tmpl.h b/aos/common/controls/control_loop-tmpl.h
index dde33c0..baf352b 100644
--- a/aos/common/controls/control_loop-tmpl.h
+++ b/aos/common/controls/control_loop-tmpl.h
@@ -146,8 +146,12 @@
template <class T, bool has_position, bool fail_no_position, bool fail_no_goal>
void ControlLoop<T, has_position, fail_no_position, fail_no_goal>::Run() {
+ ::aos::time::Time::EnableMockTime();
while (true) {
- time::SleepUntil(NextLoopTime());
+ ::aos::time::Time::UpdateMockTime();
+ const ::aos::time::Time next_loop = NextLoopTime();
+ time::SleepUntil(next_loop);
+ ::aos::time::Time::SetMockTime(next_loop);
Iterate();
}
}
diff --git a/aos/common/controls/control_loop.h b/aos/common/controls/control_loop.h
index 0889b48..becb080 100644
--- a/aos/common/controls/control_loop.h
+++ b/aos/common/controls/control_loop.h
@@ -1,7 +1,7 @@
#ifndef AOS_CONTROL_LOOP_CONTROL_LOOP_H_
#define AOS_CONTROL_LOOP_CONTROL_LOOP_H_
-#include <cstring>
+#include <string.h>
#include "aos/common/type_traits.h"
#include "aos/common/queue.h"
diff --git a/aos/common/time.cc b/aos/common/time.cc
index 8a44010..88802e3 100644
--- a/aos/common/time.cc
+++ b/aos/common/time.cc
@@ -30,14 +30,28 @@
// TODO(aschuh): This doesn't include SleepFor and SleepUntil.
// TODO(aschuh): Create a clock source object and change the default?
// That would let me create a MockTime clock source.
+
+Time NowImpl(clockid_t clock) {
+ timespec temp;
+ if (clock_gettime(clock, &temp) != 0) {
+ LOG(FATAL, "clock_gettime(%jd, %p) failed with %d: %s\n",
+ static_cast<uintmax_t>(clock), &temp, errno, strerror(errno));
+ }
+ return Time(temp);
}
+} // namespace
+
void Time::EnableMockTime(const Time &now) {
- mock_time_enabled = true;
MutexLocker time_mutex_locker(&time_mutex);
+ mock_time_enabled = true;
current_mock_time = now;
}
+void Time::UpdateMockTime() {
+ SetMockTime(NowImpl(kDefaultClock));
+}
+
void Time::DisableMockTime() {
MutexLocker time_mutex_locker(&time_mutex);
mock_time_enabled = false;
@@ -45,7 +59,7 @@
void Time::SetMockTime(const Time &now) {
MutexLocker time_mutex_locker(&time_mutex);
- if (!mock_time_enabled) {
+ if (__builtin_expect(!mock_time_enabled, 0)) {
LOG(FATAL, "Tried to set mock time and mock time is not enabled\n");
}
current_mock_time = now;
@@ -58,17 +72,13 @@
}
Time Time::Now(clockid_t clock) {
- if (mock_time_enabled) {
+ {
MutexLocker time_mutex_locker(&time_mutex);
- return current_mock_time;
- } else {
- timespec temp;
- if (clock_gettime(clock, &temp) != 0) {
- LOG(FATAL, "clock_gettime(%jd, %p) failed with %d: %s\n",
- static_cast<uintmax_t>(clock), &temp, errno, strerror(errno));
+ if (mock_time_enabled) {
+ return current_mock_time;
}
- return Time(temp);
}
+ return NowImpl(clock);
}
void Time::CheckImpl(int32_t nsec) {
diff --git a/aos/common/time.h b/aos/common/time.h
index 1dc1def..846366c 100644
--- a/aos/common/time.h
+++ b/aos/common/time.h
@@ -10,6 +10,7 @@
#include <ostream>
#include "aos/common/type_traits.h"
+#include "aos/common/macros.h"
namespace aos {
namespace time {
@@ -206,7 +207,9 @@
// Enables returning the mock time value for Now instead of checking the
// system clock. This should only be used when testing things depending on
// time, or many things may/will break.
- static void EnableMockTime(const Time &now);
+ static void EnableMockTime(const Time &now = Now());
+ // Calls SetMockTime with the current actual time.
+ static void UpdateMockTime();
// Sets now when time is being mocked.
static void SetMockTime(const Time &now);
// Convenience function to just increment the mock time by a certain amount in
@@ -239,6 +242,21 @@
// Sleeps until clock is at the time represented by time.
void SleepUntil(const Time &time, clockid_t clock = Time::kDefaultClock);
+// RAII class that freezes Time::Now() (to avoid making large numbers of
+// syscalls to find the real time).
+class TimeFreezer {
+ public:
+ TimeFreezer() {
+ Time::EnableMockTime();
+ }
+ ~TimeFreezer() {
+ Time::DisableMockTime();
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(TimeFreezer);
+};
+
} // namespace time
} // namespace aos
diff --git a/aos/prime/output/motor_output.cc b/aos/prime/output/motor_output.cc
index 95428b1..c02a11b 100644
--- a/aos/prime/output/motor_output.cc
+++ b/aos/prime/output/motor_output.cc
@@ -45,8 +45,11 @@
}
void MotorOutput::Run() {
+ ::aos::time::Time::EnableMockTime();
while (true) {
+ ::aos::time::Time::UpdateMockTime();
time::PhasedLoopXMS(5, 1000);
+ ::aos::time::Time::UpdateMockTime();
values_.digital_module = -1;
// 0 means output disabled.
diff --git a/bbb_cape/src/bbb/uart_reader.cc b/bbb_cape/src/bbb/uart_reader.cc
index 7f88d51..fe1c526 100644
--- a/bbb_cape/src/bbb/uart_reader.cc
+++ b/bbb_cape/src/bbb/uart_reader.cc
@@ -56,13 +56,13 @@
ssize_t UartReader::ReadBytes(uint8_t *dest, size_t max_bytes,
const ::aos::time::Time &timeout_time) {
+ fd_set fds;
+ FD_ZERO(&fds);
do {
::aos::time::Time timeout = timeout_time - ::aos::time::Time::Now();
if (timeout < ::aos::time::Time(0, 0)) return -2;
struct timeval timeout_timeval = timeout.ToTimeval();
- fd_set fds;
- FD_ZERO(&fds);
- FD_SET(fd_, &fds);
+ FD_SET(fd_, &fds);
switch (select(fd_ + 1, &fds, NULL, NULL, &timeout_timeval)) {
case 0:
return -2;
diff --git a/frc971/input/sensor_receiver.cc b/frc971/input/sensor_receiver.cc
index ed44d98..3c16b39 100644
--- a/frc971/input/sensor_receiver.cc
+++ b/frc971/input/sensor_receiver.cc
@@ -145,6 +145,8 @@
void PacketReceived(const ::bbb::DataStruct *data,
const ::aos::time::Time &cape_timestamp,
State *state) {
+ ::aos::time::TimeFreezer time_freezer;
+
::frc971::logging_structs::CapeReading reading_to_log(
cape_timestamp, static_cast<uint16_t>(sizeof(*data)),
sonar_translate(data->main.ultrasonic_pulse_length),