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
This commit is contained in:
Martin Stein 2017-05-31 15:24:56 +02:00 committed by Christian Helmuth
parent 0d79611c03
commit 685f509a43
13 changed files with 179 additions and 103 deletions

View File

@ -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

View File

@ -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

View File

@ -1 +1,3 @@
LIBS += timeout
include $(REP_DIR)/lib/mk/base-foc.inc

View File

@ -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

View File

@ -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

View File

@ -6,4 +6,6 @@
SRC_CC += cpu/arm/cache.cc
LIBS += timeout-arm
include $(REP_DIR)/lib/mk/base.mk

View File

@ -6,4 +6,6 @@
SRC_CC += cache.cc
LIBS += timeout
include $(REP_DIR)/lib/mk/base-linux.mk

View File

@ -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

View File

@ -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

View File

@ -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 <timer_session/connection.h>
#include <base/internal/globals.h>
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()));
}

View File

@ -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.
*/
/*

View File

@ -69,62 +69,6 @@ unsigned long Timer::Connection::_ts_to_us_ratio(Timestamp ts,
}
void Timer::Connection::_update_real_time()
{
Lock_guard<Lock> 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<Lock> > 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) {

View File

@ -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 <timer_session/connection.h>
#include <base/internal/globals.h>
using namespace Genode;
using namespace Genode::Trace;
void Timer::Connection::_update_real_time()
{
Lock_guard<Lock> 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<Lock> > 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);
}