diff options
Diffstat (limited to 'daemon/defer.h')
-rw-r--r-- | daemon/defer.h | 118 |
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; + } } |