Skip to content

Commit 1ef3cb1

Browse files
committed
sqlite: Improve boot time estimation
Our old boot time estimation algorithm has served us well, but started to show issues when faced with faster devices than data_exporter has normally been run on. The problem was our use of multiple clock sources, and more specifically, reading uptime from file. What could happen was that uptime would increase, but the clock used as source for gettimeofday() would not. On devices with a (working) RTC or on restarts of data exporter, this timer-behavior caused our estimate for the real boot time to be less than the original estimate. When we detected a clock that has moved backwards, we stop exporting metadata. This commit improves how we make the estimations by reducing the number of clock sources. Uptime is only read when we estimate the original boot time, and then we use CLOCK_MONOTONIC_RAW to estimate the amount of time that has passed when we estimate the real boot time. Instead of using gettimeofday() to read the current wall time, we use clock_gettime(). Using clock_gettime() ensures that the real time as well as elapsed time all come from the same source. We also read the wall time after we read MONOTONIC_RAW, to avoid the elapsed time being "larger" than the real time. Worst-case, what can happen with the new approach, is that the timers have not changed and the diff is 0.
1 parent a49916d commit 1ef3cb1

File tree

2 files changed

+45
-17
lines changed

2 files changed

+45
-17
lines changed

metadata_writer_sqlite.c

Lines changed: 43 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,12 @@
3131
#include <libmnl/libmnl.h>
3232
#include <string.h>
3333
#include <sys/time.h>
34+
#include <time.h>
3435
#include <stdlib.h>
3536
#include <errno.h>
3637
#include <sqlite3.h>
38+
#include <linux/sysinfo.h>
39+
#include <sys/syscall.h>
3740

3841
#include "metadata_writer_sqlite.h"
3942
#include "metadata_writer_inventory_conn.h"
@@ -295,27 +298,51 @@ static sqlite3* md_sqlite_configure_db(struct md_writer_sqlite *mws, const char
295298
return db_handle;
296299
}
297300

298-
static int md_sqlite_read_boot_time(struct md_writer_sqlite *mws, uint64_t *boot_time)
301+
static int md_sqlite_read_orig_boot_time(struct md_writer_sqlite *mws)
299302
{
300-
struct timeval tv;
301-
uint64_t uptime;
303+
struct timespec tp_raw, tp_real;
304+
struct sysinfo info = {0};
302305

303-
//read uptime
304-
if (system_helpers_read_uint64_from_file("/proc/uptime", &uptime)) {
305-
return RETVAL_FAILURE;
306-
}
306+
syscall(SYS_sysinfo, &info);
307307

308-
gettimeofday(&tv, NULL);
308+
clock_gettime(CLOCK_MONOTONIC_RAW, &tp_raw);
309+
clock_gettime(CLOCK_REALTIME, &tp_real);
309310

310-
*boot_time = tv.tv_sec - uptime;
311-
312-
if (*boot_time < mws->orig_boot_time) {
313-
return RETVAL_FAILURE;
311+
//This can only happen on boot on devices where time is reset to epoch.
312+
//uptime and clock_gettime() come from different clock sources, uptime might
313+
//for example have been updated before tp_real
314+
if (info.uptime > tp_real.tv_sec) {
315+
mws->orig_boot_time = 0;
316+
} else {
317+
mws->orig_boot_time = tp_real.tv_sec - info.uptime;
314318
}
315319

320+
mws->orig_uptime = info.uptime;
321+
mws->orig_raw_time = tp_raw.tv_sec;
322+
316323
return RETVAL_SUCCESS;
317324
}
318325

326+
static void md_sqlite_get_real_boot_time(struct md_writer_sqlite *mws, uint64_t *real_boot_time)
327+
{
328+
struct timespec tp_raw, tp_real;
329+
330+
clock_gettime(CLOCK_MONOTONIC_RAW, &tp_raw);
331+
clock_gettime(CLOCK_REALTIME, &tp_real);
332+
333+
//The calculation here is as follows:
334+
//* The goal is to find the correct boot time, now that we have a valid NTP fix
335+
//* We get the current (walltime).
336+
//* From this value we want to subtract the total uptime.
337+
//* To reduce the number of clock sources, we use use MONOTONIG_RAW to calculate
338+
//the amount of time that has passed since data_exporter was started.
339+
//* We add the diff between (cur_raw - orig_raw) to the uptime we read when
340+
//data_exporter was started. The sum is time elapsed since boot.
341+
//* In order to get the "correct" boot time, we subtract the calculation above
342+
//from the current walltime.
343+
*real_boot_time = tp_real.tv_sec - (mws->orig_uptime + (tp_raw.tv_sec - mws->orig_raw_time));
344+
}
345+
319346
static int md_sqlite_configure(struct md_writer_sqlite *mws,
320347
const char *db_filename, uint32_t node_id, uint32_t db_interval,
321348
uint32_t db_events, const char *meta_prefix, const char *gps_prefix,
@@ -466,7 +493,7 @@ static int md_sqlite_configure(struct md_writer_sqlite *mws,
466493
system_helpers_read_uint64_from_file(mws->last_conn_tstamp_path,
467494
&(mws->dump_tstamp));
468495

469-
return md_sqlite_read_boot_time(mws, &(mws->orig_boot_time));
496+
return md_sqlite_read_orig_boot_time(mws);
470497
}
471498

472499
void md_sqlite_usage()
@@ -575,13 +602,12 @@ static uint8_t md_sqlite_check_valid_tstamp(struct md_writer_sqlite *mws)
575602

576603
gettimeofday(&tv, NULL);
577604

578-
if (mws->ntp_fix_file[0] && access(mws->ntp_fix_file, F_OK))
579-
return RETVAL_FAILURE;
580-
581-
if (md_sqlite_read_boot_time(mws, &real_boot_time)) {
605+
if (mws->ntp_fix_file[0] && access(mws->ntp_fix_file, F_OK)) {
582606
return RETVAL_FAILURE;
583607
}
584608

609+
md_sqlite_get_real_boot_time(mws, &real_boot_time);
610+
585611
META_PRINT_SYSLOG(mws->parent, LOG_INFO, "Real boot %" PRIu64 " orig boot %" PRIu64 "\n", real_boot_time, mws->orig_boot_time);
586612

587613
if (md_sqlite_update_timestamp_db(mws, UPDATE_EVENT_TSTAMP,

metadata_writer_sqlite.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -262,6 +262,8 @@ struct md_writer_sqlite {
262262
uint64_t last_msg_tstamp;
263263
uint64_t last_gps_insert;
264264
uint64_t orig_boot_time;
265+
uint64_t orig_uptime;
266+
uint64_t orig_raw_time;
265267

266268
//TODO: Consider moving this to the generic writer struct if need be
267269
//These values keep track of the unique session id (and multiplier), which

0 commit comments

Comments
 (0)