summaryrefslogtreecommitdiffstats
path: root/daemon/defer.h
diff options
context:
space:
mode:
Diffstat (limited to 'daemon/defer.h')
-rw-r--r--daemon/defer.h118
1 files changed, 80 insertions, 38 deletions
diff --git a/daemon/defer.h b/daemon/defer.h
index db1b083b..18adf91b 100644
--- a/daemon/defer.h
+++ b/daemon/defer.h
@@ -8,9 +8,8 @@
#include "lib/kru.h"
/// Initialize defer, incl. shared memory with KRU, excl. idle.
-/// To be called from Lua; defer is disabled by default otherwise.
KR_EXPORT
-int defer_init(const char *mmap_file, int cpus);
+int defer_init(const char *mmap_file, uint32_t log_period, int cpus);
/// Initialize idle.
int defer_init_idle(uv_loop_t *loop);
@@ -19,37 +18,33 @@ int defer_init_idle(uv_loop_t *loop);
void defer_deinit(void);
/// Increment KRU counters by the given time.
-void defer_account(uint64_t nsec, union kr_sockaddr *addr, bool stream);
+void defer_charge(uint64_t nsec, union kr_sockaddr *addr, bool stream);
typedef struct {
- int8_t is_accounting; /// whether currently accounting the time to someone; should be 0/1
- union kr_sockaddr addr; /// request source (to which we account) or AF_UNSPEC if unknown yet
+ bool is_accounting; /// whether currently accounting the time to someone
bool stream;
+ union kr_sockaddr addr; /// request source (to which we account) or AF_UNSPEC if unknown yet
uint64_t stamp; /// monotonic nanoseconds, probably won't wrap
} defer_sample_state_t;
extern defer_sample_state_t defer_sample_state;
extern struct defer *defer; /// skip sampling/deferring if NULL
-
+extern bool defer_initialized; /// defer_init was called, possibly keeping defer disabled
+extern uint64_t defer_uvtime_stamp; /// stamp of the last uv time update
// TODO: reconsider `static inline` cases below
#include <time.h>
-static inline uint64_t get_stamp(void)
+static inline uint64_t defer_get_stamp(void)
{
struct timespec now_ts = {0};
clock_gettime(CLOCK_THREAD_CPUTIME_ID, &now_ts);
- return now_ts.tv_nsec + 1000*1000*1000 * (uint64_t)now_ts.tv_sec;
-}
-
-/// Start accounting work, if not doing it already.
-static inline void defer_sample_start(void)
-{
- if (!defer) return;
- kr_assert(!defer_sample_state.is_accounting);
- ++defer_sample_state.is_accounting;
- defer_sample_state.stamp = get_stamp();
- defer_sample_state.addr.ip.sa_family = AF_UNSPEC;
+ uint64_t stamp = now_ts.tv_nsec + 1000*1000*1000 * (uint64_t)now_ts.tv_sec;
+ if (defer_uvtime_stamp + 1000*1000 < stamp) {
+ defer_uvtime_stamp = stamp;
+ uv_update_time(uv_default_loop());
+ }
+ return stamp;
}
/// Annotate the work currently being accounted by an IP address.
@@ -60,8 +55,14 @@ static inline void defer_sample_addr(const union kr_sockaddr *addr, bool stream)
if (defer_sample_state.addr.ip.sa_family != AF_UNSPEC) {
// TODO: this costs performance, so only in some debug mode?
- kr_assert(kr_sockaddr_cmp(&addr->ip, &defer_sample_state.addr.ip) == kr_ok());
- return;
+ if (kr_sockaddr_cmp(&addr->ip, &defer_sample_state.addr.ip) != kr_ok()) {
+ char defer_addr[KR_STRADDR_MAXLEN + 1] = { 0 };
+ strncpy(defer_addr, kr_straddr(&defer_sample_state.addr.ip), sizeof(defer_addr) - 1);
+ kr_log_warning(DEFER, "Sampling address mismatch: %s != %s\n",
+ kr_straddr(&addr->ip),
+ defer_addr);
+ return;
+ }
}
switch (addr->ip.sa_family) {
@@ -78,38 +79,79 @@ static inline void defer_sample_addr(const union kr_sockaddr *addr, bool stream)
defer_sample_state.stream = stream;
}
-/// Stop accounting work - and change the source if applicable.
-static inline void defer_sample_stop(void)
+/// Internal; start accounting work at specified timestamp.
+static inline void defer_sample_start_stamp(uint64_t stamp)
{
if (!defer) return;
+ kr_assert(!defer_sample_state.is_accounting);
+ defer_sample_state.is_accounting = true;
+ defer_sample_state.stamp = stamp;
+ defer_sample_state.addr.ip.sa_family = AF_UNSPEC;
+}
- if (kr_fails_assert(defer_sample_state.is_accounting > 0)) return; // weird
- if (--defer_sample_state.is_accounting) return;
- if (defer_sample_state.addr.ip.sa_family == AF_UNSPEC) return;
+/// Internal; stop accounting work at specified timestamp and charge the source if applicable.
+static inline void defer_sample_stop_stamp(uint64_t stamp)
+{
+ if (!defer) return;
+ kr_assert(defer_sample_state.is_accounting);
+ defer_sample_state.is_accounting = false;
- const uint64_t elapsed = get_stamp() - defer_sample_state.stamp;
+ if (defer_sample_state.addr.ip.sa_family == AF_UNSPEC) return;
- // we accounted something
+ const uint64_t elapsed = stamp - defer_sample_state.stamp;
+ if (elapsed == 0) return;
// TODO: some queries of internal origin have suspicioiusly high numbers.
// We won't be really accounting those, but it might suggest some other issue.
- defer_account(elapsed, &defer_sample_state.addr, defer_sample_state.stream);
+ defer_charge(elapsed, &defer_sample_state.addr, defer_sample_state.stream);
}
-/// Stop accounting if active, then start again. Uses just one stamp.
-static inline void defer_sample_restart(void)
+static inline bool defer_sample_is_accounting(void)
{
- if (!defer) return;
+ return defer_sample_state.is_accounting;
+}
- uint64_t stamp = get_stamp();
+/// Start accounting work; optionally save state of current accounting.
+/// Current state can be saved only after having an address assigned.
+static inline void defer_sample_start(defer_sample_state_t *prev_state_out) {
+ if (!defer) return;
+ uint64_t stamp = defer_get_stamp();
- if (defer_sample_state.is_accounting > 0) {
- const uint64_t elapsed = stamp - defer_sample_state.stamp;
- defer_account(elapsed, &defer_sample_state.addr, defer_sample_state.stream);
+ // suspend
+ if (prev_state_out) {
+ *prev_state_out = defer_sample_state; // TODO stamp is not needed
+ if (defer_sample_state.is_accounting)
+ defer_sample_stop_stamp(stamp);
}
- defer_sample_state.stamp = stamp;
- defer_sample_state.addr.ip.sa_family = AF_UNSPEC;
- defer_sample_state.is_accounting = 1;
+ // start
+ defer_sample_start_stamp(stamp);
+}
+
+/// Stop accounting and start it again.
+static inline void defer_sample_restart(void) {
+ if (!defer) return;
+ uint64_t stamp = defer_get_stamp();
+
+ // stop
+ defer_sample_stop_stamp(stamp);
+
+ // start
+ defer_sample_start_stamp(stamp);
+}
+
+/// Stop accounting and charge the source if applicable; optionally resume previous accounting.
+static inline void defer_sample_stop(defer_sample_state_t *prev_state, bool reuse_last_stamp) {
+ if (!defer) return;
+ uint64_t stamp = reuse_last_stamp ? defer_sample_state.stamp : defer_get_stamp();
+
+ // stop
+ defer_sample_stop_stamp(stamp);
+
+ // resume
+ if (prev_state) {
+ defer_sample_state = *prev_state;
+ defer_sample_state.stamp = stamp;
+ }
}