From 685f509a4335a63680cd1ce7d508900d0c95ac08 Mon Sep 17 00:00:00 2001 From: Martin Stein Date: Wed, 31 May 2017 15:24:56 +0200 Subject: [PATCH] timer connection: no interpolation on arm w/o hw On ARM, we do not have a component-local hardware time-source. The ARM performance counter has no reliable frequency as the ARM idle command halts the counter. Thus, we do not do local time interpolation on ARM. Except we're on the HW kernel. In this case we can read out the kernel time instead. Ref #2435 --- repos/base-foc/lib/mk/base-foc.inc | 2 +- repos/base-foc/lib/mk/spec/arm/base-foc.mk | 2 + repos/base-foc/lib/mk/spec/x86/base-foc.mk | 2 + repos/base-hw/lib/mk/timeout-hw.mk | 1 + repos/base-linux/lib/mk/base-linux.mk | 2 +- .../base-linux/lib/mk/spec/arm/base-linux.mk | 2 + .../base-linux/lib/mk/spec/x86/base-linux.mk | 2 + repos/os/lib/mk/timeout-arm.mk | 10 ++ repos/os/lib/mk/timeout.mk | 1 + .../lib/timeout/arm/timer_connection_time.cc | 32 +++++ .../timeout/hw/timer_connection_timestamp.cc | 5 + repos/os/src/lib/timeout/timer_connection.cc | 101 --------------- .../src/lib/timeout/timer_connection_time.cc | 120 ++++++++++++++++++ 13 files changed, 179 insertions(+), 103 deletions(-) create mode 100644 repos/os/lib/mk/timeout-arm.mk create mode 100644 repos/os/src/lib/timeout/arm/timer_connection_time.cc create mode 100644 repos/os/src/lib/timeout/timer_connection_time.cc diff --git a/repos/base-foc/lib/mk/base-foc.inc b/repos/base-foc/lib/mk/base-foc.inc index 4f01754718..4b78fbf6bb 100644 --- a/repos/base-foc/lib/mk/base-foc.inc +++ b/repos/base-foc/lib/mk/base-foc.inc @@ -1,6 +1,6 @@ include $(BASE_DIR)/lib/mk/base.inc -LIBS += base-foc-common syscall-foc cxx timeout +LIBS += base-foc-common syscall-foc cxx SRC_CC += cap_map_remove.cc cap_alloc.cc SRC_CC += thread_start.cc diff --git a/repos/base-foc/lib/mk/spec/arm/base-foc.mk b/repos/base-foc/lib/mk/spec/arm/base-foc.mk index 77ff4ac868..542fb51b1f 100644 --- a/repos/base-foc/lib/mk/spec/arm/base-foc.mk +++ b/repos/base-foc/lib/mk/spec/arm/base-foc.mk @@ -1,4 +1,6 @@ # override default stack-area location INC_DIR += $(REP_DIR)/src/include/spec/arm +LIBS += timeout-arm + include $(REP_DIR)/lib/mk/base-foc.inc diff --git a/repos/base-foc/lib/mk/spec/x86/base-foc.mk b/repos/base-foc/lib/mk/spec/x86/base-foc.mk index ff31b15f8e..820c2c2707 100644 --- a/repos/base-foc/lib/mk/spec/x86/base-foc.mk +++ b/repos/base-foc/lib/mk/spec/x86/base-foc.mk @@ -1 +1,3 @@ +LIBS += timeout + include $(REP_DIR)/lib/mk/base-foc.inc diff --git a/repos/base-hw/lib/mk/timeout-hw.mk b/repos/base-hw/lib/mk/timeout-hw.mk index 235f50ec76..e8a5a7dc63 100644 --- a/repos/base-hw/lib/mk/timeout-hw.mk +++ b/repos/base-hw/lib/mk/timeout-hw.mk @@ -1,5 +1,6 @@ SRC_CC += timeout.cc SRC_CC += timer_connection.cc +SRC_CC += timer_connection_time.cc SRC_CC += hw/timer_connection_timestamp.cc SRC_CC += duration.cc diff --git a/repos/base-linux/lib/mk/base-linux.mk b/repos/base-linux/lib/mk/base-linux.mk index 1ce498bd18..60e26542e5 100644 --- a/repos/base-linux/lib/mk/base-linux.mk +++ b/repos/base-linux/lib/mk/base-linux.mk @@ -6,7 +6,7 @@ include $(REP_DIR)/lib/mk/base-linux.inc -LIBS += startup-linux base-linux-common cxx timeout +LIBS += startup-linux base-linux-common cxx SRC_CC += thread.cc thread_myself.cc thread_linux.cc SRC_CC += capability_space.cc capability_raw.cc SRC_CC += attach_stack_area.cc diff --git a/repos/base-linux/lib/mk/spec/arm/base-linux.mk b/repos/base-linux/lib/mk/spec/arm/base-linux.mk index c8020257b7..80643724dc 100644 --- a/repos/base-linux/lib/mk/spec/arm/base-linux.mk +++ b/repos/base-linux/lib/mk/spec/arm/base-linux.mk @@ -6,4 +6,6 @@ SRC_CC += cpu/arm/cache.cc +LIBS += timeout-arm + include $(REP_DIR)/lib/mk/base.mk diff --git a/repos/base-linux/lib/mk/spec/x86/base-linux.mk b/repos/base-linux/lib/mk/spec/x86/base-linux.mk index a3ba74e823..1feab5a909 100644 --- a/repos/base-linux/lib/mk/spec/x86/base-linux.mk +++ b/repos/base-linux/lib/mk/spec/x86/base-linux.mk @@ -6,4 +6,6 @@ SRC_CC += cache.cc +LIBS += timeout + include $(REP_DIR)/lib/mk/base-linux.mk diff --git a/repos/os/lib/mk/timeout-arm.mk b/repos/os/lib/mk/timeout-arm.mk new file mode 100644 index 0000000000..2ce3b6a28e --- /dev/null +++ b/repos/os/lib/mk/timeout-arm.mk @@ -0,0 +1,10 @@ +SRC_CC += timeout.cc +SRC_CC += timer_connection.cc +SRC_CC += arm/timer_connection_time.cc +SRC_CC += duration.cc + +LIBS += alarm + +INC_DIR += $(BASE_DIR)/src/include + +vpath % $(BASE_DIR)/../os/src/lib/timeout diff --git a/repos/os/lib/mk/timeout.mk b/repos/os/lib/mk/timeout.mk index eaddf27776..d2649af4bb 100644 --- a/repos/os/lib/mk/timeout.mk +++ b/repos/os/lib/mk/timeout.mk @@ -1,5 +1,6 @@ SRC_CC += timeout.cc SRC_CC += timer_connection.cc +SRC_CC += timer_connection_time.cc SRC_CC += timer_connection_timestamp.cc SRC_CC += duration.cc diff --git a/repos/os/src/lib/timeout/arm/timer_connection_time.cc b/repos/os/src/lib/timeout/arm/timer_connection_time.cc new file mode 100644 index 0000000000..e5c07f0cef --- /dev/null +++ b/repos/os/src/lib/timeout/arm/timer_connection_time.cc @@ -0,0 +1,32 @@ +/* + * \brief Connection to timer service and timeout scheduler + * \author Martin Stein + * \date 2016-11-04 + * + * On ARM, we do not have a component-local hardware time-source. The ARM + * performance counter has no reliable frequency as the ARM idle command + * halts the counter. Thus, we do not do local time interpolation. + */ + +/* + * Copyright (C) 2016-2017 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +/* Genode includes */ +#include +#include + +using namespace Genode; +using namespace Genode::Trace; + +Timestamp Timer::Connection::_timestamp() { return 0ULL; } + +void Timer::Connection::_update_real_time() { } + +Duration Timer::Connection::curr_time() +{ + return Duration(Milliseconds(elapsed_ms())); +} diff --git a/repos/os/src/lib/timeout/hw/timer_connection_timestamp.cc b/repos/os/src/lib/timeout/hw/timer_connection_timestamp.cc index dc2f04b04f..46bce911f0 100644 --- a/repos/os/src/lib/timeout/hw/timer_connection_timestamp.cc +++ b/repos/os/src/lib/timeout/hw/timer_connection_timestamp.cc @@ -2,6 +2,11 @@ * \brief Timestamp implementation for the Genode Timer * \author Martin Stein * \date 2016-11-04 + * + * On ARM, we do not have a component-local hardware time-source. The ARM + * performance counter has no reliable frequency as the ARM idle command + * halts the counter. However, on the HW kernel, we use a syscall that reads + * out the kernel time instead. */ /* diff --git a/repos/os/src/lib/timeout/timer_connection.cc b/repos/os/src/lib/timeout/timer_connection.cc index 3a3f33a964..c166826069 100644 --- a/repos/os/src/lib/timeout/timer_connection.cc +++ b/repos/os/src/lib/timeout/timer_connection.cc @@ -69,62 +69,6 @@ unsigned long Timer::Connection::_ts_to_us_ratio(Timestamp ts, } -void Timer::Connection::_update_real_time() -{ - Lock_guard lock_guard(_real_time_lock); - - Timestamp ts = 0UL; - unsigned long ms = 0UL; - unsigned long us_diff = ~0UL; - - for (unsigned remote_time_trials = 0; - remote_time_trials < MAX_REMOTE_TIME_TRIALS; - remote_time_trials++) - { - /* determine time and timestamp difference since the last call */ - Timestamp volatile new_ts = _timestamp(); - unsigned long volatile new_ms = elapsed_ms(); - - if (_interpolation_quality < MAX_INTERPOLATION_QUALITY) { - ms = new_ms; - ts = new_ts; - break; - } - - Timestamp const ts_diff = _timestamp() - new_ts; - unsigned long const new_us_diff = _ts_to_us_ratio(ts_diff, - _us_to_ts_factor); - - /* remember results only if the latency was better than last time */ - if (new_us_diff < us_diff) { - ms = new_ms; - ts = new_ts; - - if (us_diff < MAX_REMOTE_TIME_LATENCY_US) { - break; - } - } - } - - unsigned long const ms_diff = ms - _ms; - Timestamp const ts_diff = ts - _ts; - - /* update real time and values for next difference calculation */ - _ms = ms; - _ts = ts; - _real_time += Milliseconds(ms_diff); - - unsigned long const new_factor = _ts_to_us_ratio(ts_diff, ms_diff * 1000UL); - unsigned long const old_factor = _us_to_ts_factor; - - /* update interpolation-quality value */ - if (old_factor > new_factor) { _update_interpolation_quality(new_factor, old_factor); } - else { _update_interpolation_quality(old_factor, new_factor); } - - _us_to_ts_factor = new_factor; -} - - Duration Timer::Connection::_update_interpolated_time(Duration &interpolated_time) { /* @@ -167,51 +111,6 @@ void Timer::Connection::schedule_timeout(Microseconds duration, } -Duration Timer::Connection::curr_time() -{ - _enable_modern_mode(); - - Reconstructible > lock_guard(_real_time_lock); - Duration interpolated_time(_real_time); - - /* - * Interpolate with timestamps only if the factor value - * remained stable for some time. If we would interpolate with - * a yet unstable factor, there's an increased risk that the - * interpolated time falsely reaches an enourmous level. Then - * the value would stand still for quite some time because we - * can't let it jump back to a more realistic level. This - * would also eliminate updates of the real time as the - * timeout scheduler that manages our update timeout also - * uses this function. - */ - if (_interpolation_quality == MAX_INTERPOLATION_QUALITY) { - - /* locally buffer real-time related members */ - unsigned long const ts = _ts; - unsigned long const us_to_ts_factor = _us_to_ts_factor; - - lock_guard.destruct(); - - /* get time difference since the last real time update */ - Timestamp const ts_diff = _timestamp() - ts; - unsigned long const us_diff = _ts_to_us_ratio(ts_diff, us_to_ts_factor); - - interpolated_time += Microseconds(us_diff); - - } else { - - /* - * Use remote timer instead of timestamps - */ - interpolated_time += Milliseconds(elapsed_ms() - _ms); - - lock_guard.destruct(); - } - return _update_interpolated_time(interpolated_time); -} - - void Timer::Connection::_enable_modern_mode() { if (_mode == MODERN) { diff --git a/repos/os/src/lib/timeout/timer_connection_time.cc b/repos/os/src/lib/timeout/timer_connection_time.cc new file mode 100644 index 0000000000..6aeab59b57 --- /dev/null +++ b/repos/os/src/lib/timeout/timer_connection_time.cc @@ -0,0 +1,120 @@ +/* + * \brief Connection to timer service and timeout scheduler + * \author Martin Stein + * \date 2016-11-04 + */ + +/* + * Copyright (C) 2016-2017 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +/* Genode includes */ +#include +#include + +using namespace Genode; +using namespace Genode::Trace; + + +void Timer::Connection::_update_real_time() +{ + Lock_guard lock_guard(_real_time_lock); + + Timestamp ts = 0UL; + unsigned long ms = 0UL; + unsigned long us_diff = ~0UL; + + for (unsigned remote_time_trials = 0; + remote_time_trials < MAX_REMOTE_TIME_TRIALS; + remote_time_trials++) + { + /* determine time and timestamp difference since the last call */ + Timestamp volatile new_ts = _timestamp(); + unsigned long volatile new_ms = elapsed_ms(); + + if (_interpolation_quality < MAX_INTERPOLATION_QUALITY) { + ms = new_ms; + ts = new_ts; + break; + } + + Timestamp const ts_diff = _timestamp() - new_ts; + unsigned long const new_us_diff = _ts_to_us_ratio(ts_diff, + _us_to_ts_factor); + + /* remember results only if the latency was better than last time */ + if (new_us_diff < us_diff) { + ms = new_ms; + ts = new_ts; + + if (us_diff < MAX_REMOTE_TIME_LATENCY_US) { + break; + } + } + } + + unsigned long const ms_diff = ms - _ms; + Timestamp const ts_diff = ts - _ts; + + /* update real time and values for next difference calculation */ + _ms = ms; + _ts = ts; + _real_time += Milliseconds(ms_diff); + + unsigned long const new_factor = _ts_to_us_ratio(ts_diff, ms_diff * 1000UL); + unsigned long const old_factor = _us_to_ts_factor; + + /* update interpolation-quality value */ + if (old_factor > new_factor) { _update_interpolation_quality(new_factor, old_factor); } + else { _update_interpolation_quality(old_factor, new_factor); } + + _us_to_ts_factor = new_factor; +} + + +Duration Timer::Connection::curr_time() +{ + _enable_modern_mode(); + + Reconstructible > lock_guard(_real_time_lock); + Duration interpolated_time(_real_time); + + /* + * Interpolate with timestamps only if the factor value + * remained stable for some time. If we would interpolate with + * a yet unstable factor, there's an increased risk that the + * interpolated time falsely reaches an enourmous level. Then + * the value would stand still for quite some time because we + * can't let it jump back to a more realistic level. This + * would also eliminate updates of the real time as the + * timeout scheduler that manages our update timeout also + * uses this function. + */ + if (_interpolation_quality == MAX_INTERPOLATION_QUALITY) + { + /* locally buffer real-time related members */ + unsigned long const ts = _ts; + unsigned long const us_to_ts_factor = _us_to_ts_factor; + + lock_guard.destruct(); + + /* get time difference since the last real time update */ + Timestamp const ts_diff = _timestamp() - ts; + unsigned long const us_diff = _ts_to_us_ratio(ts_diff, us_to_ts_factor); + + interpolated_time += Microseconds(us_diff); + + } else { + + /* + * Use remote timer instead of timestamps + */ + interpolated_time += Milliseconds(elapsed_ms() - _ms); + + lock_guard.destruct(); + } + return _update_interpolated_time(interpolated_time); +}