diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 1f3babef1588e6738f24cd5b4ee7d97bb281d15f..e190b313d6f74a36fcb8827ea236e1059d74b754 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -76,6 +76,7 @@ set (core_sources reflection.c assoc.c rmean.c + latency.c histogram.c util.c path_lock.c diff --git a/src/box/vinyl.c b/src/box/vinyl.c index 899570258d440583c1661db2668b74af29582626..f2a9006bc57cd2b7bd8183328c26142b2a7c5af9 100644 --- a/src/box/vinyl.c +++ b/src/box/vinyl.c @@ -4536,6 +4536,7 @@ vy_index_info(struct vy_index *index, struct info_handler *h) info_append_int(h, "lookup", stat->lookup); vy_info_append_stmt_counter(h, "get", &stat->get); vy_info_append_stmt_counter(h, "put", &stat->put); + info_append_double(h, "latency", latency_get(&stat->latency)); info_table_begin(h, "upsert"); info_append_int(h, "squashed", stat->upsert.squashed); @@ -4969,6 +4970,9 @@ vy_index_new(struct vy_env *e, struct index_def *user_index_def, tuple_format_ref(index->upsert_format, 1); } + if (vy_index_stat_create(&index->stat) != 0) + goto fail_stat; + index->run_hist = histogram_new(run_buckets, lengthof(run_buckets)); if (index->run_hist == NULL) goto fail_run_hist; @@ -5005,6 +5009,8 @@ vy_index_new(struct vy_env *e, struct index_def *user_index_def, fail_mem: histogram_delete(index->run_hist); fail_run_hist: + vy_index_stat_destroy(&index->stat); +fail_stat: tuple_format_ref(index->space_format_with_colmask, -1); fail_space_format_with_colmask: tuple_format_ref(index->upsert_format, -1); @@ -5224,6 +5230,7 @@ vy_index_delete(struct vy_index *index) free(index->key_def); free(index->user_key_def); histogram_delete(index->run_hist); + vy_index_stat_destroy(&index->stat); vy_cache_destroy(&index->cache); tuple_format_ref(index->space_format, -1); free(index->tree); @@ -7930,6 +7937,8 @@ vy_read_iterator_next_range(struct vy_read_iterator *itr, struct tuple **ret) static NODISCARD int vy_read_iterator_next(struct vy_read_iterator *itr, struct tuple **result) { + ev_tstamp start_time = ev_now(loop()); + *result = NULL; if (!itr->search_started) @@ -8028,6 +8037,7 @@ vy_read_iterator_next(struct vy_read_iterator *itr, struct tuple **result) tuple_unref(prev_key); } + latency_collect(&index->stat.latency, ev_now(loop()) - start_time); return rc; } diff --git a/src/box/vy_stat.h b/src/box/vy_stat.h index d844c4f197a38089d49dc1ee81fa5285a664a86a..1a42665a142b06fdf8c66650a8e17efdd05c9c35 100644 --- a/src/box/vy_stat.h +++ b/src/box/vy_stat.h @@ -33,6 +33,7 @@ #include <stdint.h> +#include "latency.h" #include "tuple.h" #if defined(__cplusplus) @@ -117,6 +118,8 @@ struct vy_index_stat { struct vy_stmt_counter get; /** Number of statements written to this index. */ struct vy_stmt_counter put; + /** Read latency. */ + struct latency latency; /** Upsert statistics. */ struct { /** How many upsert chains have been squashed. */ @@ -173,6 +176,18 @@ struct vy_cache_stat { struct vy_stmt_counter evict; }; +static inline int +vy_index_stat_create(struct vy_index_stat *stat) +{ + return latency_create(&stat->latency); +} + +static inline void +vy_index_stat_destroy(struct vy_index_stat *stat) +{ + latency_destroy(&stat->latency); +} + static inline void vy_stmt_counter_acct_tuple(struct vy_stmt_counter *c, const struct tuple *tuple) diff --git a/src/latency.c b/src/latency.c new file mode 100644 index 0000000000000000000000000000000000000000..406bc4f68c12ec42b918bd6f9e430e4e3cd14286 --- /dev/null +++ b/src/latency.c @@ -0,0 +1,91 @@ +/* + * Copyright 2010-2017, Tarantool AUTHORS, please see AUTHORS file. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * 1. Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY AUTHORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF + * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +#include "latency.h" + +#include <stdint.h> + +#include "histogram.h" +#include "trivia/util.h" + +enum { + USEC_PER_MSEC = 1000, + USEC_PER_SEC = 1000000, +}; + +enum { + LATENCY_PERCENTILE = 99, +}; + +int +latency_create(struct latency *latency) +{ + enum { US = 1, MS = USEC_PER_MSEC, S = USEC_PER_SEC }; + static int64_t buckets[] = { + 100 * US, 200 * US, 300 * US, 400 * US, 500 * US, 600 * US, + 700 * US, 800 * US, 900 * US, + 1 * MS, 2 * MS, 3 * MS, 4 * MS, 5 * MS, 6 * MS, + 7 * MS, 8 * MS, 9 * MS, + 10 * MS, 20 * MS, 30 * MS, 40 * MS, 50 * MS, 60 * MS, + 70 * MS, 80 * MS, 90 * MS, + 100 * MS, 200 * MS, 300 * MS, 400 * MS, 500 * MS, 600 * MS, + 700 * MS, 800 * MS, 900 * MS, + 1 * S, 2 * S, 3 * S, 4 * S, 5 * S, 6 * S, + 7 * S, 8 * S, 9 * S, 10 * S, + }; + + latency->histogram = histogram_new(buckets, lengthof(buckets)); + if (latency->histogram == NULL) + return -1; + + histogram_collect(latency->histogram, 0); + return 0; +} + +void +latency_destroy(struct latency *latency) +{ + histogram_delete(latency->histogram); +} + +void +latency_collect(struct latency *latency, double value) +{ + int64_t value_usec = value * USEC_PER_SEC; + histogram_collect(latency->histogram, value_usec); +} + +double +latency_get(struct latency *latency) +{ + int64_t value_usec = histogram_percentile(latency->histogram, + LATENCY_PERCENTILE); + return (double)value_usec / USEC_PER_SEC; +} diff --git a/src/latency.h b/src/latency.h new file mode 100644 index 0000000000000000000000000000000000000000..cb53cea96501d30369dfad8a9726e283899b51de --- /dev/null +++ b/src/latency.h @@ -0,0 +1,73 @@ +#ifndef TARANTOOL_LATENCY_H_INCLUDED +#define TARANTOOL_LATENCY_H_INCLUDED +/* + * Copyright 2010-2017, Tarantool AUTHORS, please see AUTHORS file. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * 1. Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY AUTHORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF + * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +struct histogram; + +/** + * Latency counter. + */ +struct latency { + /** + * Histogram of all latency observations, + * in microseconds. + */ + struct histogram *histogram; +}; + +/** + * Initialize a latency counter. + * Return 0 on success, -1 on OOM. + */ +int +latency_create(struct latency *latency); + +/** + * Destroy a latency counter. + */ +void +latency_destroy(struct latency *latency); + +/** + * Update a latency counter with a new observation. + * @value is the observed latency value, in seconds. + */ +void +latency_collect(struct latency *latency, double value); + +/** + * Get accumulated latency value, in seconds. + */ +double +latency_get(struct latency *latency); + +#endif /* TARANTOOL_LATENCY_H_INCLUDED */