summaryrefslogtreecommitdiff
path: root/libgpsd_core.c
diff options
context:
space:
mode:
authorEric S. Raymond <esr@thyrsus.com>2015-01-22 16:05:52 -0500
committerEric S. Raymond <esr@thyrsus.com>2015-01-22 16:05:52 -0500
commita2cabfcd89d8ac45a60fb35847258567c3450560 (patch)
tree49919ca7302ea899df93e5d9958590bdccb0370a /libgpsd_core.c
parentfbc716f9e36491c80b426bff36295c1cb0c2dc31 (diff)
downloadgpsd-a2cabfcd89d8ac45a60fb35847258567c3450560.tar.gz
Introduce an adaptive delay into the main loop to prevent select buzzing.
When select(2) returns too fast with only small amounts of data, the main loop will buzz and eat power - a significant issue on, e.g. battery-powered RasPi devices, where it was first spotted. This code watches read volume and delays when it sees lots of small bursts. All regressiion tests pass. But note: the adaptive-delay logic has to suppress delays to arrange this, otherwise we get an all too familiar class of spurious test failure.
Diffstat (limited to 'libgpsd_core.c')
-rw-r--r--libgpsd_core.c22
1 files changed, 22 insertions, 0 deletions
diff --git a/libgpsd_core.c b/libgpsd_core.c
index 933bb4be..ac558bef 100644
--- a/libgpsd_core.c
+++ b/libgpsd_core.c
@@ -279,6 +279,9 @@ void gps_context_init(struct gps_context_t *context,
.shmexport = NULL,
#endif /* SHM_EXPORT_ENABLE */
.serial_write = gpsd_serial_write,
+ .inbytesavg = 0.0,
+ .inbyteswpos = (char) 0,
+ .selectbug = false
};
/*@ +initallelements +nullassign +nullderef +fullinitblock @*/
/* *INDENT-ON* */
@@ -1069,6 +1072,7 @@ gps_mask_t gpsd_poll(struct gps_device_t *session)
{
ssize_t newlen;
bool driver_change = false;
+ float alpha;
gps_clear_fix(&session->newdata);
@@ -1154,6 +1158,24 @@ gps_mask_t gpsd_poll(struct gps_device_t *session)
newlen = generic_get(session);
}
+ /* Calculate window average of read count */
+ session->context->inbyteswpos = session->context->inbyteswpos % WINDOW_AVG_SIZE;
+ alpha = (session->context->inbyteswpos== (unsigned char) 0) ? 0.0f:1.0f;
+ if (newlen > 0)
+ session->context->inbytesavg = alpha*session->context->inbytesavg + (float) newlen;
+ else
+ /* error reading -- counts as 0 */
+ session->context->inbytesavg = alpha*session->context->inbytesavg;
+
+ if (session->context->inbyteswpos== (unsigned char) (WINDOW_AVG_SIZE-1)) {
+ session->context->inbytesavg/=WINDOW_AVG_SIZE;
+ }
+ session->context->inbyteswpos += (unsigned char) 1;
+
+ gpsd_report(&session->context->errout, LOG_RAW,
+ "window average of received byte count is %f\n",
+ session->context->inbytesavg);
+
/* update the scoreboard structure from the GPS */
gpsd_report(&session->context->errout, LOG_RAW + 2,
"%s sent %zd new characters\n",