diff options
author | Costa Tsaousis <costa@tsaousis.gr> | 2018-10-15 23:16:42 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-10-15 23:16:42 +0300 |
commit | 8fbf817ef83b3524b15f908251909d9d6feb5532 (patch) | |
tree | 4c2d417b7392c907bbdbe355b8db361bd3741a02 /libnetdata/clocks | |
parent | 1ad4f1bcfc691120102b57dbd426de0870abd76f (diff) |
modularized all source code (#4391)
* modularized all external plugins
* added README.md in plugins
* fixed title
* fixed typo
* relative link to external plugins
* external plugins configuration README
* added plugins link
* remove plugins link
* plugin names are links
* added links to external plugins
* removed unecessary spacing
* list to table
* added language
* fixed typo
* list to table on internal plugins
* added more documentation to internal plugins
* moved python, node, and bash code and configs into the external plugins
* added statsd README
* fix bug with corrupting config.h every 2nd compilation
* moved all config files together with their code
* more documentation
* diskspace info
* fixed broken links in apps.plugin
* added backends docs
* updated plugins readme
* move nc-backend.sh to backends
* created daemon directory
* moved all code outside src/
* fixed readme identation
* renamed plugins.d.plugin to plugins.d
* updated readme
* removed linux- from linux plugins
* updated readme
* updated readme
* updated readme
* updated readme
* updated readme
* updated readme
* fixed README.md links
* fixed netdata tree links
* updated codacy, codeclimate and lgtm excluded paths
* update CMakeLists.txt
* updated automake options at top directory
* libnetdata slit into directories
* updated READMEs
* updated READMEs
* updated ARL docs
* updated ARL docs
* moved /plugins to /collectors
* moved all external plugins outside plugins.d
* updated codacy, codeclimate, lgtm
* updated README
* updated url
* updated readme
* updated readme
* updated readme
* updated readme
* moved api and web into webserver
* web/api web/gui web/server
* modularized webserver
* removed web/gui/version.txt
Diffstat (limited to 'libnetdata/clocks')
-rw-r--r-- | libnetdata/clocks/Makefile.am | 9 | ||||
-rw-r--r-- | libnetdata/clocks/README.md | 0 | ||||
-rw-r--r-- | libnetdata/clocks/clocks.c | 158 | ||||
-rw-r--r-- | libnetdata/clocks/clocks.h | 131 |
4 files changed, 298 insertions, 0 deletions
diff --git a/libnetdata/clocks/Makefile.am b/libnetdata/clocks/Makefile.am new file mode 100644 index 0000000000..1cb69ed99a --- /dev/null +++ b/libnetdata/clocks/Makefile.am @@ -0,0 +1,9 @@ +# SPDX-License-Identifier: GPL-3.0-or-later + +AUTOMAKE_OPTIONS = subdir-objects +MAINTAINERCLEANFILES = $(srcdir)/Makefile.in + + +dist_noinst_DATA = \ + README.md \ + $(NULL) diff --git a/libnetdata/clocks/README.md b/libnetdata/clocks/README.md new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/libnetdata/clocks/README.md diff --git a/libnetdata/clocks/clocks.c b/libnetdata/clocks/clocks.c new file mode 100644 index 0000000000..e644aeeb09 --- /dev/null +++ b/libnetdata/clocks/clocks.c @@ -0,0 +1,158 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "../libnetdata.h" + +#ifndef HAVE_CLOCK_GETTIME +inline int clock_gettime(clockid_t clk_id, struct timespec *ts) { + struct timeval tv; + if(unlikely(gettimeofday(&tv, NULL) == -1)) { + error("gettimeofday() failed."); + return -1; + } + ts->tv_sec = tv.tv_sec; + ts->tv_nsec = (tv.tv_usec % USEC_PER_SEC) * NSEC_PER_USEC; + return 0; +} +#endif + +static inline time_t now_sec(clockid_t clk_id) { + struct timespec ts; + if(unlikely(clock_gettime(clk_id, &ts) == -1)) { + error("clock_gettime(%d, ×pec) failed.", clk_id); + return 0; + } + return ts.tv_sec; +} + +static inline usec_t now_usec(clockid_t clk_id) { + struct timespec ts; + if(unlikely(clock_gettime(clk_id, &ts) == -1)) { + error("clock_gettime(%d, ×pec) failed.", clk_id); + return 0; + } + return (usec_t)ts.tv_sec * USEC_PER_SEC + (ts.tv_nsec % NSEC_PER_SEC) / NSEC_PER_USEC; +} + +static inline int now_timeval(clockid_t clk_id, struct timeval *tv) { + struct timespec ts; + + if(unlikely(clock_gettime(clk_id, &ts) == -1)) { + error("clock_gettime(%d, ×pec) failed.", clk_id); + tv->tv_sec = 0; + tv->tv_usec = 0; + return -1; + } + + tv->tv_sec = ts.tv_sec; + tv->tv_usec = (suseconds_t)((ts.tv_nsec % NSEC_PER_SEC) / NSEC_PER_USEC); + return 0; +} + +inline time_t now_realtime_sec(void) { + return now_sec(CLOCK_REALTIME); +} + +inline usec_t now_realtime_usec(void) { + return now_usec(CLOCK_REALTIME); +} + +inline int now_realtime_timeval(struct timeval *tv) { + return now_timeval(CLOCK_REALTIME, tv); +} + +inline time_t now_monotonic_sec(void) { + return now_sec(CLOCK_MONOTONIC); +} + +inline usec_t now_monotonic_usec(void) { + return now_usec(CLOCK_MONOTONIC); +} + +inline int now_monotonic_timeval(struct timeval *tv) { + return now_timeval(CLOCK_MONOTONIC, tv); +} + +inline time_t now_boottime_sec(void) { + return now_sec(CLOCK_BOOTTIME); +} + +inline usec_t now_boottime_usec(void) { + return now_usec(CLOCK_BOOTTIME); +} + +inline int now_boottime_timeval(struct timeval *tv) { + return now_timeval(CLOCK_BOOTTIME, tv); +} + +inline usec_t timeval_usec(struct timeval *tv) { + return (usec_t)tv->tv_sec * USEC_PER_SEC + (tv->tv_usec % USEC_PER_SEC); +} + +inline msec_t timeval_msec(struct timeval *tv) { + return (msec_t)tv->tv_sec * MSEC_PER_SEC + ((tv->tv_usec % USEC_PER_SEC) / MSEC_PER_SEC); +} + +inline susec_t dt_usec_signed(struct timeval *now, struct timeval *old) { + usec_t ts1 = timeval_usec(now); + usec_t ts2 = timeval_usec(old); + + if(likely(ts1 >= ts2)) return (susec_t)(ts1 - ts2); + return -((susec_t)(ts2 - ts1)); +} + +inline usec_t dt_usec(struct timeval *now, struct timeval *old) { + usec_t ts1 = timeval_usec(now); + usec_t ts2 = timeval_usec(old); + return (ts1 > ts2) ? (ts1 - ts2) : (ts2 - ts1); +} + +inline void heartbeat_init(heartbeat_t *hb) +{ + hb->monotonic = hb->realtime = 0ULL; +} + +// waits for the next heartbeat +// it waits using the monotonic clock +// it returns the dt using the realtime clock + +usec_t heartbeat_next(heartbeat_t *hb, usec_t tick) { + heartbeat_t now; + now.monotonic = now_monotonic_usec(); + now.realtime = now_realtime_usec(); + + usec_t next_monotonic = now.monotonic - (now.monotonic % tick) + tick; + + while(now.monotonic < next_monotonic) { + sleep_usec(next_monotonic - now.monotonic); + now.monotonic = now_monotonic_usec(); + now.realtime = now_realtime_usec(); + } + + if(likely(hb->realtime != 0ULL)) { + usec_t dt_monotonic = now.monotonic - hb->monotonic; + usec_t dt_realtime = now.realtime - hb->realtime; + + hb->monotonic = now.monotonic; + hb->realtime = now.realtime; + + if(unlikely(dt_monotonic >= tick + tick / 2)) { + errno = 0; + error("heartbeat missed %llu monotonic microseconds", dt_monotonic - tick); + } + + return dt_realtime; + } + else { + hb->monotonic = now.monotonic; + hb->realtime = now.realtime; + return 0ULL; + } +} + +// returned the elapsed time, since the last heartbeat +// using the monotonic clock + +inline usec_t heartbeat_monotonic_dt_to_now_usec(heartbeat_t *hb) { + if(!hb || !hb->monotonic) return 0ULL; + return now_monotonic_usec() - hb->monotonic; +} diff --git a/libnetdata/clocks/clocks.h b/libnetdata/clocks/clocks.h new file mode 100644 index 0000000000..c66dda4369 --- /dev/null +++ b/libnetdata/clocks/clocks.h @@ -0,0 +1,131 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +#ifndef NETDATA_CLOCKS_H +#define NETDATA_CLOCKS_H 1 + +#include "../libnetdata.h" + +#ifndef HAVE_STRUCT_TIMESPEC +struct timespec { + time_t tv_sec; /* seconds */ + long tv_nsec; /* nanoseconds */ +}; +#endif + +#ifndef HAVE_CLOCKID_T +typedef int clockid_t; +#endif + +typedef unsigned long long nsec_t; +typedef unsigned long long msec_t; +typedef unsigned long long usec_t; +typedef long long susec_t; + +typedef struct heartbeat { + usec_t monotonic; + usec_t realtime; +} heartbeat_t; + +/* Linux value is as good as any other */ +#ifndef CLOCK_REALTIME +#define CLOCK_REALTIME 0 +#endif + +#ifndef CLOCK_MONOTONIC +/* fallback to CLOCK_REALTIME if not available */ +#define CLOCK_MONOTONIC CLOCK_REALTIME +#endif + +#ifndef CLOCK_BOOTTIME + +#ifdef CLOCK_UPTIME +/* CLOCK_BOOTTIME falls back to CLOCK_UPTIME on FreeBSD */ +#define CLOCK_BOOTTIME CLOCK_UPTIME +#else // CLOCK_UPTIME +/* CLOCK_BOOTTIME falls back to CLOCK_MONOTONIC */ +#define CLOCK_BOOTTIME CLOCK_MONOTONIC +#endif // CLOCK_UPTIME + +#else // CLOCK_BOOTTIME + +#ifdef HAVE_CLOCK_GETTIME +#define CLOCK_BOOTTIME_IS_AVAILABLE 1 // required for /proc/uptime +#endif // HAVE_CLOCK_GETTIME + +#endif // CLOCK_BOOTTIME + +#define NSEC_PER_MSEC 1000000ULL + +#define NSEC_PER_SEC 1000000000ULL +#define NSEC_PER_USEC 1000ULL + +#define USEC_PER_SEC 1000000ULL +#define MSEC_PER_SEC 1000ULL + +#define USEC_PER_MS 1000ULL + +#ifndef HAVE_CLOCK_GETTIME +/* Fallback function for POSIX.1-2001 clock_gettime() function. + * + * We use a realtime clock from gettimeofday(), this will + * make systems without clock_gettime() support sensitive + * to time jumps or hibernation/suspend side effects. + */ +extern int clock_gettime(clockid_t clk_id, struct timespec *ts); +#endif + +/* + * Three clocks are available (cf. man 3 clock_gettime): + * + * REALTIME clock (i.e. wall-clock): + * This clock is affected by discontinuous jumps in the system time + * (e.g., if the system administrator manually changes the clock), and by the incremental adjustments performed by adjtime(3) and NTP. + * + * MONOTONIC clock + * Clock that cannot be set and represents monotonic time since some unspecified starting point. + * This clock is not affected by discontinuous jumps in the system time + * (e.g., if the system administrator manually changes the clock), but is affected by the incremental adjustments performed by adjtime(3) and NTP. + * If not available on the system, this clock falls back to REALTIME clock. + * + * BOOTTIME clock + * Identical to CLOCK_MONOTONIC, except it also includes any time that the system is suspended. + * This allows applications to get a suspend-aware monotonic clock without having to deal with the complications of CLOCK_REALTIME, + * which may have discontinuities if the time is changed using settimeofday(2). + * If not available on the system, this clock falls back to MONOTONIC clock. + * + * All now_*_timeval() functions fill the `struct timeval` with the time from the appropriate clock. + * Those functions return 0 on success, -1 else with errno set appropriately. + * + * All now_*_sec() functions return the time in seconds from the approriate clock, or 0 on error. + * All now_*_usec() functions return the time in microseconds from the approriate clock, or 0 on error. + */ +extern int now_realtime_timeval(struct timeval *tv); +extern time_t now_realtime_sec(void); +extern usec_t now_realtime_usec(void); + +extern int now_monotonic_timeval(struct timeval *tv); +extern time_t now_monotonic_sec(void); +extern usec_t now_monotonic_usec(void); + +extern int now_boottime_timeval(struct timeval *tv); +extern time_t now_boottime_sec(void); +extern usec_t now_boottime_usec(void); + + +extern usec_t timeval_usec(struct timeval *tv); +extern msec_t timeval_msec(struct timeval *tv); + +extern usec_t dt_usec(struct timeval *now, struct timeval *old); +extern susec_t dt_usec_signed(struct timeval *now, struct timeval *old); + +extern void heartbeat_init(heartbeat_t *hb); + +/* Sleeps until next multiple of tick using monotonic clock. + * Returns elapsed time in microseconds since previous heartbeat + */ +extern usec_t heartbeat_next(heartbeat_t *hb, usec_t tick); + +/* Returns elapsed time in microseconds since last heartbeat */ +extern usec_t heartbeat_monotonic_dt_to_now_usec(heartbeat_t *hb); + +#endif /* NETDATA_CLOCKS_H */ |