diff options
| -rw-r--r-- | CMakeLists.txt | 9 | ||||
| -rw-r--r-- | src/metrics/fs_cell.c | 16 | ||||
| -rw-r--r-- | src/metrics/fs_cell.h | 2 | ||||
| -rw-r--r-- | src/metrics/metric_counter.c | 6 | ||||
| -rw-r--r-- | test/CMakeLists.txt | 14 | ||||
| -rw-r--r-- | vendors/hdr/hdr_atomic.h | 146 | ||||
| -rw-r--r-- | vendors/hdr/hdr_encoding.c | 323 | ||||
| -rw-r--r-- | vendors/hdr/hdr_encoding.h | 79 | ||||
| -rw-r--r-- | vendors/hdr/hdr_endian.h | 116 | ||||
| -rw-r--r-- | vendors/hdr/hdr_histogram.c (renamed from vendors/hdr_histogram/hdr_histogram.c) | 524 | ||||
| -rw-r--r-- | vendors/hdr/hdr_histogram.h (renamed from vendors/hdr_histogram/hdr_histogram.h) | 113 | ||||
| -rw-r--r-- | vendors/hdr/hdr_histogram_log.c (renamed from vendors/hdr_histogram/hdr_histogram_log.c) | 0 | ||||
| -rw-r--r-- | vendors/hdr/hdr_histogram_log.h (renamed from vendors/hdr_histogram/hdr_histogram_log.h) | 0 | ||||
| -rw-r--r-- | vendors/hdr/hdr_malloc.h | 19 | ||||
| -rw-r--r-- | vendors/hdr/hdr_tests.h | 22 | ||||
| -rw-r--r-- | vendors/hdr/hdr_time.c | 97 | ||||
| -rw-r--r-- | vendors/hdr/hdr_time.h | 47 |
17 files changed, 1344 insertions, 189 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 6900f25..6326543 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -16,7 +16,7 @@ include(Version) set(CMAKE_POSITION_INDEPENDENT_CODE ON)
set(CMAKE_MACOSX_RPATH 0)
-set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g -fPIC -Wall -lm")
+set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g -fPIC -Wall -lm -lz")
set(CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS} -Wall)
if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
@@ -48,6 +48,8 @@ if (CMAKE_CXX_CPPCHECK) "--suppress=nullPointerRedundantCheck"
"--suppress=ctunullpointer"
"--suppress=shadowFunction"
+ "--suppress=shiftTooManyBitsSigned"
+ "--suppress=preprocessorErrorDirective"
)
set(CMAKE_C_CPPCHECK ${CMAKE_CXX_CPPCHECK})
else()
@@ -72,6 +74,7 @@ elseif(ASAN_OPTION MATCHES "THREAD") endif()
# end of for ASAN
+
include_directories(${PROJECT_SOURCE_DIR}/vendors)
include_directories(${PROJECT_SOURCE_DIR}/src)
include_directories(${PROJECT_SOURCE_DIR}/include/fieldstat)
@@ -86,7 +89,7 @@ file(GLOB SRC "src/export/*.c"
"src/utils/*.c"
"vendors/cjson/*.c"
- "vendors/hdr_histogram/*.c"
+ "vendors/hdr/*.c"
"vendors/minheap/*.c"
"vendors/mpack/*.c"
"vendors/xxhash/*.c"
@@ -98,6 +101,8 @@ add_subdirectory(test) enable_testing()
add_subdirectory(./ctest)
+
+
# Shared Library Output
add_library(${lib_name}_shared SHARED ${SRC})
set_target_properties(${lib_name}_shared PROPERTIES LINK_FLAGS
diff --git a/src/metrics/fs_cell.c b/src/metrics/fs_cell.c index 90a2475..5b0b70a 100644 --- a/src/metrics/fs_cell.c +++ b/src/metrics/fs_cell.c @@ -8,8 +8,8 @@ #include "fieldstat.h" #include "heavy_keeper.h" -#include "hdr_histogram/hdr_histogram.h" -#include "hdr_histogram/hdr_histogram_log.h" +#include "hdr/hdr_histogram.h" +#include "hdr/hdr_histogram_log.h" #include "st_hyperloglog.h" #include "mpack/mpack.h" @@ -405,9 +405,9 @@ struct cell *cell_deserialize_for_counter(const char *blob, size_t blob_size) struct cell *cell = (struct cell *)counter; cell_counter_scheme_init(cell); - mpack_node_t content_node; - mpack_tree_init_data(&content_node, mpack_node_data(content_blob), mpack_node_data_len(content_blob)); - mpack_node_t content_root = mpack_tree_root(&content_node); + mpack_tree_t content_tree; + mpack_tree_init_data(&content_tree, mpack_node_data(content_blob), mpack_node_data_len(content_blob)); + mpack_node_t content_root = mpack_tree_root(&content_tree); counter->value = mpack_node_i64(mpack_node_map_cstr(content_root, "value")); // TODO: gauge @@ -417,7 +417,7 @@ struct cell *cell_deserialize_for_counter(const char *blob, size_t blob_size) cell->add_tag(cell, tag_list, tag_num); mpack_tree_destroy(&tree); - mpack_tree_destroy(&content_node); + mpack_tree_destroy(&content_tree); free(tag_list); return (struct cell *)counter; @@ -434,7 +434,7 @@ struct cell *cell_create_for_counter(int K) } // TODO: name 应该是metric吧。说实话好想typedef一下 -void cell_add_for_counter(struct cell *pthis, unsigned value) +void cell_add_for_counter(struct cell *pthis, long long value) { struct cell_counter *counter = (struct cell_counter *)pthis; counter->value += value; @@ -701,7 +701,7 @@ struct cell *cell_create_for_histogram(long long lowest_trackable_value, long lo return base; } -int cell_add_for_hdr(struct cell *pthis, long long value) +int cell_add_for_histogram(struct cell *pthis, long long value) { struct metric_histogram *histogram = (struct metric_hdr *)pthis; bool ret = hdr_record_value(histogram->hdr, value); diff --git a/src/metrics/fs_cell.h b/src/metrics/fs_cell.h index d24f6ab..9c81e80 100644 --- a/src/metrics/fs_cell.h +++ b/src/metrics/fs_cell.h @@ -30,7 +30,7 @@ void cell_query_for_topk(const struct cell *pthis, char ***keys_out, long long * struct cell *cell_create_for_counter(); struct cell *cell_deserialize_for_counter(const char *blob, size_t blob_size); void cell_add_for_counter(struct cell *pthis, long long value); -long long cell_query_for_counter(const struct cell *pthis) +long long cell_query_for_counter(const struct cell *pthis); diff --git a/src/metrics/metric_counter.c b/src/metrics/metric_counter.c index d8da2c6..66d2d7a 100644 --- a/src/metrics/metric_counter.c +++ b/src/metrics/metric_counter.c @@ -8,11 +8,7 @@ // #include "metric_type_internal.h" -// struct metric_counter { -// struct cell base; -// long long value; -// // enum metric_counter_type type; -// }; + // /* // "counter": { diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index bf5e09e..6bb87c8 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -25,6 +25,20 @@ include_directories(${PROJECT_SOURCE_DIR}/include) add_executable(unit_tests ${SRC} gtest_topk.cpp)
target_link_libraries(unit_tests gtest-static)
+#zlib, first install zlib from https://zlib.net/
+SET (ZLIB_ROOT "/home/chenzizhan/zlib")
+SET (ZLIB_INCLUDE_DIR "/home/chenzizhan/zlib/include/")
+SET (ZLIB_LIBRARY "/home/chenzizhan/zlib/lib/libz.so.1.2.13")
+
+FIND_PACKAGE (ZLIB REQUIRED)
+MESSAGE (" zlib version major is " ${ZLIB_VERSION_MAJOR})
+MESSAGE (" zlib version minor is " ${ZLIB_VERSION_MINOR})
+MESSAGE (" zlib include is " ${ZLIB_INCLUDE_DIR})
+MESSAGE (" zlib libraries are " ${ZLIB_LIBRARIES})
+
+target_link_libraries(unit_tests ${ZLIB_LIBRARIES})
+
+
# target_link_libraries(unit_tests
# PRIVATE
# fieldstat4-shared
diff --git a/vendors/hdr/hdr_atomic.h b/vendors/hdr/hdr_atomic.h new file mode 100644 index 0000000..11b0cbd --- /dev/null +++ b/vendors/hdr/hdr_atomic.h @@ -0,0 +1,146 @@ +/** + * hdr_atomic.h + * Written by Philip Orwig and released to the public domain, + * as explained at http://creativecommons.org/publicdomain/zero/1.0/ + */ + +#ifndef HDR_ATOMIC_H__ +#define HDR_ATOMIC_H__ + + +#if defined(_MSC_VER) && !(defined(__clang__) && (defined(_M_ARM) || defined(_M_ARM64))) + +#include <stdint.h> +#include <intrin.h> +#include <stdbool.h> + +static void __inline * hdr_atomic_load_pointer(void** pointer) +{ + _ReadBarrier(); + return *pointer; +} + +static void hdr_atomic_store_pointer(void** pointer, void* value) +{ + _WriteBarrier(); + *pointer = value; +} + +static int64_t __inline hdr_atomic_load_64(int64_t* field) +{ + _ReadBarrier(); + return *field; +} + +static void __inline hdr_atomic_store_64(int64_t* field, int64_t value) +{ + _WriteBarrier(); + *field = value; +} + +static int64_t __inline hdr_atomic_exchange_64(volatile int64_t* field, int64_t value) +{ +#if defined(_WIN64) + return _InterlockedExchange64(field, value); +#else + int64_t comparand; + int64_t initial_value = *field; + do + { + comparand = initial_value; + initial_value = _InterlockedCompareExchange64(field, value, comparand); + } + while (comparand != initial_value); + + return initial_value; +#endif +} + +static int64_t __inline hdr_atomic_add_fetch_64(volatile int64_t* field, int64_t value) +{ +#if defined(_WIN64) + return _InterlockedExchangeAdd64(field, value) + value; +#else + int64_t comparand; + int64_t initial_value = *field; + do + { + comparand = initial_value; + initial_value = _InterlockedCompareExchange64(field, comparand + value, comparand); + } + while (comparand != initial_value); + + return initial_value + value; +#endif +} + +static bool __inline hdr_atomic_compare_exchange_64(volatile int64_t* field, int64_t* expected, int64_t desired) +{ + return *expected == _InterlockedCompareExchange64(field, desired, *expected); +} + +#elif defined(__ATOMIC_SEQ_CST) + +#define hdr_atomic_load_pointer(x) __atomic_load_n(x, __ATOMIC_SEQ_CST) +#define hdr_atomic_store_pointer(f,v) __atomic_store_n(f,v, __ATOMIC_SEQ_CST) +#define hdr_atomic_load_64(x) __atomic_load_n(x, __ATOMIC_SEQ_CST) +#define hdr_atomic_store_64(f,v) __atomic_store_n(f,v, __ATOMIC_SEQ_CST) +#define hdr_atomic_exchange_64(f,i) __atomic_exchange_n(f,i, __ATOMIC_SEQ_CST) +#define hdr_atomic_add_fetch_64(field, value) __atomic_add_fetch(field, value, __ATOMIC_SEQ_CST) +#define hdr_atomic_compare_exchange_64(field, expected, desired) __atomic_compare_exchange_n(field, expected, desired, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST) + +#elif defined(__x86_64__) + +#include <stdint.h> +#include <stdbool.h> + +static inline void* hdr_atomic_load_pointer(void** pointer) +{ + void* p = *pointer; + asm volatile ("" ::: "memory"); + return p; +} + +static inline void hdr_atomic_store_pointer(void** pointer, void* value) +{ + asm volatile ("lock; xchgq %0, %1" : "+q" (value), "+m" (*pointer)); +} + +static inline int64_t hdr_atomic_load_64(int64_t* field) +{ + int64_t i = *field; + asm volatile ("" ::: "memory"); + return i; +} + +static inline void hdr_atomic_store_64(int64_t* field, int64_t value) +{ + asm volatile ("lock; xchgq %0, %1" : "+q" (value), "+m" (*field)); +} + +static inline int64_t hdr_atomic_exchange_64(volatile int64_t* field, int64_t value) +{ + int64_t result = 0; + asm volatile ("lock; xchgq %1, %2" : "=r" (result), "+q" (value), "+m" (*field)); + return result; +} + +static inline int64_t hdr_atomic_add_fetch_64(volatile int64_t* field, int64_t value) +{ + return __sync_add_and_fetch(field, value); +} + +static inline bool hdr_atomic_compare_exchange_64(volatile int64_t* field, int64_t* expected, int64_t desired) +{ + int64_t original; + asm volatile( "lock; cmpxchgq %2, %1" : "=a"(original), "+m"(*field) : "q"(desired), "0"(*expected)); + return original == *expected; +} + +#else + +#error "Unable to determine atomic operations for your platform" + +#endif + +#endif /* HDR_ATOMIC_H__ */ diff --git a/vendors/hdr/hdr_encoding.c b/vendors/hdr/hdr_encoding.c new file mode 100644 index 0000000..7e04d9e --- /dev/null +++ b/vendors/hdr/hdr_encoding.c @@ -0,0 +1,323 @@ +/** + * hdr_encoding.c + * Written by Michael Barker and released to the public domain, + * as explained at http://creativecommons.org/publicdomain/zero/1.0/ + */ + +#include <errno.h> +#include <stddef.h> +#include <math.h> + +#include "hdr_encoding.h" +#include "hdr_tests.h" + +int zig_zag_encode_i64(uint8_t* buffer, int64_t signed_value) +{ + int bytesWritten; + int64_t value = signed_value; + +// cppcheck-suppress shiftTooManyBitsSigned + value = (value << 1) ^ (value >> 63); // cppcheck-suppress[shiftTooManyBitsSigned] + if (value >> 7 == 0) + { + buffer[0] = (uint8_t) value; + bytesWritten = 1; + } + else + { + buffer[0] = (uint8_t) ((value & 0x7F) | 0x80); + if (value >> 14 == 0) + { + buffer[1] = (uint8_t) (value >> 7); + bytesWritten = 2; + } + else + { + buffer[1] = (uint8_t) ((value >> 7 | 0x80)); + if (value >> 21 == 0) + { + buffer[2] = (uint8_t) (value >> 14); + bytesWritten = 3; + } + else + { + buffer[2] = (uint8_t) (value >> 14 | 0x80); + if (value >> 28 == 0) + { + buffer[3] = (uint8_t) (value >> 21); + bytesWritten = 4; + } + else + { + buffer[3] = (uint8_t) (value >> 21 | 0x80); + if (value >> 35 == 0) + { + buffer[4] = (uint8_t) (value >> 28); + bytesWritten = 5; + } + else + { + buffer[4] = (uint8_t) (value >> 28 | 0x80); + if (value >> 42 == 0) + { + buffer[5] = (uint8_t) (value >> 35); + bytesWritten = 6; + } + else + { + buffer[5] = (uint8_t) (value >> 35 | 0x80); + if (value >> 49 == 0) + { + buffer[6] = (uint8_t) (value >> 42); + bytesWritten = 7; + } + else + { + buffer[6] = (uint8_t) (value >> 42 | 0x80); + if (value >> 56 == 0) + { + buffer[7] = (uint8_t) (value >> 49); + bytesWritten = 8; + } + else + { + buffer[7] = (uint8_t) (value >> 49 | 0x80); + buffer[8] = (uint8_t) (value >> 56); + bytesWritten = 9; + } + } + } + } + } + } + } + } + + return bytesWritten; +} + +int zig_zag_decode_i64(const uint8_t* buffer, int64_t* signed_value) +{ + uint64_t v = buffer[0]; + uint64_t value = v & 0x7F; + int bytesRead = 1; + if ((v & 0x80) != 0) + { + bytesRead = 2; + v = buffer[1]; + value |= (v & 0x7F) << 7; + if ((v & 0x80) != 0) + { + bytesRead = 3; + v = buffer[2]; + value |= (v & 0x7F) << 14; + if ((v & 0x80) != 0) + { + bytesRead = 4; + v = buffer[3]; + value |= (v & 0x7F) << 21; + if ((v & 0x80) != 0) + { + bytesRead = 5; + v = buffer[4]; + value |= (v & 0x7F) << 28; + if ((v & 0x80) != 0) + { + bytesRead = 6; + v = buffer[5]; + value |= (v & 0x7F) << 35; + if ((v & 0x80) != 0) + { + bytesRead = 7; + v = buffer[6]; + value |= (v & 0x7F) << 42; + if ((v & 0x80) != 0) + { + bytesRead = 8; + v = buffer[7]; + value |= (v & 0x7F) << 49; + if ((v & 0x80) != 0) + { + bytesRead = 9; + v = buffer[8]; + value |= v << 56; + } + } + } + } + } + } + } + } + +#if defined(_MSC_VER) +#pragma warning(push) +#pragma warning(disable: 4146) /* C4146: unary minus operator applied to unsigned type, result still unsigned */ +#endif + value = (value >> 1) ^ (-(value & 1)); +#if defined(_MSC_VER) +#pragma warning(pop) +#endif + *signed_value = (int64_t) value; + + return bytesRead; +} + +static const char base64_table[] = + { + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', + 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', + 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', + 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/', '\0' + }; + +static char get_base_64(uint32_t _24_bit_value, int shift) +{ + uint32_t _6_bit_value = 0x3F & (_24_bit_value >> shift); + return base64_table[_6_bit_value]; +} + +static int from_base_64(int c) +{ + if ('A' <= c && c <= 'Z') + { + return c - 'A'; + } + else if ('a' <= c && c <= 'z') + { + return (c - 'a') + 26; + } + else if ('0' <= c && c <= '9') + { + return (c - '0') + 52; + } + else if ('+' == c) + { + return 62; + } + else if ('/' == c) + { + return 63; + } + else if ('=' == c) + { + return 0; + } + + return EINVAL; +} + +size_t hdr_base64_encoded_len(size_t decoded_size) +{ + return (size_t) (ceil(decoded_size / 3.0) * 4.0); +} + +size_t hdr_base64_decoded_len(size_t encoded_size) +{ + return (encoded_size / 4) * 3; +} + +static void hdr_base64_encode_block_pad(const uint8_t* input, char* output, size_t pad) +{ + uint32_t _24_bit_value = 0; + + switch (pad) + { + case 2: + _24_bit_value = (input[0] << 16) + (input[1] << 8); + + output[0] = get_base_64(_24_bit_value, 18); + output[1] = get_base_64(_24_bit_value, 12); + output[2] = get_base_64(_24_bit_value, 6); + output[3] = '='; + + break; + + case 1: + _24_bit_value = (input[0] << 16); + + output[0] = get_base_64(_24_bit_value, 18); + output[1] = get_base_64(_24_bit_value, 12); + output[2] = '='; + output[3] = '='; + + break; + + default: + /* No-op */ + break; + } +} + +/** + * Assumes that there is 3 input bytes and 4 output chars. + */ +void hdr_base64_encode_block(const uint8_t* input, char* output) +{ + uint32_t _24_bit_value = (input[0] << 16) + (input[1] << 8) + (input[2]); + + output[0] = get_base_64(_24_bit_value, 18); + output[1] = get_base_64(_24_bit_value, 12); + output[2] = get_base_64(_24_bit_value, 6); + output[3] = get_base_64(_24_bit_value, 0); +} + +int hdr_base64_encode( + const uint8_t* input, size_t input_len, char* output, size_t output_len) +{ + size_t i, j, remaining; + + if (hdr_base64_encoded_len(input_len) != output_len) + { + return EINVAL; + } + + for (i = 0, j = 0; input_len - i >= 3 && j < output_len; i += 3, j += 4) + { + hdr_base64_encode_block(&input[i], &output[j]); + } + + remaining = input_len - i; + + hdr_base64_encode_block_pad(&input[i], &output[j], remaining); + + return 0; +} + +/** + * Assumes that there is 4 input chars available and 3 output chars. + */ +void hdr_base64_decode_block(const char* input, uint8_t* output) +{ + uint32_t _24_bit_value = 0; + + _24_bit_value |= from_base_64(input[0]) << 18; + _24_bit_value |= from_base_64(input[1]) << 12; + _24_bit_value |= from_base_64(input[2]) << 6; + _24_bit_value |= from_base_64(input[3]); + + output[0] = (uint8_t) ((_24_bit_value >> 16) & 0xFF); + output[1] = (uint8_t) ((_24_bit_value >> 8) & 0xFF); + output[2] = (uint8_t) ((_24_bit_value) & 0xFF); +} + +int hdr_base64_decode( + const char* input, size_t input_len, uint8_t* output, size_t output_len) +{ + size_t i, j; + + if (input_len < 4 || + (input_len & 3u) != 0 || + (input_len / 4) * 3 != output_len) + { + return -EINVAL; + } + + for (i = 0, j = 0; i < input_len; i += 4, j += 3) + { + hdr_base64_decode_block(&input[i], &output[j]); + } + + return 0; +} diff --git a/vendors/hdr/hdr_encoding.h b/vendors/hdr/hdr_encoding.h new file mode 100644 index 0000000..95f1db6 --- /dev/null +++ b/vendors/hdr/hdr_encoding.h @@ -0,0 +1,79 @@ +/** + * hdr_encoding.h + * Written by Michael Barker and released to the public domain, + * as explained at http://creativecommons.org/publicdomain/zero/1.0/ + */ + +#ifndef HDR_ENCODING_H +#define HDR_ENCODING_H + +#include <stdint.h> + +#define MAX_BYTES_LEB128 9 + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Writes a int64_t value to the given buffer in LEB128 ZigZag encoded format + * + * @param buffer the buffer to write to + * @param signed_value the value to write to the buffer + * @return the number of bytes written to the buffer + */ +int zig_zag_encode_i64(uint8_t* buffer, int64_t signed_value); + +/** + * Read an LEB128 ZigZag encoded long value from the given buffer + * + * @param buffer the buffer to read from + * @param retVal out value to capture the read value + * @return the number of bytes read from the buffer + */ +int zig_zag_decode_i64(const uint8_t* buffer, int64_t* signed_value); + +/** + * Gets the length in bytes of base64 data, given the input size. + * + * @param decoded_size the size of the unencoded values. + * @return the encoded size + */ +size_t hdr_base64_encoded_len(size_t decoded_size); + +/** + * Encode into base64. + * + * @param input the data to encode + * @param input_len the length of the data to encode + * @param output the buffer to write the output to + * @param output_len the number of bytes to write to the output + */ +int hdr_base64_encode( + const uint8_t* input, size_t input_len, char* output, size_t output_len); + +/** + * Gets the length in bytes of decoded base64 data, given the size of the base64 encoded + * data. + * + * @param encoded_size the size of the encoded value. + * @return the decoded size + */ +size_t hdr_base64_decoded_len(size_t encoded_size); + +/** + * Decode from base64. + * + * @param input the base64 encoded data + * @param input_len the size in bytes of the endcoded data + * @param output the buffer to write the decoded data to + * @param output_len the number of bytes to write to the output data + */ +int hdr_base64_decode( + const char* input, size_t input_len, uint8_t* output, size_t output_len); + +#ifdef __cplusplus +} +#endif + +#endif /* HDR_HISTOGRAM_HDR_ENCODING_H */ diff --git a/vendors/hdr/hdr_endian.h b/vendors/hdr/hdr_endian.h new file mode 100644 index 0000000..839fdb1 --- /dev/null +++ b/vendors/hdr/hdr_endian.h @@ -0,0 +1,116 @@ +/** +* hdr_time.h +* Released to the public domain, as explained at http://creativecommons.org/publicdomain/zero/1.0/ +*/ + +#ifndef HDR_ENDIAN_H__ +#define HDR_ENDIAN_H__ + +#if (defined(_WIN16) || defined(_WIN32) || defined(_WIN64)) && !defined(__WINDOWS__) + +# define __WINDOWS__ + +#endif + +#if defined(__linux__) || defined(__CYGWIN__) + +# include <endian.h> + +#elif defined(__APPLE__) + +# include <libkern/OSByteOrder.h> + +# define htobe16(x) OSSwapHostToBigInt16(x) +# define htole16(x) OSSwapHostToLittleInt16(x) +# define be16toh(x) OSSwapBigToHostInt16(x) +# define le16toh(x) OSSwapLittleToHostInt16(x) + +# define htobe32(x) OSSwapHostToBigInt32(x) +# define htole32(x) OSSwapHostToLittleInt32(x) +# define be32toh(x) OSSwapBigToHostInt32(x) +# define le32toh(x) OSSwapLittleToHostInt32(x) + +# define htobe64(x) OSSwapHostToBigInt64(x) +# define htole64(x) OSSwapHostToLittleInt64(x) +# define be64toh(x) OSSwapBigToHostInt64(x) +# define le64toh(x) OSSwapLittleToHostInt64(x) + +# define __BYTE_ORDER BYTE_ORDER +# define __BIG_ENDIAN BIG_ENDIAN +# define __LITTLE_ENDIAN LITTLE_ENDIAN +# define __PDP_ENDIAN PDP_ENDIAN + +#elif defined(__OpenBSD__) + +# include <sys/endian.h> + +#elif defined(__NetBSD__) || defined(__FreeBSD__) || defined(__DragonFly__) + +# include <sys/endian.h> + +# define be16toh(x) betoh16(x) +# define le16toh(x) letoh16(x) + +# define be32toh(x) betoh32(x) +# define le32toh(x) letoh32(x) + +# define be64toh(x) betoh64(x) +# define le64toh(x) letoh64(x) + +#elif defined(__WINDOWS__) + +# include <winsock2.h> + +# if BYTE_ORDER == LITTLE_ENDIAN + +# define htobe16(x) htons(x) +# define htole16(x) (x) +# define be16toh(x) ntohs(x) +# define le16toh(x) (x) + +# define htobe32(x) htonl(x) +# define htole32(x) (x) +# define be32toh(x) ntohl(x) +# define le32toh(x) (x) + +# define htobe64(x) htonll(x) +# define htole64(x) (x) +# define be64toh(x) ntohll(x) +# define le64toh(x) (x) + +# elif BYTE_ORDER == BIG_ENDIAN + + /* that would be xbox 360 */ +# define htobe16(x) (x) +# define htole16(x) __builtin_bswap16(x) +# define be16toh(x) (x) +# define le16toh(x) __builtin_bswap16(x) + +# define htobe32(x) (x) +# define htole32(x) __builtin_bswap32(x) +# define be32toh(x) (x) +# define le32toh(x) __builtin_bswap32(x) + +# define htobe64(x) (x) +# define htole64(x) __builtin_bswap64(x) +# define be64toh(x) (x) +# define le64toh(x) __builtin_bswap64(x) + +# else + +# error byte order not supported + +# endif + +# define __BYTE_ORDER BYTE_ORDER +# define __BIG_ENDIAN BIG_ENDIAN +# define __LITTLE_ENDIAN LITTLE_ENDIAN +# define __PDP_ENDIAN PDP_ENDIAN + +#else + +# error platform not supported + +#endif + +#endif diff --git a/vendors/hdr_histogram/hdr_histogram.c b/vendors/hdr/hdr_histogram.c index e1caaf2..7a4c4fd 100644 --- a/vendors/hdr_histogram/hdr_histogram.c +++ b/vendors/hdr/hdr_histogram.c @@ -7,32 +7,40 @@ #include <stdlib.h> #include <stdbool.h> #include <math.h> -#include <assert.h> #include <stdio.h> #include <string.h> #include <stdint.h> #include <errno.h> #include <inttypes.h> -#include "hdr_histogram.h" +#include <hdr/hdr_histogram.h> +#include "hdr_tests.h" +#include "hdr_atomic.h" -// ###### ####### ## ## ## ## ######## ###### -// ## ## ## ## ## ## ### ## ## ## ## -// ## ## ## ## ## #### ## ## ## -// ## ## ## ## ## ## ## ## ## ###### -// ## ## ## ## ## ## #### ## ## -// ## ## ## ## ## ## ## ### ## ## ## -// ###### ####### ####### ## ## ## ###### +#ifndef HDR_MALLOC_INCLUDE +#define HDR_MALLOC_INCLUDE "hdr_malloc.h" +#endif + +#include HDR_MALLOC_INCLUDE + +/* ###### ####### ## ## ## ## ######## ###### */ +/* ## ## ## ## ## ## ### ## ## ## ## */ +/* ## ## ## ## ## #### ## ## ## */ +/* ## ## ## ## ## ## ## ## ## ###### */ +/* ## ## ## ## ## ## #### ## ## */ +/* ## ## ## ## ## ## ## ### ## ## ## */ +/* ###### ####### ####### ## ## ## ###### */ static int32_t normalize_index(const struct hdr_histogram* h, int32_t index) { + int32_t normalized_index; + int32_t adjustment = 0; if (h->normalizing_index_offset == 0) { return index; } - int32_t normalized_index = index - h->normalizing_index_offset; - int32_t adjustment = 0; + normalized_index = index - h->normalizing_index_offset; if (normalized_index < 0) { @@ -64,19 +72,56 @@ static void counts_inc_normalised( h->total_count += value; } +static void counts_inc_normalised_atomic( + struct hdr_histogram* h, int32_t index, int64_t value) +{ + int32_t normalised_index = normalize_index(h, index); + + hdr_atomic_add_fetch_64(&h->counts[normalised_index], value); + hdr_atomic_add_fetch_64(&h->total_count, value); +} + static void update_min_max(struct hdr_histogram* h, int64_t value) { h->min_value = (value < h->min_value && value != 0) ? value : h->min_value; h->max_value = (value > h->max_value) ? value : h->max_value; } -// ## ## ######## #### ## #### ######## ## ## -// ## ## ## ## ## ## ## ## ## -// ## ## ## ## ## ## ## #### -// ## ## ## ## ## ## ## ## -// ## ## ## ## ## ## ## ## -// ## ## ## ## ## ## ## ## -// ####### ## #### ######## #### ## ## +static void update_min_max_atomic(struct hdr_histogram* h, int64_t value) +{ + int64_t current_min_value; + int64_t current_max_value; + do + { + current_min_value = hdr_atomic_load_64(&h->min_value); + + if (0 == value || current_min_value <= value) + { + break; + } + } + while (!hdr_atomic_compare_exchange_64(&h->min_value, ¤t_min_value, value)); + + do + { + current_max_value = hdr_atomic_load_64(&h->max_value); + + if (value <= current_max_value) + { + break; + } + } + while (!hdr_atomic_compare_exchange_64(&h->max_value, ¤t_max_value, value)); +} + + +/* ## ## ######## #### ## #### ######## ## ## */ +/* ## ## ## ## ## ## ## ## ## */ +/* ## ## ## ## ## ## ## #### */ +/* ## ## ## ## ## ## ## ## */ +/* ## ## ## ## ## ## ## ## */ +/* ## ## ## ## ## ## ## ## */ +/* ####### ## #### ######## #### ## ## */ static int64_t power(int64_t base, int64_t exp) { @@ -88,19 +133,41 @@ static int64_t power(int64_t base, int64_t exp) return result; } -#if defined(_MSC_VER) -#pragma intrinsic(_BitScanReverse64) +#if defined(_MSC_VER) && !(defined(__clang__) && (defined(_M_ARM) || defined(_M_ARM64))) +# if defined(_WIN64) +# pragma intrinsic(_BitScanReverse64) +# else +# pragma intrinsic(_BitScanReverse) +# endif #endif -static int32_t get_bucket_index(const struct hdr_histogram* h, int64_t value) +static int32_t count_leading_zeros_64(int64_t value) { -#if defined(_MSC_VER) +#if defined(_MSC_VER) && !(defined(__clang__) && (defined(_M_ARM) || defined(_M_ARM64))) uint32_t leading_zero = 0; - _BitScanReverse64(&leading_zero, value | h->sub_bucket_mask); - int32_t pow2ceiling = 64 - (63 - leading_zero); // smallest power of 2 containing value +#if defined(_WIN64) + _BitScanReverse64(&leading_zero, value); #else - int32_t pow2ceiling = 64 - __builtin_clzll(value | h->sub_bucket_mask); // smallest power of 2 containing value + uint32_t high = value >> 32; + if (_BitScanReverse(&leading_zero, high)) + { + leading_zero += 32; + } + else + { + uint32_t low = value & 0x00000000FFFFFFFF; + _BitScanReverse(&leading_zero, low); + } #endif + return 63 - leading_zero; /* smallest power of 2 containing value */ +#else + return __builtin_clzll(value); /* smallest power of 2 containing value */ +#endif +} + +static int32_t get_bucket_index(const struct hdr_histogram* h, int64_t value) +{ + int32_t pow2ceiling = 64 - count_leading_zeros_64(value | h->sub_bucket_mask); /* smallest power of 2 containing value */ return pow2ceiling - h->unit_magnitude - (h->sub_bucket_half_count_magnitude + 1); } @@ -111,12 +178,12 @@ static int32_t get_sub_bucket_index(int64_t value, int32_t bucket_index, int32_t static int32_t counts_index(const struct hdr_histogram* h, int32_t bucket_index, int32_t sub_bucket_index) { - // Calculate the index for the first entry in the bucket: - // (The following is the equivalent of ((bucket_index + 1) * subBucketHalfCount) ): + /* Calculate the index for the first entry in the bucket: */ + /* (The following is the equivalent of ((bucket_index + 1) * subBucketHalfCount) ): */ int32_t bucket_base_index = (bucket_index + 1) << h->sub_bucket_half_count_magnitude; - // Calculate the offset in the bucket: + /* Calculate the offset in the bucket: */ int32_t offset_in_bucket = sub_bucket_index - h->sub_bucket_half_count; - // The following is the equivalent of ((sub_bucket_index - subBucketHalfCount) + bucketBaseIndex; + /* The following is the equivalent of ((sub_bucket_index - subBucketHalfCount) + bucketBaseIndex; */ return bucket_base_index + offset_in_bucket; } @@ -155,6 +222,15 @@ int64_t hdr_size_of_equivalent_value_range(const struct hdr_histogram* h, int64_ return INT64_C(1) << (h->unit_magnitude + adjusted_bucket); } +static int64_t size_of_equivalent_value_range_given_bucket_indices( + const struct hdr_histogram *h, + int32_t bucket_index, + int32_t sub_bucket_index) +{ + const int32_t adjusted_bucket = (sub_bucket_index >= h->sub_bucket_count) ? (bucket_index + 1) : bucket_index; + return INT64_C(1) << (h->unit_magnitude + adjusted_bucket); +} + static int64_t lowest_equivalent_value(const struct hdr_histogram* h, int64_t value) { int32_t bucket_index = get_bucket_index(h, value); @@ -162,6 +238,14 @@ static int64_t lowest_equivalent_value(const struct hdr_histogram* h, int64_t va return value_from_index(bucket_index, sub_bucket_index, h->unit_magnitude); } +static int64_t lowest_equivalent_value_given_bucket_indices( + const struct hdr_histogram *h, + int32_t bucket_index, + int32_t sub_bucket_index) +{ + return value_from_index(bucket_index, sub_bucket_index, h->unit_magnitude); +} + int64_t hdr_next_non_equivalent_value(const struct hdr_histogram *h, int64_t value) { return lowest_equivalent_value(h, value) + hdr_size_of_equivalent_value_range(h, value); @@ -248,40 +332,45 @@ static int32_t buckets_needed_to_cover_value(int64_t value, int32_t sub_bucket_c return buckets_needed; } -// ## ## ######## ## ## ####### ######## ## ## -// ### ### ## ### ### ## ## ## ## ## ## -// #### #### ## #### #### ## ## ## ## #### -// ## ### ## ###### ## ### ## ## ## ######## ## -// ## ## ## ## ## ## ## ## ## ## -// ## ## ## ## ## ## ## ## ## ## -// ## ## ######## ## ## ####### ## ## ## +/* ## ## ######## ## ## ####### ######## ## ## */ +/* ### ### ## ### ### ## ## ## ## ## ## */ +/* #### #### ## #### #### ## ## ## ## #### */ +/* ## ### ## ###### ## ### ## ## ## ######## ## */ +/* ## ## ## ## ## ## ## ## ## ## */ +/* ## ## ## ## ## ## ## ## ## ## */ +/* ## ## ######## ## ## ####### ## ## ## */ int hdr_calculate_bucket_config( - int64_t lowest_trackable_value, + int64_t lowest_discernible_value, int64_t highest_trackable_value, int significant_figures, struct hdr_histogram_bucket_config* cfg) { - if (lowest_trackable_value < 1 || - significant_figures < 1 || 5 < significant_figures) - { - return EINVAL; - } - else if (lowest_trackable_value * 2 > highest_trackable_value) + int32_t sub_bucket_count_magnitude; + int64_t largest_value_with_single_unit_resolution; + + if (lowest_discernible_value < 1 || + significant_figures < 1 || 5 < significant_figures || + lowest_discernible_value * 2 > highest_trackable_value) { return EINVAL; } - cfg->lowest_trackable_value = lowest_trackable_value; + cfg->lowest_discernible_value = lowest_discernible_value; cfg->significant_figures = significant_figures; cfg->highest_trackable_value = highest_trackable_value; - int64_t largest_value_with_single_unit_resolution = 2 * power(10, significant_figures); - int32_t sub_bucket_count_magnitude = (int32_t) ceil(log((double)largest_value_with_single_unit_resolution) / log(2)); + largest_value_with_single_unit_resolution = 2 * power(10, significant_figures); + sub_bucket_count_magnitude = (int32_t) ceil(log((double)largest_value_with_single_unit_resolution) / log(2)); cfg->sub_bucket_half_count_magnitude = ((sub_bucket_count_magnitude > 1) ? sub_bucket_count_magnitude : 1) - 1; - cfg->unit_magnitude = (int32_t) floor(log((double)lowest_trackable_value) / log(2)); + double unit_magnitude = log((double)lowest_discernible_value) / log(2); + if (INT32_MAX < unit_magnitude) + { + return EINVAL; + } + cfg->unit_magnitude = (int32_t) unit_magnitude; cfg->sub_bucket_count = (int32_t) pow(2, (cfg->sub_bucket_half_count_magnitude + 1)); cfg->sub_bucket_half_count = cfg->sub_bucket_count / 2; cfg->sub_bucket_mask = ((int64_t) cfg->sub_bucket_count - 1) << cfg->unit_magnitude; @@ -299,7 +388,7 @@ int hdr_calculate_bucket_config( void hdr_init_preallocated(struct hdr_histogram* h, struct hdr_histogram_bucket_config* cfg) { - h->lowest_trackable_value = cfg->lowest_trackable_value; + h->lowest_discernible_value = cfg->lowest_discernible_value; h->highest_trackable_value = cfg->highest_trackable_value; h->unit_magnitude = (int32_t)cfg->unit_magnitude; h->significant_figures = (int32_t)cfg->significant_figures; @@ -317,24 +406,31 @@ void hdr_init_preallocated(struct hdr_histogram* h, struct hdr_histogram_bucket_ } int hdr_init( - int64_t lowest_trackable_value, + int64_t lowest_discernible_value, int64_t highest_trackable_value, int significant_figures, struct hdr_histogram** result) { + int64_t* counts; struct hdr_histogram_bucket_config cfg; + struct hdr_histogram* histogram; - int r = hdr_calculate_bucket_config(lowest_trackable_value, highest_trackable_value, significant_figures, &cfg); + int r = hdr_calculate_bucket_config(lowest_discernible_value, highest_trackable_value, significant_figures, &cfg); if (r) { return r; } - int64_t* counts = calloc((size_t) cfg.counts_len, sizeof(int64_t)); - struct hdr_histogram* histogram = calloc(1, sizeof(struct hdr_histogram)); + counts = (int64_t*) hdr_calloc((size_t) cfg.counts_len, sizeof(int64_t)); + if (!counts) + { + return ENOMEM; + } - if (!counts || !histogram) + histogram = (struct hdr_histogram*) hdr_calloc(1, sizeof(struct hdr_histogram)); + if (!histogram) { + hdr_free(counts); return ENOMEM; } @@ -348,8 +444,10 @@ int hdr_init( void hdr_close(struct hdr_histogram* h) { - free(h->counts); - free(h); + if (h) { + hdr_free(h->counts); + hdr_free(h); + } } int hdr_alloc(int64_t highest_trackable_value, int significant_figures, struct hdr_histogram** result) @@ -357,7 +455,7 @@ int hdr_alloc(int64_t highest_trackable_value, int significant_figures, struct h return hdr_init(1, highest_trackable_value, significant_figures, result); } -// reset a histogram to zero. +/* reset a histogram to zero. */ void hdr_reset(struct hdr_histogram *h) { h->total_count=0; @@ -371,13 +469,13 @@ size_t hdr_get_memory_size(struct hdr_histogram *h) return sizeof(struct hdr_histogram) + h->counts_len * sizeof(int64_t); } -// ## ## ######## ######## ### ######## ######## ###### -// ## ## ## ## ## ## ## ## ## ## ## ## -// ## ## ## ## ## ## ## ## ## ## ## -// ## ## ######## ## ## ## ## ## ###### ###### -// ## ## ## ## ## ######### ## ## ## -// ## ## ## ## ## ## ## ## ## ## ## -// ####### ## ######## ## ## ## ######## ###### +/* ## ## ######## ######## ### ######## ######## ###### */ +/* ## ## ## ## ## ## ## ## ## ## ## ## */ +/* ## ## ## ## ## ## ## ## ## ## ## */ +/* ## ## ######## ## ## ## ## ## ###### ###### */ +/* ## ## ## ## ## ######### ## ## ## */ +/* ## ## ## ## ## ## ## ## ## ## ## */ +/* ####### ## ######## ## ## ## ######## ###### */ bool hdr_record_value(struct hdr_histogram* h, int64_t value) @@ -385,14 +483,21 @@ bool hdr_record_value(struct hdr_histogram* h, int64_t value) return hdr_record_values(h, value, 1); } +bool hdr_record_value_atomic(struct hdr_histogram* h, int64_t value) +{ + return hdr_record_values_atomic(h, value, 1); +} + bool hdr_record_values(struct hdr_histogram* h, int64_t value, int64_t count) { + int32_t counts_index; + if (value < 0) { return false; } - int32_t counts_index = counts_index_for(h, value); + counts_index = counts_index_for(h, value); if (counts_index < 0 || h->counts_len <= counts_index) { @@ -405,14 +510,42 @@ bool hdr_record_values(struct hdr_histogram* h, int64_t value, int64_t count) return true; } +bool hdr_record_values_atomic(struct hdr_histogram* h, int64_t value, int64_t count) +{ + int32_t counts_index; + + if (value < 0) + { + return false; + } + + counts_index = counts_index_for(h, value); + + if (counts_index < 0 || h->counts_len <= counts_index) + { + return false; + } + + counts_inc_normalised_atomic(h, counts_index, count); + update_min_max_atomic(h, value); + + return true; +} + bool hdr_record_corrected_value(struct hdr_histogram* h, int64_t value, int64_t expected_interval) { return hdr_record_corrected_values(h, value, 1, expected_interval); } +bool hdr_record_corrected_value_atomic(struct hdr_histogram* h, int64_t value, int64_t expected_interval) +{ + return hdr_record_corrected_values_atomic(h, value, 1, expected_interval); +} bool hdr_record_corrected_values(struct hdr_histogram* h, int64_t value, int64_t count, int64_t expected_interval) { + int64_t missing_value; + if (!hdr_record_values(h, value, count)) { return false; @@ -423,7 +556,7 @@ bool hdr_record_corrected_values(struct hdr_histogram* h, int64_t value, int64_t return true; } - int64_t missing_value = value - expected_interval; + missing_value = value - expected_interval; for (; missing_value >= expected_interval; missing_value -= expected_interval) { if (!hdr_record_values(h, missing_value, count)) @@ -435,11 +568,37 @@ bool hdr_record_corrected_values(struct hdr_histogram* h, int64_t value, int64_t return true; } +bool hdr_record_corrected_values_atomic(struct hdr_histogram* h, int64_t value, int64_t count, int64_t expected_interval) +{ + int64_t missing_value; + + if (!hdr_record_values_atomic(h, value, count)) + { + return false; + } + + if (expected_interval <= 0 || value <= expected_interval) + { + return true; + } + + missing_value = value - expected_interval; + for (; missing_value >= expected_interval; missing_value -= expected_interval) + { + if (!hdr_record_values_atomic(h, missing_value, count)) + { + return false; + } + } + + return true; +} + int64_t hdr_add(struct hdr_histogram* h, const struct hdr_histogram* from) { struct hdr_iter iter; - hdr_iter_recorded_init(&iter, from); int64_t dropped = 0; + hdr_iter_recorded_init(&iter, from); while (hdr_iter_next(&iter)) { @@ -459,8 +618,8 @@ int64_t hdr_add_while_correcting_for_coordinated_omission( struct hdr_histogram* h, struct hdr_histogram* from, int64_t expected_interval) { struct hdr_iter iter; - hdr_iter_recorded_init(&iter, from); int64_t dropped = 0; + hdr_iter_recorded_init(&iter, from); while (hdr_iter_next(&iter)) { @@ -478,13 +637,13 @@ int64_t hdr_add_while_correcting_for_coordinated_omission( -// ## ## ### ## ## ## ######## ###### -// ## ## ## ## ## ## ## ## ## ## -// ## ## ## ## ## ## ## ## ## -// ## ## ## ## ## ## ## ###### ###### -// ## ## ######### ## ## ## ## ## -// ## ## ## ## ## ## ## ## ## ## -// ### ## ## ######## ####### ######## ###### +/* ## ## ### ## ## ## ######## ###### */ +/* ## ## ## ## ## ## ## ## ## ## */ +/* ## ## ## ## ## ## ## ## ## */ +/* ## ## ## ## ## ## ## ###### ###### */ +/* ## ## ######### ## ## ## ## ## */ +/* ## ## ## ## ## ## ## ## ## ## */ +/* ### ## ## ######## ####### ######## ###### */ int64_t hdr_max(const struct hdr_histogram* h) @@ -507,47 +666,89 @@ int64_t hdr_min(const struct hdr_histogram* h) return non_zero_min(h); } -int64_t hdr_value_at_percentile(const struct hdr_histogram* h, double percentile) +static int64_t get_value_from_idx_up_to_count(const struct hdr_histogram* h, int64_t count_at_percentile) { - struct hdr_iter iter; - hdr_iter_init(&iter, h); + int64_t count_to_idx = 0; + count_at_percentile = 0 < count_at_percentile ? count_at_percentile : 1; + for (int32_t idx = 0; idx < h->counts_len; idx++) + { + count_to_idx += h->counts[idx]; + if (count_to_idx >= count_at_percentile) + { + return hdr_value_at_index(h, idx); + } + } + + return 0; +} + + +int64_t hdr_value_at_percentile(const struct hdr_histogram* h, double percentile) +{ double requested_percentile = percentile < 100.0 ? percentile : 100.0; int64_t count_at_percentile = (int64_t) (((requested_percentile / 100) * h->total_count) + 0.5); - count_at_percentile = count_at_percentile > 1 ? count_at_percentile : 1; - int64_t total = 0; + int64_t value_from_idx = get_value_from_idx_up_to_count(h, count_at_percentile); + if (percentile == 0.0) + { + return lowest_equivalent_value(h, value_from_idx); + } + return highest_equivalent_value(h, value_from_idx); +} - while (hdr_iter_next(&iter)) +int hdr_value_at_percentiles(const struct hdr_histogram *h, const double *percentiles, int64_t *values, size_t length) +{ + if (NULL == percentiles || NULL == values) { - total += iter.count; + return EINVAL; + } - if (total >= count_at_percentile) + struct hdr_iter iter; + const int64_t total_count = h->total_count; + // to avoid allocations we use the values array for intermediate computation + // i.e. to store the expected cumulative count at each percentile + for (size_t i = 0; i < length; i++) + { + const double requested_percentile = percentiles[i] < 100.0 ? percentiles[i] : 100.0; + const int64_t count_at_percentile = + (int64_t) (((requested_percentile / 100) * total_count) + 0.5); + values[i] = count_at_percentile > 1 ? count_at_percentile : 1; + } + + hdr_iter_init(&iter, h); + int64_t total = 0; + size_t at_pos = 0; + while (hdr_iter_next(&iter) && at_pos < length) + { + total += iter.count; + while (at_pos < length && total >= values[at_pos]) { - int64_t value_from_index = iter.value; - return highest_equivalent_value(h, value_from_index); + values[at_pos] = highest_equivalent_value(h, iter.value); + at_pos++; } } - return 0; } double hdr_mean(const struct hdr_histogram* h) { struct hdr_iter iter; - int64_t total = 0; + int64_t total = 0, count = 0; + int64_t total_count = h->total_count; hdr_iter_init(&iter, h); - while (hdr_iter_next(&iter)) + while (hdr_iter_next(&iter) && count < total_count) { if (0 != iter.count) { + count += iter.count; total += iter.count * hdr_median_equivalent_value(h, iter.value); } } - return (total * 1.0) / h->total_count; + return (total * 1.0) / total_count; } double hdr_stddev(const struct hdr_histogram* h) @@ -591,13 +792,13 @@ int64_t hdr_count_at_index(const struct hdr_histogram* h, int32_t index) } -// #### ######## ######## ######## ### ######## ####### ######## ###### -// ## ## ## ## ## ## ## ## ## ## ## ## ## ## -// ## ## ## ## ## ## ## ## ## ## ## ## ## -// ## ## ###### ######## ## ## ## ## ## ######## ###### -// ## ## ## ## ## ######### ## ## ## ## ## ## -// ## ## ## ## ## ## ## ## ## ## ## ## ## ## -// #### ## ######## ## ## ## ## ## ####### ## ## ###### +/* #### ######## ######## ######## ### ######## ####### ######## ###### */ +/* ## ## ## ## ## ## ## ## ## ## ## ## ## ## */ +/* ## ## ## ## ## ## ## ## ## ## ## ## ## */ +/* ## ## ###### ######## ## ## ## ## ## ######## ###### */ +/* ## ## ## ## ## ######### ## ## ## ## ## ## */ +/* ## ## ## ## ## ## ## ## ## ## ## ## ## ## */ +/* #### ## ######## ## ## ## ## ## ####### ## ## ###### */ static bool has_buckets(struct hdr_iter* iter) @@ -621,11 +822,16 @@ static bool move_next(struct hdr_iter* iter) iter->count = counts_get_normalised(iter->h, iter->counts_index); iter->cumulative_count += iter->count; - - iter->value = hdr_value_at_index(iter->h, iter->counts_index); - iter->highest_equivalent_value = highest_equivalent_value(iter->h, iter->value); - iter->lowest_equivalent_value = lowest_equivalent_value(iter->h, iter->value); - iter->median_equivalent_value = hdr_median_equivalent_value(iter->h, iter->value); + const int64_t value = hdr_value_at_index(iter->h, iter->counts_index); + const int32_t bucket_index = get_bucket_index(iter->h, value); + const int32_t sub_bucket_index = get_sub_bucket_index(value, bucket_index, iter->h->unit_magnitude); + const int64_t leq = lowest_equivalent_value_given_bucket_indices(iter->h, bucket_index, sub_bucket_index); + const int64_t size_of_equivalent_value_range = size_of_equivalent_value_range_given_bucket_indices( + iter->h, bucket_index, sub_bucket_index); + iter->lowest_equivalent_value = leq; + iter->value = value; + iter->highest_equivalent_value = leq + size_of_equivalent_value_range - 1; + iter->median_equivalent_value = leq + (size_of_equivalent_value_range >> 1); return true; } @@ -646,7 +852,7 @@ static bool next_value_greater_than_reporting_level_upper_bound( return peek_next_value_from_index(iter) > reporting_level_upper_bound; } -static bool _basic_iter_next(struct hdr_iter *iter) +static bool basic_iter_next(struct hdr_iter *iter) { if (!has_next(iter) || iter->counts_index >= iter->h->counts_len) { @@ -658,19 +864,19 @@ static bool _basic_iter_next(struct hdr_iter *iter) return true; } -static void _update_iterated_values(struct hdr_iter* iter, int64_t new_value_iterated_to) +static void update_iterated_values(struct hdr_iter* iter, int64_t new_value_iterated_to) { iter->value_iterated_from = iter->value_iterated_to; iter->value_iterated_to = new_value_iterated_to; } -static bool _all_values_iter_next(struct hdr_iter* iter) +static bool all_values_iter_next(struct hdr_iter* iter) { bool result = move_next(iter); if (result) { - _update_iterated_values(iter, iter->value); + update_iterated_values(iter, iter->value); } return result; @@ -689,7 +895,7 @@ void hdr_iter_init(struct hdr_iter* iter, const struct hdr_histogram* h) iter->value_iterated_from = 0; iter->value_iterated_to = 0; - iter->_next_fp = _all_values_iter_next; + iter->_next_fp = all_values_iter_next; } bool hdr_iter_next(struct hdr_iter* iter) @@ -697,16 +903,18 @@ bool hdr_iter_next(struct hdr_iter* iter) return iter->_next_fp(iter); } -// ######## ######## ######## ###### ######## ## ## ######## #### ## ######## ###### -// ## ## ## ## ## ## ## ## ### ## ## ## ## ## ## ## -// ## ## ## ## ## ## ## #### ## ## ## ## ## ## -// ######## ###### ######## ## ###### ## ## ## ## ## ## ###### ###### -// ## ## ## ## ## ## ## #### ## ## ## ## ## -// ## ## ## ## ## ## ## ## ### ## ## ## ## ## ## -// ## ######## ## ## ###### ######## ## ## ## #### ######## ######## ###### +/* ######## ######## ######## ###### ######## ## ## ######## #### ## ######## ###### */ +/* ## ## ## ## ## ## ## ## ### ## ## ## ## ## ## ## */ +/* ## ## ## ## ## ## ## #### ## ## ## ## ## ## */ +/* ######## ###### ######## ## ###### ## ## ## ## ## ## ###### ###### */ +/* ## ## ## ## ## ## ## #### ## ## ## ## ## */ +/* ## ## ## ## ## ## ## ## ### ## ## ## ## ## ## */ +/* ## ######## ## ## ###### ######## ## ## ## #### ######## ######## ###### */ -static bool _percentile_iter_next(struct hdr_iter* iter) +static bool percentile_iter_next(struct hdr_iter* iter) { + int64_t temp, half_distance, percentile_reporting_ticks; + struct hdr_iter_percentiles* percentiles = &iter->specifics.percentiles; if (!has_next(iter)) @@ -722,7 +930,7 @@ static bool _percentile_iter_next(struct hdr_iter* iter) return true; } - if (iter->counts_index == -1 && !_basic_iter_next(iter)) + if (iter->counts_index == -1 && !basic_iter_next(iter)) { return false; } @@ -733,18 +941,18 @@ static bool _percentile_iter_next(struct hdr_iter* iter) if (iter->count != 0 && percentiles->percentile_to_iterate_to <= current_percentile) { - _update_iterated_values(iter, highest_equivalent_value(iter->h, iter->value)); + update_iterated_values(iter, highest_equivalent_value(iter->h, iter->value)); percentiles->percentile = percentiles->percentile_to_iterate_to; - int64_t temp = (int64_t)(log(100 / (100.0 - (percentiles->percentile_to_iterate_to))) / log(2)) + 1; - int64_t half_distance = (int64_t) pow(2, (double) temp); - int64_t percentile_reporting_ticks = percentiles->ticks_per_half_distance * half_distance; + temp = (int64_t)(log(100 / (100.0 - (percentiles->percentile_to_iterate_to))) / log(2)) + 1; + half_distance = (int64_t) pow(2, (double) temp); + percentile_reporting_ticks = percentiles->ticks_per_half_distance * half_distance; percentiles->percentile_to_iterate_to += 100.0 / percentile_reporting_ticks; return true; } } - while (_basic_iter_next(iter)); + while (basic_iter_next(iter)); return true; } @@ -760,7 +968,7 @@ void hdr_iter_percentile_init(struct hdr_iter* iter, const struct hdr_histogram* iter->specifics.percentiles.percentile_to_iterate_to = 0.0; iter->specifics.percentiles.percentile = 0.0; - iter->_next_fp = _percentile_iter_next; + iter->_next_fp = percentile_iter_next; } static void format_line_string(char* str, size_t len, int significant_figures, format_type format) @@ -790,22 +998,22 @@ static void format_line_string(char* str, size_t len, int significant_figures, f } -// ######## ######## ###### ####### ######## ######## ######## ######## -// ## ## ## ## ## ## ## ## ## ## ## ## ## ## -// ## ## ## ## ## ## ## ## ## ## ## ## ## -// ######## ###### ## ## ## ######## ## ## ###### ## ## -// ## ## ## ## ## ## ## ## ## ## ## ## ## -// ## ## ## ## ## ## ## ## ## ## ## ## ## ## -// ## ## ######## ###### ####### ## ## ######## ######## ######## +/* ######## ######## ###### ####### ######## ######## ######## ######## */ +/* ## ## ## ## ## ## ## ## ## ## ## ## ## ## */ +/* ## ## ## ## ## ## ## ## ## ## ## ## ## */ +/* ######## ###### ## ## ## ######## ## ## ###### ## ## */ +/* ## ## ## ## ## ## ## ## ## ## ## ## ## */ +/* ## ## ## ## ## ## ## ## ## ## ## ## ## ## */ +/* ## ## ######## ###### ####### ## ## ######## ######## ######## */ -static bool _recorded_iter_next(struct hdr_iter* iter) +static bool recorded_iter_next(struct hdr_iter* iter) { - while (_basic_iter_next(iter)) + while (basic_iter_next(iter)) { if (iter->count != 0) { - _update_iterated_values(iter, iter->value); + update_iterated_values(iter, iter->value); iter->specifics.recorded.count_added_in_this_iteration_step = iter->count; return true; @@ -821,19 +1029,19 @@ void hdr_iter_recorded_init(struct hdr_iter* iter, const struct hdr_histogram* h iter->specifics.recorded.count_added_in_this_iteration_step = 0; - iter->_next_fp = _recorded_iter_next; + iter->_next_fp = recorded_iter_next; } -// ## #### ## ## ######## ### ######## -// ## ## ### ## ## ## ## ## ## -// ## ## #### ## ## ## ## ## ## -// ## ## ## ## ## ###### ## ## ######## -// ## ## ## #### ## ######### ## ## -// ## ## ## ### ## ## ## ## ## -// ######## #### ## ## ######## ## ## ## ## +/* ## #### ## ## ######## ### ######## */ +/* ## ## ### ## ## ## ## ## ## */ +/* ## ## #### ## ## ## ## ## ## */ +/* ## ## ## ## ## ###### ## ## ######## */ +/* ## ## ## #### ## ######### ## ## */ +/* ## ## ## ### ## ## ## ## ## */ +/* ######## #### ## ## ######## ## ## ## ## */ -static bool _iter_linear_next(struct hdr_iter* iter) +static bool iter_linear_next(struct hdr_iter* iter) { struct hdr_iter_linear* linear = &iter->specifics.linear; @@ -847,7 +1055,7 @@ static bool _iter_linear_next(struct hdr_iter* iter) { if (iter->value >= linear->next_value_reporting_level_lowest_equivalent) { - _update_iterated_values(iter, linear->next_value_reporting_level); + update_iterated_values(iter, linear->next_value_reporting_level); linear->next_value_reporting_level += linear->value_units_per_bucket; linear->next_value_reporting_level_lowest_equivalent = @@ -879,18 +1087,18 @@ void hdr_iter_linear_init(struct hdr_iter* iter, const struct hdr_histogram* h, iter->specifics.linear.next_value_reporting_level = value_units_per_bucket; iter->specifics.linear.next_value_reporting_level_lowest_equivalent = lowest_equivalent_value(h, value_units_per_bucket); - iter->_next_fp = _iter_linear_next; + iter->_next_fp = iter_linear_next; } -// ## ####### ###### ### ######## #### ######## ## ## ## ## #### ###### -// ## ## ## ## ## ## ## ## ## ## ## ## ## ### ### ## ## ## -// ## ## ## ## ## ## ## ## ## ## ## ## #### #### ## ## -// ## ## ## ## #### ## ## ######## ## ## ######### ## ### ## ## ## -// ## ## ## ## ## ######### ## ## ## ## ## ## ## ## ## ## -// ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## -// ######## ####### ###### ## ## ## ## #### ## ## ## ## ## #### ###### +/* ## ####### ###### ### ######## #### ######## ## ## ## ## #### ###### */ +/* ## ## ## ## ## ## ## ## ## ## ## ## ## ### ### ## ## ## */ +/* ## ## ## ## ## ## ## ## ## ## ## ## #### #### ## ## */ +/* ## ## ## ## #### ## ## ######## ## ## ######### ## ### ## ## ## */ +/* ## ## ## ## ## ######### ## ## ## ## ## ## ## ## ## ## */ +/* ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## */ +/* ######## ####### ###### ## ## ## ## #### ## ## ## ## ## #### ###### */ -static bool _log_iter_next(struct hdr_iter *iter) +static bool log_iter_next(struct hdr_iter *iter) { struct hdr_iter_log* logarithmic = &iter->specifics.log; @@ -904,7 +1112,7 @@ static bool _log_iter_next(struct hdr_iter *iter) { if (iter->value >= logarithmic->next_value_reporting_level_lowest_equivalent) { - _update_iterated_values(iter, logarithmic->next_value_reporting_level); + update_iterated_values(iter, logarithmic->next_value_reporting_level); logarithmic->next_value_reporting_level *= (int64_t)logarithmic->log_base; logarithmic->next_value_reporting_level_lowest_equivalent = lowest_equivalent_value(iter->h, logarithmic->next_value_reporting_level); @@ -937,10 +1145,10 @@ void hdr_iter_log_init( iter->specifics.log.next_value_reporting_level = value_units_first_bucket; iter->specifics.log.next_value_reporting_level_lowest_equivalent = lowest_equivalent_value(h, value_units_first_bucket); - iter->_next_fp = _log_iter_next; + iter->_next_fp = log_iter_next; } -// Printing. +/* Printing. */ static const char* format_head_string(format_type format) { @@ -949,7 +1157,6 @@ static const char* format_head_string(format_type format) case CSV: return "%s,%s,%s,%s\n"; case CLASSIC: - return "%12s %12s %12s %12s\n\n"; default: return "%12s %12s %12s %12s\n\n"; } @@ -965,11 +1172,14 @@ int hdr_percentiles_print( double value_scale, format_type format) { char line_format[25]; - format_line_string(line_format, 25, h->significant_figures, format); - const char* head_format = format_head_string(format); + const char* head_format; int rc = 0; - struct hdr_iter iter; + struct hdr_iter_percentiles * percentiles; + + format_line_string(line_format, 25, h->significant_figures, format); + head_format = format_head_string(format); + hdr_iter_percentile_init(&iter, h, ticks_per_half_distance); if (fprintf( @@ -980,7 +1190,7 @@ int hdr_percentiles_print( goto cleanup; } - struct hdr_iter_percentiles * percentiles = &iter.specifics.percentiles; + percentiles = &iter.specifics.percentiles; while (hdr_iter_next(&iter)) { double value = iter.highest_equivalent_value / value_scale; diff --git a/vendors/hdr_histogram/hdr_histogram.h b/vendors/hdr/hdr_histogram.h index 14eebdd..59ffe54 100644 --- a/vendors/hdr_histogram/hdr_histogram.h +++ b/vendors/hdr/hdr_histogram.h @@ -16,7 +16,7 @@ struct hdr_histogram { - int64_t lowest_trackable_value; + int64_t lowest_discernible_value; int64_t highest_trackable_value; int32_t unit_magnitude; int32_t significant_figures; @@ -43,11 +43,10 @@ extern "C" { * * Due to the size of the histogram being the result of some reasonably * involved math on the input parameters this function it is tricky to stack allocate. - * The histogram is allocated in a single contigious block so can be delete via free, - * without any structure specific destructor. + * The histogram should be released with hdr_close * - * @param lowest_trackable_value The smallest possible value to be put into the - * histogram. + * @param lowest_discernible_value The smallest possible value that is distinguishable from 0. + * Must be a positive integer that is >= 1. May be internally rounded down to nearest power of 2. * @param highest_trackable_value The largest possible value to be put into the * histogram. * @param significant_figures The level of precision for this histogram, i.e. the number @@ -55,12 +54,12 @@ extern "C" { * the results from the histogram will be accurate up to the first three digits. Must * be a value between 1 and 5 (inclusive). * @param result Output parameter to capture allocated histogram. - * @return 0 on success, EINVAL if lowest_trackable_value is < 1 or the + * @return 0 on success, EINVAL if lowest_discernible_value is < 1 or the * significant_figure value is outside of the allowed range, ENOMEM if malloc * failed. */ int hdr_init( - int64_t lowest_trackable_value, + int64_t lowest_discernible_value, int64_t highest_trackable_value, int significant_figures, struct hdr_histogram** result); @@ -112,6 +111,21 @@ size_t hdr_get_memory_size(struct hdr_histogram* h); bool hdr_record_value(struct hdr_histogram* h, int64_t value); /** + * Records a value in the histogram, will round this value of to a precision at or better + * than the significant_figure specified at construction time. + * + * Will record this value atomically, however the whole structure may appear inconsistent + * when read concurrently with this update. Do NOT mix calls to this method with calls + * to non-atomic updates. + * + * @param h "This" pointer + * @param value Value to add to the histogram + * @return false if the value is larger than the highest_trackable_value and can't be recorded, + * true otherwise. + */ +bool hdr_record_value_atomic(struct hdr_histogram* h, int64_t value); + +/** * Records count values in the histogram, will round this value of to a * precision at or better than the significant_figure specified at construction * time. @@ -124,15 +138,31 @@ bool hdr_record_value(struct hdr_histogram* h, int64_t value); */ bool hdr_record_values(struct hdr_histogram* h, int64_t value, int64_t count); +/** + * Records count values in the histogram, will round this value of to a + * precision at or better than the significant_figure specified at construction + * time. + * + * Will record this value atomically, however the whole structure may appear inconsistent + * when read concurrently with this update. Do NOT mix calls to this method with calls + * to non-atomic updates. + * + * @param h "This" pointer + * @param value Value to add to the histogram + * @param count Number of 'value's to add to the histogram + * @return false if any value is larger than the highest_trackable_value and can't be recorded, + * true otherwise. + */ +bool hdr_record_values_atomic(struct hdr_histogram* h, int64_t value, int64_t count); /** * Record a value in the histogram and backfill based on an expected interval. * * Records a value in the histogram, will round this value of to a precision at or better - * than the significant_figure specified at contruction time. This is specifically used + * than the significant_figure specified at construction time. This is specifically used * for recording latency. If the value is larger than the expected_interval then the * latency recording system has experienced co-ordinated omission. This method fills in the - * values that would have occured had the client providing the load not been blocked. + * values that would have occurred had the client providing the load not been blocked. * @param h "This" pointer * @param value Value to add to the histogram @@ -140,7 +170,29 @@ bool hdr_record_values(struct hdr_histogram* h, int64_t value, int64_t count); * @return false if the value is larger than the highest_trackable_value and can't be recorded, * true otherwise. */ -bool hdr_record_corrected_value(struct hdr_histogram* h, int64_t value, int64_t expexcted_interval); +bool hdr_record_corrected_value(struct hdr_histogram* h, int64_t value, int64_t expected_interval); + +/** + * Record a value in the histogram and backfill based on an expected interval. + * + * Records a value in the histogram, will round this value of to a precision at or better + * than the significant_figure specified at construction time. This is specifically used + * for recording latency. If the value is larger than the expected_interval then the + * latency recording system has experienced co-ordinated omission. This method fills in the + * values that would have occurred had the client providing the load not been blocked. + * + * Will record this value atomically, however the whole structure may appear inconsistent + * when read concurrently with this update. Do NOT mix calls to this method with calls + * to non-atomic updates. + * + * @param h "This" pointer + * @param value Value to add to the histogram + * @param expected_interval The delay between recording values. + * @return false if the value is larger than the highest_trackable_value and can't be recorded, + * true otherwise. + */ +bool hdr_record_corrected_value_atomic(struct hdr_histogram* h, int64_t value, int64_t expected_interval); + /** * Record a value in the histogram 'count' times. Applies the same correcting logic * as 'hdr_record_corrected_value'. @@ -155,9 +207,26 @@ bool hdr_record_corrected_value(struct hdr_histogram* h, int64_t value, int64_t bool hdr_record_corrected_values(struct hdr_histogram* h, int64_t value, int64_t count, int64_t expected_interval); /** + * Record a value in the histogram 'count' times. Applies the same correcting logic + * as 'hdr_record_corrected_value'. + * + * Will record this value atomically, however the whole structure may appear inconsistent + * when read concurrently with this update. Do NOT mix calls to this method with calls + * to non-atomic updates. + * + * @param h "This" pointer + * @param value Value to add to the histogram + * @param count Number of 'value's to add to the histogram + * @param expected_interval The delay between recording values. + * @return false if the value is larger than the highest_trackable_value and can't be recorded, + * true otherwise. + */ +bool hdr_record_corrected_values_atomic(struct hdr_histogram* h, int64_t value, int64_t count, int64_t expected_interval); + +/** * Adds all of the values from 'from' to 'this' histogram. Will return the * number of values that are dropped when copying. Values will be dropped - * if they around outside of h.lowest_trackable_value and + * if they around outside of h.lowest_discernible_value and * h.highest_trackable_value. * * @param h "This" pointer @@ -169,7 +238,7 @@ int64_t hdr_add(struct hdr_histogram* h, const struct hdr_histogram* from); /** * Adds all of the values from 'from' to 'this' histogram. Will return the * number of values that are dropped when copying. Values will be dropped - * if they around outside of h.lowest_trackable_value and + * if they around outside of h.lowest_discernible_value and * h.highest_trackable_value. * * @param h "This" pointer @@ -204,6 +273,18 @@ int64_t hdr_max(const struct hdr_histogram* h); int64_t hdr_value_at_percentile(const struct hdr_histogram* h, double percentile); /** + * Get the values at the given percentiles. + * + * @param h "This" pointer. + * @param percentiles The ordered percentiles array to get the values for. + * @param length Number of elements in the arrays. + * @param values Destination array containing the values at the given percentiles. + * The values array should be allocated by the caller. + * @return 0 on success, ENOMEM if the provided destination array is null. + */ +int hdr_value_at_percentiles(const struct hdr_histogram *h, const double *percentiles, int64_t *values, size_t length); + +/** * Gets the standard deviation for the values in the histogram. * * @param h "This" pointer @@ -300,7 +381,7 @@ struct hdr_iter /** raw index into the counts array */ int32_t counts_index; /** snapshot of the length at the time the iterator is created */ - int32_t total_count; + int64_t total_count; /** value directly from array for the current counts_index */ int64_t count; /** sum of all of the counts up to and including the count at this index */ @@ -396,7 +477,7 @@ int hdr_percentiles_print( */ struct hdr_histogram_bucket_config { - int64_t lowest_trackable_value; + int64_t lowest_discernible_value; int64_t highest_trackable_value; int64_t unit_magnitude; int64_t significant_figures; @@ -409,7 +490,7 @@ struct hdr_histogram_bucket_config }; int hdr_calculate_bucket_config( - int64_t lowest_trackable_value, + int64_t lowest_discernible_value, int64_t highest_trackable_value, int significant_figures, struct hdr_histogram_bucket_config* cfg); @@ -423,7 +504,7 @@ int64_t hdr_next_non_equivalent_value(const struct hdr_histogram* h, int64_t val int64_t hdr_median_equivalent_value(const struct hdr_histogram* h, int64_t value); /** - * Used to reset counters after importing data manuallying into the histogram, used by the logging code + * Used to reset counters after importing data manually into the histogram, used by the logging code * and other custom serialisation tools. */ void hdr_reset_internal_counters(struct hdr_histogram* h); diff --git a/vendors/hdr_histogram/hdr_histogram_log.c b/vendors/hdr/hdr_histogram_log.c index 06ab81a..06ab81a 100644 --- a/vendors/hdr_histogram/hdr_histogram_log.c +++ b/vendors/hdr/hdr_histogram_log.c diff --git a/vendors/hdr_histogram/hdr_histogram_log.h b/vendors/hdr/hdr_histogram_log.h index c1842b2..c1842b2 100644 --- a/vendors/hdr_histogram/hdr_histogram_log.h +++ b/vendors/hdr/hdr_histogram_log.h diff --git a/vendors/hdr/hdr_malloc.h b/vendors/hdr/hdr_malloc.h new file mode 100644 index 0000000..6fefc68 --- /dev/null +++ b/vendors/hdr/hdr_malloc.h @@ -0,0 +1,19 @@ +/** + * hdr_malloc.h + * Written by Filipe Oliveira and released to the public domain, + * as explained at http://creativecommons.org/publicdomain/zero/1.0/ + * + * Allocator selection. + * + * This file is used in order to change the HdrHistogram allocator at compile time. + * Just define the following defines to what you want to use. Also add + * the include of your alternate allocator if needed (not needed in order + * to use the default libc allocator). */ + +#ifndef HDR_MALLOC_H__ +#define HDR_MALLOC_H__ +#define hdr_malloc malloc +#define hdr_calloc calloc +#define hdr_realloc realloc +#define hdr_free free +#endif diff --git a/vendors/hdr/hdr_tests.h b/vendors/hdr/hdr_tests.h new file mode 100644 index 0000000..5cc65a0 --- /dev/null +++ b/vendors/hdr/hdr_tests.h @@ -0,0 +1,22 @@ +#ifndef HDR_TESTS_H +#define HDR_TESTS_H + +/* These are functions used in tests and are not intended for normal usage. */ + +#include <hdr/hdr_histogram.h> + +#ifdef __cplusplus +extern "C" { +#endif + +int32_t counts_index_for(const struct hdr_histogram* h, int64_t value); +int hdr_encode_compressed(struct hdr_histogram* h, uint8_t** compressed_histogram, size_t* compressed_len); +int hdr_decode_compressed(uint8_t* buffer, size_t length, struct hdr_histogram** histogram); +void hdr_base64_decode_block(const char* input, uint8_t* output); +void hdr_base64_encode_block(const uint8_t* input, char* output); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/vendors/hdr/hdr_time.c b/vendors/hdr/hdr_time.c new file mode 100644 index 0000000..feebb56 --- /dev/null +++ b/vendors/hdr/hdr_time.c @@ -0,0 +1,97 @@ +/** +* hdr_time.h +* Written by Michael Barker and Philip Orwig and released to the public domain, +* as explained at http://creativecommons.org/publicdomain/zero/1.0/ +*/ + +#include <math.h> + +#include <hdr/hdr_time.h> + +#if defined(_WIN32) || defined(_WIN64) + +#if !defined(WIN32_LEAN_AND_MEAN) +#define WIN32_LEAN_AND_MEAN +#endif + +#include <windows.h> + +static int s_clockPeriodSet = 0; +static double s_clockPeriod = 1.0; + +void hdr_gettime(hdr_timespec* t) +{ + LARGE_INTEGER num; + /* if this is distasteful, we can add in an hdr_time_init() */ + if (!s_clockPeriodSet) + { + QueryPerformanceFrequency(&num); + s_clockPeriod = 1.0 / (double) num.QuadPart; + s_clockPeriodSet = 1; + } + + QueryPerformanceCounter(&num); + double seconds = num.QuadPart * s_clockPeriod; + double integral; + double remainder = modf(seconds, &integral); + + t->tv_sec = (long) integral; + t->tv_nsec = (long) (remainder * 1000000000); +} + +#elif defined(__APPLE__) + +#include <mach/clock.h> +#include <mach/mach.h> + + +void hdr_gettime(hdr_timespec* ts) +{ + clock_serv_t cclock; + mach_timespec_t mts; + host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, &cclock); + clock_get_time(cclock, &mts); + mach_port_deallocate(mach_task_self(), cclock); + ts->tv_sec = mts.tv_sec; + ts->tv_nsec = mts.tv_nsec; +} + + +void hdr_getnow(hdr_timespec* ts) +{ + hdr_gettime(ts); +} + +#elif defined(__linux__) || defined(__CYGWIN__) || defined(__OpenBSD__) + + +void hdr_gettime(hdr_timespec* t) +{ + clock_gettime(CLOCK_MONOTONIC, (struct timespec*)t); +} + +void hdr_getnow(hdr_timespec* t) +{ + clock_gettime(CLOCK_REALTIME, (struct timespec*)t); +} + +#else + +#warning "Platform not supported\n" + +#endif + +double hdr_timespec_as_double(const hdr_timespec* t) +{ + double d = t->tv_sec; + return d + (t->tv_nsec / 1000000000.0); +} + +void hdr_timespec_from_double(hdr_timespec* t, double value) +{ + int seconds = (int) value; + int milliseconds = (int) round((value - seconds) * 1000); + + t->tv_sec = seconds; + t->tv_nsec = milliseconds * 1000000; +} diff --git a/vendors/hdr/hdr_time.h b/vendors/hdr/hdr_time.h new file mode 100644 index 0000000..3bdeec1 --- /dev/null +++ b/vendors/hdr/hdr_time.h @@ -0,0 +1,47 @@ +/** + * hdr_time.h + * Written by Michael Barker and released to the public domain, + * as explained at http://creativecommons.org/publicdomain/zero/1.0/ + */ + +#ifndef HDR_TIME_H__ +#define HDR_TIME_H__ + +#include <time.h> + +#if defined(_WIN32) || defined(_WIN64) || defined(__CYGWIN__) + +typedef struct hdr_timespec +{ + long tv_sec; + long tv_nsec; +} hdr_timespec; + +#else + +typedef struct timespec hdr_timespec; + +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined(_MSC_VER) +void hdr_gettime(hdr_timespec* t); +#else +void hdr_gettime(hdr_timespec* t); +#endif + +void hdr_getnow(hdr_timespec* t); + +double hdr_timespec_as_double(const hdr_timespec* t); + +/* Assumes only millisecond accuracy. */ +void hdr_timespec_from_double(hdr_timespec* t, double value); + +#ifdef __cplusplus +} +#endif + +#endif |
