diff --git a/include/maxscale/statistics.h b/include/maxscale/statistics.h index 798df286f..c9b21f446 100644 --- a/include/maxscale/statistics.h +++ b/include/maxscale/statistics.h @@ -40,13 +40,18 @@ enum ts_stats_type TS_STATS_AVG /**< Average of all values */ }; -/** stats_init should be called only once */ -void ts_stats_init(); - -/** No-op for now */ -void ts_stats_end(); - +/** + * @brief Allocate a new statistics object + * + * @return New statistics object or NULL if memory allocation failed + */ ts_stats_t ts_stats_alloc(); + +/** + * @brief Free statistics + * + * @param stats Statistics to free + */ void ts_stats_free(ts_stats_t stats); /** @@ -66,11 +71,7 @@ int64_t ts_stats_get(ts_stats_t stats, enum ts_stats_type type); * @param stats Statistics to add to * @param thread_id ID of thread */ -static void inline -ts_stats_increment(ts_stats_t stats, int thread_id) -{ - ((int64_t*)stats)[thread_id]++; -} +void ts_stats_increment(ts_stats_t stats, int thread_id); /** * @brief Assign a value to a statistics element @@ -81,11 +82,7 @@ ts_stats_increment(ts_stats_t stats, int thread_id) * @param value Value to set to * @param thread_id ID of thread */ -static void inline -ts_stats_set(ts_stats_t stats, int value, int thread_id) -{ - ((int64_t*)stats)[thread_id] = value; -} +void ts_stats_set(ts_stats_t stats, int value, int thread_id); /** * @brief Assign the maximum value to a statistics element @@ -96,16 +93,7 @@ ts_stats_set(ts_stats_t stats, int value, int thread_id) * @param value Value to set to * @param thread_id ID of thread */ -static void inline -ts_stats_set_max(ts_stats_t stats, int value, int thread_id) -{ - int64_t *p = (int64_t*) stats; - - if (value > p[thread_id]) - { - p[thread_id] = value; - } -} +void ts_stats_set_max(ts_stats_t stats, int value, int thread_id); /** * @brief Assign the minimum value to a statistics element @@ -116,15 +104,6 @@ ts_stats_set_max(ts_stats_t stats, int value, int thread_id) * @param value Value to set to * @param thread_id ID of thread */ -static void inline -ts_stats_set_min(ts_stats_t stats, int value, int thread_id) -{ - int64_t *p = (int64_t*) stats; - - if (value < p[thread_id]) - { - p[thread_id] = value; - } -} +void ts_stats_set_min(ts_stats_t stats, int value, int thread_id); MXS_END_DECLS diff --git a/include/maxscale/utils.h b/include/maxscale/utils.h index 70fc97ab9..c8685ef78 100644 --- a/include/maxscale/utils.h +++ b/include/maxscale/utils.h @@ -37,6 +37,12 @@ MXS_BEGIN_DECLS #define MXS_ARRAY_NELEMS(array) ((size_t)(sizeof(array)/sizeof(array[0]))) +/** Macro for safe pointer arithmetic on void pointers + * @param a The void pointer + * @param b The offset into @c a + */ +#define MXS_PTR(a, b) (((uint8_t*)(a)) + (b)) + bool utils_init(); /*< Call this first before using any other function */ void utils_end(); diff --git a/server/core/gateway.cc b/server/core/gateway.cc index bb7358961..ae7ef0bde 100644 --- a/server/core/gateway.cc +++ b/server/core/gateway.cc @@ -67,12 +67,12 @@ #include #include #include -#include #include #include #include #include "maxscale/service.h" +#include "maxscale/statistics.h" #define STRING_BUFFER_SIZE 1024 #define PIDFD_CLOSED -1 diff --git a/server/core/maxscale/statistics.h b/server/core/maxscale/statistics.h new file mode 100644 index 000000000..2e096a38a --- /dev/null +++ b/server/core/maxscale/statistics.h @@ -0,0 +1,37 @@ +#pragma once +/* + * Copyright (c) 2016 MariaDB Corporation Ab + * + * Use of this software is governed by the Business Source License included + * in the LICENSE.TXT file and at www.mariadb.com/bsl. + * + * Change Date: 2019-07-01 + * + * On the date above, in accordance with the Business Source License, use + * of this software will be governed by version 2 or later of the General + * Public License. + */ + +/** + * @file + * + * Internal code for the statistics system. + */ + +#include + +MXS_BEGIN_DECLS + +/** + * @brief Initialize statistics system + * + * This function should only be called once by the MaxScale core. + */ +void ts_stats_init(); + +/** + * @brief Terminate statistics system + */ +void ts_stats_end(); + +MXS_END_DECLS diff --git a/server/core/statistics.c b/server/core/statistics.c index 97f491518..27203e341 100644 --- a/server/core/statistics.c +++ b/server/core/statistics.c @@ -29,10 +29,32 @@ #include #include #include +#include static int thread_count = 0; +static size_t cache_linesize = 0; +static size_t stats_size = 0; static bool stats_initialized = false; +static size_t get_cache_line_size() +{ + size_t rval = 64; // Cache lines are 64 bytes for x86 + +#ifdef _SC_LEVEL1_DCACHE_LINESIZE + rval = sysconf(_SC_LEVEL1_DCACHE_LINESIZE); +#endif + + if (rval < sizeof(int64_t)) + { + MXS_WARNING("Cache line size reported to be %lu bytes when a 64-bit " + "integer is %lu bytes. Increasing statistics to the minimum " + "size of %lu bytes.", rval, sizeof(int64_t), sizeof(int64_t)); + rval = sizeof(int64_t); + } + + return rval; +} + /** * @brief Initialize the statistics gathering */ @@ -40,6 +62,8 @@ void ts_stats_init() { ss_dassert(!stats_initialized); thread_count = config_threadcount(); + cache_linesize = get_cache_line_size(); + stats_size = thread_count * cache_linesize; stats_initialized = true; } @@ -59,7 +83,7 @@ void ts_stats_end() ts_stats_t ts_stats_alloc() { ss_dassert(stats_initialized); - return MXS_CALLOC(thread_count, sizeof(int64_t)); + return MXS_CALLOC(thread_count, cache_linesize); } /** @@ -85,10 +109,12 @@ int64_t ts_stats_sum(ts_stats_t stats) { ss_dassert(stats_initialized); int64_t sum = 0; - for (int i = 0; i < thread_count; i++) + + for (size_t i = 0; i < stats_size; i += cache_linesize) { - sum += ((int64_t*)stats)[i]; + sum += *((int64_t*)MXS_PTR(stats, i)); } + return sum; } @@ -106,9 +132,9 @@ int64_t ts_stats_get(ts_stats_t stats, enum ts_stats_type type) ss_dassert(stats_initialized); int64_t best = type == TS_STATS_MAX ? LONG_MIN : (type == TS_STATS_MIX ? LONG_MAX : 0); - for (int i = 0; i < thread_count; i++) + for (size_t i = 0; i < stats_size; i += cache_linesize) { - int64_t value = ((int64_t*)stats)[i]; + int64_t value = *((int64_t*)MXS_PTR(stats, i)); switch (type) { @@ -135,3 +161,39 @@ int64_t ts_stats_get(ts_stats_t stats, enum ts_stats_type type) return type == TS_STATS_AVG ? best / thread_count : best; } + +void ts_stats_increment(ts_stats_t stats, int thread_id) +{ + ss_dassert(thread_id < thread_count); + int64_t *item = (int64_t*)MXS_PTR(stats, thread_id * cache_linesize); + *item += 1; +} + +void ts_stats_set(ts_stats_t stats, int value, int thread_id) +{ + ss_dassert(thread_id < thread_count); + int64_t *item = (int64_t*)MXS_PTR(stats, thread_id * cache_linesize); + *item = value; +} + +void ts_stats_set_max(ts_stats_t stats, int value, int thread_id) +{ + ss_dassert(thread_id < thread_count); + int64_t *item = (int64_t*)MXS_PTR(stats, thread_id * cache_linesize); + + if (value > *item) + { + *item = value; + } +} + +void ts_stats_set_min(ts_stats_t stats, int value, int thread_id) +{ + ss_dassert(thread_id < thread_count); + int64_t *item = (int64_t*)MXS_PTR(stats, thread_id * cache_linesize); + + if (value < *item) + { + *item = value; + } +} diff --git a/server/core/test/test_utils.h b/server/core/test/test_utils.h index 150cc7ecd..36a826f06 100644 --- a/server/core/test/test_utils.h +++ b/server/core/test/test_utils.h @@ -20,7 +20,7 @@ #include #include #include -#include +#include "../maxscale/statistics.h" void init_test_env(char *path) {