#include "ostream.h"
#include "str.h"
#include "strescape.h"
-#include "timing.h"
+#include "stats-dist.h"
#include "time-util.h"
#include "dict-client.h"
#include "dict-settings.h"
}
static void
-cmd_stats_update(struct dict_connection_cmd *cmd, struct timing *timing)
+cmd_stats_update(struct dict_connection_cmd *cmd, struct stats_dist *stats)
{
long long diff;
diff = timeval_diff_usecs(&ioloop_timeval, &cmd->start_timeval);
if (diff < 0)
diff = 0;
- timing_add_usecs(timing, diff);
+ stats_dist_add(stats, diff);
dict_proctitle_update_later();
}
static void
-dict_cmd_reply_handle_timings(struct dict_connection_cmd *cmd,
- string_t *str, struct timing *timing)
+dict_cmd_reply_handle_stats(struct dict_connection_cmd *cmd,
+ string_t *str, struct stats_dist *stats)
{
io_loop_time_refresh();
- cmd_stats_update(cmd, timing);
+ cmd_stats_update(cmd, stats);
if (cmd->conn->minor_version < DICT_CLIENT_PROTOCOL_TIMINGS_MIN_VERSION)
return;
str_append_c(str, DICT_PROTOCOL_REPLY_FAIL);
str_append_tabescaped(str, result->error);
}
- dict_cmd_reply_handle_timings(cmd, str, cmd_stats.lookups);
+ dict_cmd_reply_handle_stats(cmd, str, cmd_stats.lookups);
str_append_c(str, '\n');
cmd->reply = i_strdup(str_c(str));
i_error("dict_iterate() failed: %s", error);
str_printfa(str, "%c%s", DICT_PROTOCOL_REPLY_FAIL, error);
}
- dict_cmd_reply_handle_timings(cmd, str, cmd_stats.iterations);
+ dict_cmd_reply_handle_stats(cmd, str, cmd_stats.iterations);
str_append_c(str, '\n');
cmd->reply = i_strdup(str_c(str));
str_append_c(str, '\t');
str_append_tabescaped(str, result->error);
}
- dict_cmd_reply_handle_timings(cmd, str, cmd_stats.commits);
+ dict_cmd_reply_handle_stats(cmd, str, cmd_stats.commits);
str_append_c(str, '\n');
cmd->reply = i_strdup(str_c(str));
void dict_commands_init(void)
{
- cmd_stats.lookups = timing_init();
- cmd_stats.iterations = timing_init();
- cmd_stats.commits = timing_init();
+ cmd_stats.lookups = stats_dist_init();
+ cmd_stats.iterations = stats_dist_init();
+ cmd_stats.commits = stats_dist_init();
}
void dict_commands_deinit(void)
{
- timing_deinit(&cmd_stats.lookups);
- timing_deinit(&cmd_stats.iterations);
- timing_deinit(&cmd_stats.commits);
+ stats_dist_deinit(&cmd_stats.lookups);
+ stats_dist_deinit(&cmd_stats.iterations);
+ stats_dist_deinit(&cmd_stats.commits);
}
struct dict_connection;
struct dict_command_stats {
- struct timing *lookups;
- struct timing *iterations;
- struct timing *commits;
+ struct stats_dist *lookups;
+ struct stats_dist *iterations;
+ struct stats_dist *commits;
};
extern struct dict_command_stats cmd_stats;
#include "randgen.h"
#include "str.h"
#include "hostpid.h"
-#include "timing.h"
+#include "stats-dist.h"
#include "process-title.h"
#include "env-util.h"
#include "module-dir.h"
static bool proctitle_updated;
static void
-add_timing_string(string_t *str, struct timing *timing, const char *name)
+add_stats_string(string_t *str, struct stats_dist *stats, const char *name)
{
str_printfa(str, ", %u %s:%"PRIu64"/%"PRIu64"/%"PRIu64"/%"PRIu64,
- timing_get_count(timing), name,
- timing_get_min(timing)/1000, timing_get_avg(timing)/1000,
- timing_get_95th(timing)/1000, timing_get_max(timing)/1000);
- timing_reset(timing);
+ stats_dist_get_count(stats), name,
+ stats_dist_get_min(stats)/1000, stats_dist_get_avg(stats)/1000,
+ stats_dist_get_95th(stats)/1000, stats_dist_get_max(stats)/1000);
+ stats_dist_reset(stats);
}
static void dict_proctitle_update(void *context ATTR_UNUSED)
str_printfa(str, "[%u clients", dict_connections_current_count());
- add_timing_string(str, cmd_stats.lookups, "lookups");
- add_timing_string(str, cmd_stats.iterations, "iters");
- add_timing_string(str, cmd_stats.commits, "commits");
+ add_stats_string(str, cmd_stats.lookups, "lookups");
+ add_stats_string(str, cmd_stats.iterations, "iters");
+ add_stats_string(str, cmd_stats.commits, "commits");
str_append_c(str, ']');
process_title_set(str_c(str));
#include "istream.h"
#include "istream-seekable.h"
#include "ostream.h"
-#include "timing.h"
+#include "stats-dist.h"
#include "time-util.h"
#include "istream-fs-stats.h"
#include "fs-api-private.h"
i_free(fs->temp_path_prefix);
for (i = 0; i < FS_OP_COUNT; i++) {
if (fs->stats.timings[i] != NULL)
- timing_deinit(&fs->stats.timings[i]);
+ stats_dist_deinit(&fs->stats.timings[i]);
}
T_BEGIN {
fs->v.deinit(fs);
}
static void
-fs_timing_end(struct timing **timing, const struct timeval *start_tv)
+fs_timing_end(struct stats_dist **timing, const struct timeval *start_tv)
{
struct timeval now;
long long diff;
diff = timeval_diff_usecs(&now, start_tv);
if (diff > 0) {
if (*timing == NULL)
- *timing = timing_init();
- timing_add_usecs(*timing, diff);
+ *timing = stats_dist_init();
+ stats_dist_add(*timing, diff);
}
}
for (unsigned int i = 0; i < ops_count; i++) {
if (stats->timings[ops[i]] != NULL)
- ret += timing_get_sum(stats->timings[ops[i]]);
+ ret += stats_dist_get_sum(stats->timings[ops[i]]);
}
return ret;
}
/* Cumulative sum of usecs spent on calls - set only if
fs_settings.enable_timing=TRUE */
- struct timing *timings[FS_OP_COUNT];
+ struct stats_dist *timings[FS_OP_COUNT];
};
struct fs_metadata {
sha2.c \
sha3.c \
sort.c \
+ stats-dist.c \
str.c \
str-find.c \
str-sanitize.c \
strfuncs.c \
strnum.c \
time-util.c \
- timing.c \
unix-socket-create.c \
unlink-directory.c \
unlink-old-files.c \
sha2.h \
sha3.h \
sort.h \
+ stats-dist.h \
str.h \
str-find.h \
str-sanitize.h \
strfuncs.h \
strnum.h \
time-util.h \
- timing.h \
unix-socket-create.h \
unlink-directory.h \
unlink-old-files.h \
test-printf-format-fix.c \
test-priorityq.c \
test-seq-range-array.c \
+ test-stats-dist.c \
test-str.c \
test-strescape.c \
test-strfuncs.c \
test-str-sanitize.c \
test-str-table.c \
test-time-util.c \
- test-timing.c \
test-unichar.c \
test-utc-mktime.c \
test-uri.c \
--- /dev/null
+/* Copyright (c) 2015-2017 Dovecot authors, see the included COPYING file */
+
+#include "lib.h"
+#include "stats-dist.h"
+#include "sort.h"
+
+/* In order to have a vaguely accurate 95th percentile, you need way
+ more than 20 in your subsample. */
+#define TIMING_DEFAULT_SUBSAMPLING_BUFFER (20*24) /* 20*24 fits in a page */
+
+struct stats_dist {
+ unsigned int sample_count;
+ unsigned int count;
+ bool sorted;
+ uint64_t min;
+ uint64_t max;
+ uint64_t sum;
+ uint64_t samples[];
+};
+
+struct stats_dist *stats_dist_init(void)
+{
+ return stats_dist_init_with_size(TIMING_DEFAULT_SUBSAMPLING_BUFFER);
+}
+
+struct stats_dist *stats_dist_init_with_size(unsigned int sample_count)
+{
+ i_assert(sample_count > 0);
+
+ struct stats_dist *stats =
+ i_malloc(sizeof(struct stats_dist) +
+ sizeof(uint64_t) * sample_count);
+ stats->sample_count = sample_count;
+ return stats;
+}
+
+void stats_dist_deinit(struct stats_dist **_stats)
+{
+ i_free_and_null(*_stats);
+}
+
+void stats_dist_reset(struct stats_dist *stats)
+{
+ unsigned int sample_count = stats->sample_count;
+ i_zero(stats);
+ stats->sample_count = sample_count;
+}
+
+void stats_dist_add(struct stats_dist *stats, uint64_t value)
+{
+ if (stats->count < stats->sample_count) {
+ stats->samples[stats->count] = value;
+ if (stats->count == 0)
+ stats->min = stats->max = value;
+ } else {
+ unsigned int idx = i_rand_limit(stats->count);
+ if (idx < stats->sample_count)
+ stats->samples[idx] = value;
+ }
+
+ stats->count++;
+ stats->sum += value;
+ if (stats->max < value)
+ stats->max = value;
+ if (stats->min > value)
+ stats->min = value;
+ stats->sorted = FALSE;
+}
+
+unsigned int stats_dist_get_count(const struct stats_dist *stats)
+{
+ return stats->count;
+}
+
+uint64_t stats_dist_get_sum(const struct stats_dist *stats)
+{
+ return stats->sum;
+}
+
+uint64_t stats_dist_get_min(const struct stats_dist *stats)
+{
+ return stats->min;
+}
+
+uint64_t stats_dist_get_max(const struct stats_dist *stats)
+{
+ return stats->max;
+}
+
+uint64_t stats_dist_get_avg(const struct stats_dist *stats)
+{
+ if (stats->count == 0)
+ return 0;
+
+ return (stats->sum + stats->count/2) / stats->count;
+}
+
+static void stats_dist_ensure_sorted(struct stats_dist *stats)
+{
+ if (stats->sorted)
+ return;
+
+ unsigned int count = (stats->count < stats->sample_count)
+ ? stats->count
+ : stats->sample_count;
+ i_qsort(stats->samples, count, sizeof(*stats->samples),
+ uint64_cmp);
+ stats->sorted = TRUE;
+}
+
+uint64_t stats_dist_get_median(const struct stats_dist *stats)
+{
+ if (stats->count == 0)
+ return 0;
+ /* cast-away const - reading requires sorting */
+ stats_dist_ensure_sorted((struct stats_dist *)stats);
+ unsigned int count = (stats->count < stats->sample_count)
+ ? stats->count
+ : stats->sample_count;
+ unsigned int idx1 = (count-1)/2, idx2 = count/2;
+ return (stats->samples[idx1] + stats->samples[idx2]) / 2;
+}
+
+/* This is independent of the stats framework, useful for any selection task */
+static unsigned int stats_dist_get_index(unsigned int range, double fraction)
+{
+ /* With out of range fractions, we can give the caller what
+ they probably want rather than just crashing. */
+ if (fraction >= 1.)
+ return range - 1;
+ if (fraction <= 0.)
+ return 0;
+
+ double idx_float = range * fraction;
+ unsigned int idx = idx_float; /* C defaults to rounding down */
+ idx_float -= idx;
+ /* Exact boundaries belong to the open range below them.
+ As FP isn't exact, and ratios may be specified inexactly,
+ include a small amount of fuzz around the exact boundary. */
+ if (idx_float < 1e-8*range)
+ idx--;
+
+ return idx;
+}
+
+uint64_t stats_dist_get_percentile(const struct stats_dist *stats, double fraction)
+{
+ if (stats->count == 0)
+ return 0;
+ /* cast-away const - reading requires sorting */
+ stats_dist_ensure_sorted((struct stats_dist *)stats);
+ unsigned int count = (stats->count < stats->sample_count)
+ ? stats->count
+ : stats->sample_count;
+ unsigned int idx = stats_dist_get_index(count, fraction);
+ return stats->samples[idx];
+}
--- /dev/null
+#ifndef STATS_DIST_H
+#define STATS_DIST_H
+
+struct stats_dist *stats_dist_init(void);
+struct stats_dist *stats_dist_init_with_size(unsigned int sample_count);
+void stats_dist_deinit(struct stats_dist **stats);
+
+/* Reset all events. */
+void stats_dist_reset(struct stats_dist *stats);
+
+/* Add a new event. */
+void stats_dist_add(struct stats_dist *stats, uint64_t value);
+
+/* Returns number of events added. */
+unsigned int stats_dist_get_count(const struct stats_dist *stats);
+/* Returns the sum of all events. */
+uint64_t stats_dist_get_sum(const struct stats_dist *stats);
+
+/* Returns events' minimum. */
+uint64_t stats_dist_get_min(const struct stats_dist *stats);
+/* Returns events' maximum. */
+uint64_t stats_dist_get_max(const struct stats_dist *stats);
+/* Returns events' average. */
+uint64_t stats_dist_get_avg(const struct stats_dist *stats);
+/* Returns events' approximate (through random subsampling) median. */
+uint64_t stats_dist_get_median(const struct stats_dist *stats);
+/* Returns events' approximate (through random subsampling) percentile.
+ fraction parameter is in the range (0., 1.], so 95th %-ile is 0.95. */
+uint64_t stats_dist_get_percentile(const struct stats_dist *stats, double fraction);
+/* Returns events' approximate (through random subsampling) 95th percentile. */
+static inline uint64_t stats_dist_get_95th(const struct stats_dist *stats)
+{
+ return stats_dist_get_percentile(stats, 0.95);
+}
+
+#endif
FATAL(fatal_printf_format_fix)
TEST(test_priorityq)
TEST(test_seq_range_array)
+TEST(test_stats_dist)
TEST(test_str)
TEST(test_strescape)
TEST(test_strfuncs)
TEST(test_str_sanitize)
TEST(test_str_table)
TEST(test_time_util)
-TEST(test_timing)
TEST(test_unichar)
TEST(test_uri)
TEST(test_utc_mktime)
--- /dev/null
+/* Copyright (c) 2007-2017 Dovecot authors, see the included COPYING file */
+
+#include "test-lib.h"
+#include "stats-dist.h"
+#include "sort.h"
+
+static void
+test_stats_dist_verify(const struct stats_dist *t, const int64_t *input,
+ unsigned int input_size)
+{
+ uint64_t min = INT_MAX, max = 0, sum = 0;
+ uint64_t *copy;
+ unsigned int i;
+
+ i_assert(input_size > 0);
+
+ copy = i_new(uint64_t, input_size);
+ for (i = 0; i < input_size; i++) {
+ uint64_t value = input[i];
+
+ if (min > value)
+ min = value;
+ if (max < value)
+ max = value;
+ sum += value;
+ copy[i] = value;
+ }
+ i_qsort(copy, input_size, sizeof(*copy), uint64_cmp);
+
+ test_assert_idx(stats_dist_get_count(t) == input_size, input_size);
+ test_assert_idx(stats_dist_get_sum(t) == sum, input_size);
+ test_assert_idx(stats_dist_get_min(t) == min, input_size);
+ test_assert_idx(stats_dist_get_max(t) == max, input_size);
+ test_assert_idx(stats_dist_get_avg(t) == (sum + input_size/2)/input_size, input_size);
+
+ /* these aren't always fully accurate: */
+ test_assert_idx(stats_dist_get_median(t) >= copy[(input_size-1)/2] &&
+ stats_dist_get_median(t) <= copy[input_size/2],
+ input_size);
+ /* when we have 20 elements, [19] is the max, not the 95th %ile, so subtract 1 */
+ test_assert_idx(stats_dist_get_95th(t) == copy[input_size*95/100 - ((input_size%20) == 0 ? 1 : 0)],
+ input_size);
+
+ i_free(copy);
+}
+
+void test_stats_dist(void)
+{
+ static int64_t test_input1[] = {
+ 20, 19, 18, 1, 2, 3, 4, 5, 6, 7, 8,
+ 9, 10, 11, 12, 13, 14, 15, 16, 17, -1
+ };
+ static int64_t test_input2[] = {
+ 20, 21, 19, 18, 1, 2, 3, 4, 5, 6, 7, 8,
+ 9, 10, 11, 12, 13, 14, 15, 16, 17, -1
+ };
+ static int64_t test_input3[] = {
+ 20, 21, 19, 18, 1, 2, 3, 4, 5, 6, 7, 8,
+ 9, 10, 11, 12, 13, 14, 15, 16, 17, 22, -1
+ };
+ static int64_t *test_inputs[] = {
+ test_input1, test_input2, test_input3
+ };
+ struct stats_dist *t;
+ unsigned int i, j;
+
+ for (i = 0; i < N_ELEMENTS(test_inputs); i++) {
+ test_begin(t_strdup_printf("stats_dists %u", i));
+ t = stats_dist_init();
+ for (j = 0; test_inputs[i][j] >= 0; j++) {
+ stats_dist_add(t, test_inputs[i][j]);
+ test_stats_dist_verify(t, test_inputs[i], j+1);
+ }
+ stats_dist_reset(t);
+ test_assert(stats_dist_get_count(t) == 0);
+ test_assert(stats_dist_get_max(t) == 0);
+ stats_dist_deinit(&t);
+ test_end();
+ }
+
+ test_begin("stats_dists large");
+ t = stats_dist_init();
+ for (i = 0; i < 10000; i++)
+ stats_dist_add(t, i);
+ test_assert(stats_dist_get_count(t) == i);
+ test_assert(stats_dist_get_sum(t) == (i-1)*i/2);
+ test_assert(stats_dist_get_min(t) == 0);
+ test_assert(stats_dist_get_max(t) == i-1);
+ test_assert(stats_dist_get_avg(t) == i/2);
+ /* just test that these work: */
+ test_assert(stats_dist_get_median(t) > 0 && stats_dist_get_median(t) < i-1);
+ test_assert(stats_dist_get_95th(t) > 0 && stats_dist_get_95th(t) < i-1);
+ stats_dist_deinit(&t);
+ test_end();
+}
+++ /dev/null
-/* Copyright (c) 2007-2017 Dovecot authors, see the included COPYING file */
-
-#include "test-lib.h"
-#include "timing.h"
-#include "sort.h"
-
-static void
-test_timing_verify(const struct timing *t, const int64_t *input,
- unsigned int input_size)
-{
- uint64_t min = INT_MAX, max = 0, sum = 0;
- uint64_t *copy;
- unsigned int i;
-
- i_assert(input_size > 0);
-
- copy = i_new(uint64_t, input_size);
- for (i = 0; i < input_size; i++) {
- uint64_t value = input[i];
-
- if (min > value)
- min = value;
- if (max < value)
- max = value;
- sum += value;
- copy[i] = value;
- }
- i_qsort(copy, input_size, sizeof(*copy), uint64_cmp);
-
- test_assert_idx(timing_get_count(t) == input_size, input_size);
- test_assert_idx(timing_get_sum(t) == sum, input_size);
- test_assert_idx(timing_get_min(t) == min, input_size);
- test_assert_idx(timing_get_max(t) == max, input_size);
- test_assert_idx(timing_get_avg(t) == (sum + input_size/2)/input_size, input_size);
-
- /* these aren't always fully accurate: */
- test_assert_idx(timing_get_median(t) >= copy[(input_size-1)/2] &&
- timing_get_median(t) <= copy[input_size/2],
- input_size);
- /* when we have 20 elements, [19] is the max, not the 95th %ile, so subtract 1 */
- test_assert_idx(timing_get_95th(t) == copy[input_size*95/100 - ((input_size%20) == 0 ? 1 : 0)],
- input_size);
-
- i_free(copy);
-}
-
-void test_timing(void)
-{
- static int64_t test_input1[] = {
- 20, 19, 18, 1, 2, 3, 4, 5, 6, 7, 8,
- 9, 10, 11, 12, 13, 14, 15, 16, 17, -1
- };
- static int64_t test_input2[] = {
- 20, 21, 19, 18, 1, 2, 3, 4, 5, 6, 7, 8,
- 9, 10, 11, 12, 13, 14, 15, 16, 17, -1
- };
- static int64_t test_input3[] = {
- 20, 21, 19, 18, 1, 2, 3, 4, 5, 6, 7, 8,
- 9, 10, 11, 12, 13, 14, 15, 16, 17, 22, -1
- };
- static int64_t *test_inputs[] = {
- test_input1, test_input2, test_input3
- };
- struct timing *t;
- unsigned int i, j;
-
- for (i = 0; i < N_ELEMENTS(test_inputs); i++) {
- test_begin(t_strdup_printf("timings %u", i));
- t = timing_init();
- for (j = 0; test_inputs[i][j] >= 0; j++) {
- timing_add_usecs(t, test_inputs[i][j]);
- test_timing_verify(t, test_inputs[i], j+1);
- }
- timing_reset(t);
- test_assert(timing_get_count(t) == 0);
- test_assert(timing_get_max(t) == 0);
- timing_deinit(&t);
- test_end();
- }
-
- test_begin("timings large");
- t = timing_init();
- for (i = 0; i < 10000; i++)
- timing_add_usecs(t, i);
- test_assert(timing_get_count(t) == i);
- test_assert(timing_get_sum(t) == (i-1)*i/2);
- test_assert(timing_get_min(t) == 0);
- test_assert(timing_get_max(t) == i-1);
- test_assert(timing_get_avg(t) == i/2);
- /* just test that these work: */
- test_assert(timing_get_median(t) > 0 && timing_get_median(t) < i-1);
- test_assert(timing_get_95th(t) > 0 && timing_get_95th(t) < i-1);
- timing_deinit(&t);
- test_end();
-}
+++ /dev/null
-/* Copyright (c) 2015-2017 Dovecot authors, see the included COPYING file */
-
-#include "lib.h"
-#include "timing.h"
-#include "sort.h"
-
-/* In order to have a vaguely accurate 95th percentile, you need way
- more than 20 in your subsample. */
-#define TIMING_DEFAULT_SUBSAMPLING_BUFFER (20*24) /* 20*24 fits in a page */
-
-struct timing {
- unsigned int sample_count;
- unsigned int count;
- bool sorted;
- uint64_t min;
- uint64_t max;
- uint64_t sum;
- uint64_t samples[];
-};
-
-struct timing *timing_init(void)
-{
- return timing_init_with_size(TIMING_DEFAULT_SUBSAMPLING_BUFFER);
-}
-
-struct timing *timing_init_with_size(unsigned int sample_count)
-{
- i_assert(sample_count > 0);
-
- struct timing *timing =
- i_malloc(sizeof(struct timing) +
- sizeof(uint64_t) * sample_count);
- timing->sample_count = sample_count;
- return timing;
-}
-
-void timing_deinit(struct timing **_timing)
-{
- i_free_and_null(*_timing);
-}
-
-void timing_reset(struct timing *timing)
-{
- unsigned int sample_count = timing->sample_count;
- i_zero(timing);
- timing->sample_count = sample_count;
-}
-
-void timing_add_usecs(struct timing *timing, uint64_t usecs)
-{
- if (timing->count < timing->sample_count) {
- timing->samples[timing->count] = usecs;
- if (timing->count == 0)
- timing->min = timing->max = usecs;
- } else {
- unsigned int idx = i_rand_limit(timing->count);
- if (idx < timing->sample_count)
- timing->samples[idx] = usecs;
- }
-
- timing->count++;
- timing->sum += usecs;
- if (timing->max < usecs)
- timing->max = usecs;
- if (timing->min > usecs)
- timing->min = usecs;
- timing->sorted = FALSE;
-}
-
-unsigned int timing_get_count(const struct timing *timing)
-{
- return timing->count;
-}
-
-uint64_t timing_get_sum(const struct timing *timing)
-{
- return timing->sum;
-}
-
-uint64_t timing_get_min(const struct timing *timing)
-{
- return timing->min;
-}
-
-uint64_t timing_get_max(const struct timing *timing)
-{
- return timing->max;
-}
-
-uint64_t timing_get_avg(const struct timing *timing)
-{
- if (timing->count == 0)
- return 0;
-
- return (timing->sum + timing->count/2) / timing->count;
-}
-
-static void timing_ensure_sorted(struct timing *timing)
-{
- if (timing->sorted)
- return;
-
- unsigned int count = (timing->count < timing->sample_count)
- ? timing->count
- : timing->sample_count;
- i_qsort(timing->samples, count, sizeof(*timing->samples),
- uint64_cmp);
- timing->sorted = TRUE;
-}
-
-uint64_t timing_get_median(const struct timing *timing)
-{
- if (timing->count == 0)
- return 0;
- /* cast-away const - reading requires sorting */
- timing_ensure_sorted((struct timing *)timing);
- unsigned int count = (timing->count < timing->sample_count)
- ? timing->count
- : timing->sample_count;
- unsigned int idx1 = (count-1)/2, idx2 = count/2;
- return (timing->samples[idx1] + timing->samples[idx2]) / 2;
-}
-
-/* This is independent of the timing framework, useful for any selection task */
-static unsigned int timing_get_index(unsigned int range, double fraction)
-{
- /* With out of range fractions, we can give the caller what
- they probably want rather than just crashing. */
- if (fraction >= 1.)
- return range - 1;
- if (fraction <= 0.)
- return 0;
-
- double idx_float = range * fraction;
- unsigned int idx = idx_float; /* C defaults to rounding down */
- idx_float -= idx;
- /* Exact boundaries belong to the open range below them.
- As FP isn't exact, and ratios may be specified inexactly,
- include a small amount of fuzz around the exact boundary. */
- if (idx_float < 1e-8*range)
- idx--;
-
- return idx;
-}
-
-uint64_t timing_get_percentile(const struct timing *timing, double fraction)
-{
- if (timing->count == 0)
- return 0;
- /* cast-away const - reading requires sorting */
- timing_ensure_sorted((struct timing *)timing);
- unsigned int count = (timing->count < timing->sample_count)
- ? timing->count
- : timing->sample_count;
- unsigned int idx = timing_get_index(count, fraction);
- return timing->samples[idx];
-}
+++ /dev/null
-#ifndef TIMING_H
-#define TIMING_H
-
-struct timing *timing_init(void);
-struct timing *timing_init_with_size(unsigned int sample_count);
-void timing_deinit(struct timing **timing);
-
-/* Reset all events. */
-void timing_reset(struct timing *timing);
-
-/* Add a new event that took the specified number of usecs. */
-void timing_add_usecs(struct timing *timing, uint64_t usecs);
-
-/* Returns number of events added. */
-unsigned int timing_get_count(const struct timing *timing);
-/* Returns the sum of all usecs added. */
-uint64_t timing_get_sum(const struct timing *timing);
-
-/* Returns events' minimum. */
-uint64_t timing_get_min(const struct timing *timing);
-/* Returns events' maximum. */
-uint64_t timing_get_max(const struct timing *timing);
-/* Returns events' average. */
-uint64_t timing_get_avg(const struct timing *timing);
-/* Returns events' approximate (through random subsampling) median. */
-uint64_t timing_get_median(const struct timing *timing);
-/* Returns events' approximate (through random subsampling) percentile.
- fraction parameter is in the range (0., 1.], so 95th %-ile is 0.95. */
-uint64_t timing_get_percentile(const struct timing *timing, double fraction);
-/* Returns events' approximate (through random subsampling) 95th percentile. */
-static inline uint64_t timing_get_95th(const struct timing *timing)
-{
- return timing_get_percentile(timing, 0.95);
-}
-
-#endif
#include "lib.h"
#include "str.h"
-#include "timing.h"
+#include "stats-dist.h"
#include "strescape.h"
#include "connection.h"
#include "ostream.h"
master_service_client_connection_destroyed(master_service);
}
-static void reader_client_dump_timing(string_t *str, struct timing *timing,
- const char *const *fields)
+static void reader_client_dump_stats(string_t *str, struct stats_dist *stats,
+ const char *const *fields)
{
for (unsigned int i = 0; fields[i] != NULL; i++) {
const char *field = fields[i];
str_append_c(str, '\t');
if (strcmp(field, "count") == 0)
- str_printfa(str, "%u", timing_get_count(timing));
+ str_printfa(str, "%u", stats_dist_get_count(stats));
else if (strcmp(field, "sum") == 0)
- str_printfa(str, "%"PRIu64, timing_get_sum(timing));
+ str_printfa(str, "%"PRIu64, stats_dist_get_sum(stats));
else if (strcmp(field, "min") == 0)
- str_printfa(str, "%"PRIu64, timing_get_min(timing));
+ str_printfa(str, "%"PRIu64, stats_dist_get_min(stats));
else if (strcmp(field, "max") == 0)
- str_printfa(str, "%"PRIu64, timing_get_max(timing));
+ str_printfa(str, "%"PRIu64, stats_dist_get_max(stats));
else if (strcmp(field, "avg") == 0)
- str_printfa(str, "%"PRIu64, timing_get_avg(timing));
+ str_printfa(str, "%"PRIu64, stats_dist_get_avg(stats));
else if (strcmp(field, "median") == 0)
- str_printfa(str, "%"PRIu64, timing_get_median(timing));
+ str_printfa(str, "%"PRIu64, stats_dist_get_median(stats));
else if (strcmp(field, "%95") == 0)
- str_printfa(str, "%"PRIu64, timing_get_95th(timing));
+ str_printfa(str, "%"PRIu64, stats_dist_get_95th(stats));
else {
/* return unknown fields as empty */
}
while ((metric = stats_metrics_iterate(iter)) != NULL) {
str_truncate(str, 0);
str_append_tabescaped(str, metric->name);
- reader_client_dump_timing(str, metric->duration_timing, args);
+ reader_client_dump_stats(str, metric->duration_stats, args);
for (unsigned int i = 0; i < metric->fields_count; i++) {
str_append_c(str, '\t');
str_append_tabescaped(str, metric->fields[i].field_key);
- reader_client_dump_timing(str, metric->fields[i].timing, args);
+ reader_client_dump_stats(str, metric->fields[i].stats, args);
}
str_append_c(str, '\n');
o_stream_nsend(client->conn.output, str_data(str), str_len(str));
#include "lib.h"
#include "array.h"
-#include "timing.h"
+#include "stats-dist.h"
#include "time-util.h"
#include "event-filter.h"
#include "stats-settings.h"
metric = p_new(metrics->pool, struct metric, 1);
metric->name = p_strdup(metrics->pool, set->name);
- metric->duration_timing = timing_init();
+ metric->duration_stats = stats_dist_init();
fields = t_strsplit_spaces(set->fields, " ");
metric->fields_count = str_array_length(fields);
for (unsigned int i = 0; i < metric->fields_count; i++) {
metric->fields[i].field_key =
p_strdup(metrics->pool, fields[i]);
- metric->fields[i].timing = timing_init();
+ metric->fields[i].stats = stats_dist_init();
}
}
array_append(&metrics->metrics, &metric, 1);
static void stats_metric_free(struct metric *metric)
{
- timing_deinit(&metric->duration_timing);
+ stats_dist_deinit(&metric->duration_stats);
for (unsigned int i = 0; i < metric->fields_count; i++)
- timing_deinit(&metric->fields[i].timing);
+ stats_dist_deinit(&metric->fields[i].stats);
}
void stats_metrics_deinit(struct stats_metrics **_metrics)
struct metric *const *metricp;
array_foreach(&metrics->metrics, metricp) {
- timing_reset((*metricp)->duration_timing);
+ stats_dist_reset((*metricp)->duration_stats);
for (unsigned int i = 0; i < (*metricp)->fields_count; i++)
- timing_reset((*metricp)->fields[i].timing);
+ stats_dist_reset((*metricp)->fields[i].stats);
}
}
event_get_create_time(event, &tv_start);
duration = timeval_diff_usecs(&tv_end, &tv_start);
}
- timing_add_usecs(metric->duration_timing, duration);
+ stats_dist_add(metric->duration_stats, duration);
for (unsigned int i = 0; i < metric->fields_count; i++) {
const struct event_field *field =
field->value.timeval.tv_usec;
break;
}
- timing_add_usecs(metric->fields[i].timing, num);
+ stats_dist_add(metric->fields[i].stats, num);
}
}
struct metric_field {
const char *field_key;
- struct timing *timing;
+ struct stats_dist *stats;
};
struct metric {
const char *name;
/* Timing for how long the event existed */
- struct timing *duration_timing;
+ struct stats_dist *duration_stats;
unsigned int fields_count;
struct metric_field *fields;