mirror of
https://github.com/djhackersdev/bemanitools.git
synced 2026-04-19 16:17:34 -05:00
wip iidxio-async
Summary: Test Plan:
This commit is contained in:
parent
ce1a004bf6
commit
3d868e33d4
|
|
@ -135,6 +135,7 @@ include src/main/ezusb2-popn-shim/Module.mk
|
|||
include src/main/ezusb2-tool/Module.mk
|
||||
include src/main/ezusb2/Module.mk
|
||||
include src/main/geninput/Module.mk
|
||||
include src/main/hdr-histogram/Module.mk
|
||||
include src/main/hook/Module.mk
|
||||
include src/main/hooklib/Module.mk
|
||||
include src/main/iidx-bio2-exit-hook/Module.mk
|
||||
|
|
@ -154,9 +155,11 @@ include src/main/iidxhook6/Module.mk
|
|||
include src/main/iidxhook7/Module.mk
|
||||
include src/main/iidxhook8/Module.mk
|
||||
include src/main/iidxhook9/Module.mk
|
||||
include src/main/iidxio-async/Module.mk
|
||||
include src/main/iidxio-bio2/Module.mk
|
||||
include src/main/iidxio-ezusb/Module.mk
|
||||
include src/main/iidxio-ezusb2/Module.mk
|
||||
include src/main/iidxio-perf/Module.mk
|
||||
include src/main/iidxio/Module.mk
|
||||
include src/main/iidxiotest/Module.mk
|
||||
include src/main/inject/Module.mk
|
||||
|
|
@ -456,9 +459,11 @@ $(zipdir)/iidx-27-to-30.zip: \
|
|||
$(zipdir)/iidx-hwio-x86.zip: \
|
||||
build/bin/indep-32/aciomgr.dll \
|
||||
build/bin/indep-32/eamio-icca.dll \
|
||||
build/bin/indep-32/iidxio-async.dll \
|
||||
build/bin/indep-32/iidxio-bio2.dll \
|
||||
build/bin/indep-32/iidxio-ezusb.dll \
|
||||
build/bin/indep-32/iidxio-ezusb2.dll \
|
||||
build/bin/indep-32/iidxio-perf.dll \
|
||||
dist/iidx/iidxio-bio2.conf \
|
||||
build/bin/indep-32/vigem-iidxio.exe \
|
||||
dist/iidx/vigem-iidxio.conf \
|
||||
|
|
@ -469,9 +474,11 @@ $(zipdir)/iidx-hwio-x86.zip: \
|
|||
$(zipdir)/iidx-hwio-x64.zip: \
|
||||
build/bin/indep-64/aciomgr.dll \
|
||||
build/bin/indep-64/eamio-icca.dll \
|
||||
build/bin/indep-64/iidxio-async.dll \
|
||||
build/bin/indep-64/iidxio-bio2.dll \
|
||||
build/bin/indep-64/iidxio-ezusb.dll \
|
||||
build/bin/indep-64/iidxio-ezusb2.dll \
|
||||
build/bin/indep-64/iidxio-perf.dll \
|
||||
dist/iidx/iidxio-bio2.conf \
|
||||
build/bin/indep-64/vigem-iidxio.exe \
|
||||
dist/iidx/vigem-iidxio.conf \
|
||||
|
|
|
|||
10
src/main/hdr-histogram/Module.mk
Normal file
10
src/main/hdr-histogram/Module.mk
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
libs += hdr-histogram
|
||||
|
||||
src_hdr-histogram := \
|
||||
hdr_encoding.c \
|
||||
hdr_histogram_log_no_op.c \
|
||||
hdr_histogram.c \
|
||||
hdr_interval_recorder.c \
|
||||
hdr_thread.c \
|
||||
hdr_time.c \
|
||||
hdr_writer_reader_phaser.c \
|
||||
146
src/main/hdr-histogram/hdr_atomic.h
Normal file
146
src/main/hdr-histogram/hdr_atomic.h
Normal file
|
|
@ -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__ */
|
||||
322
src/main/hdr-histogram/hdr_encoding.c
Normal file
322
src/main/hdr-histogram/hdr_encoding.c
Normal file
|
|
@ -0,0 +1,322 @@
|
|||
/**
|
||||
* 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-histogram/hdr_encoding.h"
|
||||
#include "hdr-histogram/hdr_tests.h"
|
||||
|
||||
int zig_zag_encode_i64(uint8_t* buffer, int64_t signed_value)
|
||||
{
|
||||
int bytesWritten;
|
||||
int64_t value = signed_value;
|
||||
|
||||
value = (value << 1) ^ (value >> 63);
|
||||
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;
|
||||
}
|
||||
79
src/main/hdr-histogram/hdr_encoding.h
Normal file
79
src/main/hdr-histogram/hdr_encoding.h
Normal file
|
|
@ -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 */
|
||||
116
src/main/hdr-histogram/hdr_endian.h
Normal file
116
src/main/hdr-histogram/hdr_endian.h
Normal file
|
|
@ -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
|
||||
1226
src/main/hdr-histogram/hdr_histogram.c
Normal file
1226
src/main/hdr-histogram/hdr_histogram.c
Normal file
File diff suppressed because it is too large
Load Diff
516
src/main/hdr-histogram/hdr_histogram.h
Normal file
516
src/main/hdr-histogram/hdr_histogram.h
Normal file
|
|
@ -0,0 +1,516 @@
|
|||
/**
|
||||
* hdr_histogram.h
|
||||
* Written by Michael Barker and released to the public domain,
|
||||
* as explained at http://creativecommons.org/publicdomain/zero/1.0/
|
||||
*
|
||||
* The source for the hdr_histogram utilises a few C99 constructs, specifically
|
||||
* the use of stdint/stdbool and inline variable declaration.
|
||||
*/
|
||||
|
||||
#ifndef HDR_HISTOGRAM_H
|
||||
#define HDR_HISTOGRAM_H 1
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
|
||||
struct hdr_histogram
|
||||
{
|
||||
int64_t lowest_discernible_value;
|
||||
int64_t highest_trackable_value;
|
||||
int32_t unit_magnitude;
|
||||
int32_t significant_figures;
|
||||
int32_t sub_bucket_half_count_magnitude;
|
||||
int32_t sub_bucket_half_count;
|
||||
int64_t sub_bucket_mask;
|
||||
int32_t sub_bucket_count;
|
||||
int32_t bucket_count;
|
||||
int64_t min_value;
|
||||
int64_t max_value;
|
||||
int32_t normalizing_index_offset;
|
||||
double conversion_ratio;
|
||||
int32_t counts_len;
|
||||
int64_t total_count;
|
||||
int64_t* counts;
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Allocate the memory and initialise the hdr_histogram.
|
||||
*
|
||||
* 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 should be released with hdr_close
|
||||
*
|
||||
* @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
|
||||
* of figures in a decimal number that will be maintained. E.g. a value of 3 will mean
|
||||
* 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_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_discernible_value,
|
||||
int64_t highest_trackable_value,
|
||||
int significant_figures,
|
||||
struct hdr_histogram** result);
|
||||
|
||||
/**
|
||||
* Free the memory and close the hdr_histogram.
|
||||
*
|
||||
* @param h The histogram you want to close.
|
||||
*/
|
||||
void hdr_close(struct hdr_histogram* h);
|
||||
|
||||
/**
|
||||
* Allocate the memory and initialise the hdr_histogram. This is the equivalent of calling
|
||||
* hdr_init(1, highest_trackable_value, significant_figures, result);
|
||||
*
|
||||
* @deprecated use hdr_init.
|
||||
*/
|
||||
int hdr_alloc(int64_t highest_trackable_value, int significant_figures, struct hdr_histogram** result);
|
||||
|
||||
|
||||
/**
|
||||
* Reset a histogram to zero - empty out a histogram and re-initialise it
|
||||
*
|
||||
* If you want to re-use an existing histogram, but reset everything back to zero, this
|
||||
* is the routine to use.
|
||||
*
|
||||
* @param h The histogram you want to reset to empty.
|
||||
*
|
||||
*/
|
||||
void hdr_reset(struct hdr_histogram* h);
|
||||
|
||||
/**
|
||||
* Get the memory size of the hdr_histogram.
|
||||
*
|
||||
* @param h "This" pointer
|
||||
* @return The amount of memory used by the hdr_histogram in bytes
|
||||
*/
|
||||
size_t hdr_get_memory_size(struct hdr_histogram* h);
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* @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(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.
|
||||
*
|
||||
* @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(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 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.
|
||||
|
||||
* @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(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'.
|
||||
*
|
||||
* @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(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_discernible_value and
|
||||
* h.highest_trackable_value.
|
||||
*
|
||||
* @param h "This" pointer
|
||||
* @param from Histogram to copy values from.
|
||||
* @return The number of values dropped when copying.
|
||||
*/
|
||||
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_discernible_value and
|
||||
* h.highest_trackable_value.
|
||||
*
|
||||
* @param h "This" pointer
|
||||
* @param from Histogram to copy values from.
|
||||
* @return The number of values dropped when copying.
|
||||
*/
|
||||
int64_t hdr_add_while_correcting_for_coordinated_omission(
|
||||
struct hdr_histogram* h, struct hdr_histogram* from, int64_t expected_interval);
|
||||
|
||||
/**
|
||||
* Get minimum value from the histogram. Will return 2^63-1 if the histogram
|
||||
* is empty.
|
||||
*
|
||||
* @param h "This" pointer
|
||||
*/
|
||||
int64_t hdr_min(const struct hdr_histogram* h);
|
||||
|
||||
/**
|
||||
* Get maximum value from the histogram. Will return 0 if the histogram
|
||||
* is empty.
|
||||
*
|
||||
* @param h "This" pointer
|
||||
*/
|
||||
int64_t hdr_max(const struct hdr_histogram* h);
|
||||
|
||||
/**
|
||||
* Get the value at a specific percentile.
|
||||
*
|
||||
* @param h "This" pointer.
|
||||
* @param percentile The percentile to get the value for
|
||||
*/
|
||||
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
|
||||
* @return The standard deviation
|
||||
*/
|
||||
double hdr_stddev(const struct hdr_histogram* h);
|
||||
|
||||
/**
|
||||
* Gets the mean for the values in the histogram.
|
||||
*
|
||||
* @param h "This" pointer
|
||||
* @return The mean
|
||||
*/
|
||||
double hdr_mean(const struct hdr_histogram* h);
|
||||
|
||||
/**
|
||||
* Determine if two values are equivalent with the histogram's resolution.
|
||||
* Where "equivalent" means that value samples recorded for any two
|
||||
* equivalent values are counted in a common total count.
|
||||
*
|
||||
* @param h "This" pointer
|
||||
* @param a first value to compare
|
||||
* @param b second value to compare
|
||||
* @return 'true' if values are equivalent with the histogram's resolution.
|
||||
*/
|
||||
bool hdr_values_are_equivalent(const struct hdr_histogram* h, int64_t a, int64_t b);
|
||||
|
||||
/**
|
||||
* Get the lowest value that is equivalent to the given value within the histogram's resolution.
|
||||
* Where "equivalent" means that value samples recorded for any two
|
||||
* equivalent values are counted in a common total count.
|
||||
*
|
||||
* @param h "This" pointer
|
||||
* @param value The given value
|
||||
* @return The lowest value that is equivalent to the given value within the histogram's resolution.
|
||||
*/
|
||||
int64_t hdr_lowest_equivalent_value(const struct hdr_histogram* h, int64_t value);
|
||||
|
||||
/**
|
||||
* Get the count of recorded values at a specific value
|
||||
* (to within the histogram resolution at the value level).
|
||||
*
|
||||
* @param h "This" pointer
|
||||
* @param value The value for which to provide the recorded count
|
||||
* @return The total count of values recorded in the histogram within the value range that is
|
||||
* {@literal >=} lowestEquivalentValue(<i>value</i>) and {@literal <=} highestEquivalentValue(<i>value</i>)
|
||||
*/
|
||||
int64_t hdr_count_at_value(const struct hdr_histogram* h, int64_t value);
|
||||
|
||||
int64_t hdr_count_at_index(const struct hdr_histogram* h, int32_t index);
|
||||
|
||||
int64_t hdr_value_at_index(const struct hdr_histogram* h, int32_t index);
|
||||
|
||||
struct hdr_iter_percentiles
|
||||
{
|
||||
bool seen_last_value;
|
||||
int32_t ticks_per_half_distance;
|
||||
double percentile_to_iterate_to;
|
||||
double percentile;
|
||||
};
|
||||
|
||||
struct hdr_iter_recorded
|
||||
{
|
||||
int64_t count_added_in_this_iteration_step;
|
||||
};
|
||||
|
||||
struct hdr_iter_linear
|
||||
{
|
||||
int64_t value_units_per_bucket;
|
||||
int64_t count_added_in_this_iteration_step;
|
||||
int64_t next_value_reporting_level;
|
||||
int64_t next_value_reporting_level_lowest_equivalent;
|
||||
};
|
||||
|
||||
struct hdr_iter_log
|
||||
{
|
||||
double log_base;
|
||||
int64_t count_added_in_this_iteration_step;
|
||||
int64_t next_value_reporting_level;
|
||||
int64_t next_value_reporting_level_lowest_equivalent;
|
||||
};
|
||||
|
||||
/**
|
||||
* The basic iterator. This is a generic structure
|
||||
* that supports all of the types of iteration. Use
|
||||
* the appropriate initialiser to get the desired
|
||||
* iteration.
|
||||
*
|
||||
* @
|
||||
*/
|
||||
struct hdr_iter
|
||||
{
|
||||
const struct hdr_histogram* h;
|
||||
/** raw index into the counts array */
|
||||
int32_t counts_index;
|
||||
/** snapshot of the length at the time the iterator is created */
|
||||
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 */
|
||||
int64_t cumulative_count;
|
||||
/** The current value based on counts_index */
|
||||
int64_t value;
|
||||
int64_t highest_equivalent_value;
|
||||
int64_t lowest_equivalent_value;
|
||||
int64_t median_equivalent_value;
|
||||
int64_t value_iterated_from;
|
||||
int64_t value_iterated_to;
|
||||
|
||||
union
|
||||
{
|
||||
struct hdr_iter_percentiles percentiles;
|
||||
struct hdr_iter_recorded recorded;
|
||||
struct hdr_iter_linear linear;
|
||||
struct hdr_iter_log log;
|
||||
} specifics;
|
||||
|
||||
bool (* _next_fp)(struct hdr_iter* iter);
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* Initalises the basic iterator.
|
||||
*
|
||||
* @param itr 'This' pointer
|
||||
* @param h The histogram to iterate over
|
||||
*/
|
||||
void hdr_iter_init(struct hdr_iter* iter, const struct hdr_histogram* h);
|
||||
|
||||
/**
|
||||
* Initialise the iterator for use with percentiles.
|
||||
*/
|
||||
void hdr_iter_percentile_init(struct hdr_iter* iter, const struct hdr_histogram* h, int32_t ticks_per_half_distance);
|
||||
|
||||
/**
|
||||
* Initialise the iterator for use with recorded values.
|
||||
*/
|
||||
void hdr_iter_recorded_init(struct hdr_iter* iter, const struct hdr_histogram* h);
|
||||
|
||||
/**
|
||||
* Initialise the iterator for use with linear values.
|
||||
*/
|
||||
void hdr_iter_linear_init(
|
||||
struct hdr_iter* iter,
|
||||
const struct hdr_histogram* h,
|
||||
int64_t value_units_per_bucket);
|
||||
|
||||
/**
|
||||
* Initialise the iterator for use with logarithmic values
|
||||
*/
|
||||
void hdr_iter_log_init(
|
||||
struct hdr_iter* iter,
|
||||
const struct hdr_histogram* h,
|
||||
int64_t value_units_first_bucket,
|
||||
double log_base);
|
||||
|
||||
/**
|
||||
* Iterate to the next value for the iterator. If there are no more values
|
||||
* available return faluse.
|
||||
*
|
||||
* @param itr 'This' pointer
|
||||
* @return 'false' if there are no values remaining for this iterator.
|
||||
*/
|
||||
bool hdr_iter_next(struct hdr_iter* iter);
|
||||
|
||||
typedef enum
|
||||
{
|
||||
CLASSIC,
|
||||
CSV
|
||||
} format_type;
|
||||
|
||||
/**
|
||||
* Print out a percentile based histogram to the supplied stream. Note that
|
||||
* this call will not flush the FILE, this is left up to the user.
|
||||
*
|
||||
* @param h 'This' pointer
|
||||
* @param stream The FILE to write the output to
|
||||
* @param ticks_per_half_distance The number of iteration steps per half-distance to 100%
|
||||
* @param value_scale Scale the output values by this amount
|
||||
* @param format_type Format to use, e.g. CSV.
|
||||
* @return 0 on success, error code on failure. EIO if an error occurs writing
|
||||
* the output.
|
||||
*/
|
||||
int hdr_percentiles_print(
|
||||
struct hdr_histogram* h, FILE* stream, int32_t ticks_per_half_distance,
|
||||
double value_scale, format_type format);
|
||||
|
||||
/**
|
||||
* Internal allocation methods, used by hdr_dbl_histogram.
|
||||
*/
|
||||
struct hdr_histogram_bucket_config
|
||||
{
|
||||
int64_t lowest_discernible_value;
|
||||
int64_t highest_trackable_value;
|
||||
int64_t unit_magnitude;
|
||||
int64_t significant_figures;
|
||||
int32_t sub_bucket_half_count_magnitude;
|
||||
int32_t sub_bucket_half_count;
|
||||
int64_t sub_bucket_mask;
|
||||
int32_t sub_bucket_count;
|
||||
int32_t bucket_count;
|
||||
int32_t counts_len;
|
||||
};
|
||||
|
||||
int hdr_calculate_bucket_config(
|
||||
int64_t lowest_discernible_value,
|
||||
int64_t highest_trackable_value,
|
||||
int significant_figures,
|
||||
struct hdr_histogram_bucket_config* cfg);
|
||||
|
||||
void hdr_init_preallocated(struct hdr_histogram* h, struct hdr_histogram_bucket_config* cfg);
|
||||
|
||||
int64_t hdr_size_of_equivalent_value_range(const struct hdr_histogram* h, int64_t value);
|
||||
|
||||
int64_t hdr_next_non_equivalent_value(const struct hdr_histogram* h, int64_t value);
|
||||
|
||||
int64_t hdr_median_equivalent_value(const struct hdr_histogram* h, int64_t value);
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
1290
src/main/hdr-histogram/hdr_histogram_log.c
Normal file
1290
src/main/hdr-histogram/hdr_histogram_log.c
Normal file
File diff suppressed because it is too large
Load Diff
236
src/main/hdr-histogram/hdr_histogram_log.h
Normal file
236
src/main/hdr-histogram/hdr_histogram_log.h
Normal file
|
|
@ -0,0 +1,236 @@
|
|||
/**
|
||||
* hdr_histogram_log.h
|
||||
* Written by Michael Barker and released to the public domain,
|
||||
* as explained at http://creativecommons.org/publicdomain/zero/1.0/
|
||||
*
|
||||
* The implementation makes use of zlib to provide compression. You will need
|
||||
* to link against -lz in order to link applications that include this header.
|
||||
*/
|
||||
|
||||
#ifndef HDR_HISTOGRAM_H_LOG
|
||||
#define HDR_HISTOGRAM_H_LOG 1
|
||||
|
||||
#define HDR_COMPRESSION_COOKIE_MISMATCH -29999
|
||||
#define HDR_ENCODING_COOKIE_MISMATCH -29998
|
||||
#define HDR_DEFLATE_INIT_FAIL -29997
|
||||
#define HDR_DEFLATE_FAIL -29996
|
||||
#define HDR_INFLATE_INIT_FAIL -29995
|
||||
#define HDR_INFLATE_FAIL -29994
|
||||
#define HDR_LOG_INVALID_VERSION -29993
|
||||
#define HDR_TRAILING_ZEROS_INVALID -29992
|
||||
#define HDR_VALUE_TRUNCATED -29991
|
||||
#define HDR_ENCODED_INPUT_TOO_LONG -29990
|
||||
|
||||
#define HDR_LOG_TAG_MAX_BUFFER_LEN (1024)
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "hdr-histogram/hdr_time.h"
|
||||
#include "hdr-histogram/hdr_histogram.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Encode and compress the histogram with gzip.
|
||||
*/
|
||||
int hdr_log_encode(struct hdr_histogram* histogram, char** encoded_histogram);
|
||||
|
||||
/**
|
||||
* Decode and decompress the histogram with gzip.
|
||||
*/
|
||||
int hdr_log_decode(struct hdr_histogram** histogram, char* base64_histogram, size_t base64_len);
|
||||
|
||||
struct hdr_log_entry
|
||||
{
|
||||
hdr_timespec start_timestamp;
|
||||
hdr_timespec interval;
|
||||
hdr_timespec max;
|
||||
char *tag;
|
||||
size_t tag_len;
|
||||
};
|
||||
|
||||
struct hdr_log_writer
|
||||
{
|
||||
uint32_t nonce;
|
||||
};
|
||||
|
||||
/**
|
||||
* Initialise the log writer.
|
||||
*
|
||||
* @param writer 'This' pointer
|
||||
* @return 0 on success.
|
||||
*/
|
||||
int hdr_log_writer_init(struct hdr_log_writer* writer);
|
||||
|
||||
/**
|
||||
* Write the header to the log, this will constist of a user defined string,
|
||||
* the current timestamp, version information and the CSV header.
|
||||
*
|
||||
* @param writer 'This' pointer
|
||||
* @param file The stream to output the log header to.
|
||||
* @param user_prefix User defined string to include in the header.
|
||||
* @param timestamp The start time that the histogram started recording from.
|
||||
* @return Will return 0 if it successfully completed or an error number if there
|
||||
* was a failure. EIO if the write failed.
|
||||
*/
|
||||
int hdr_log_write_header(
|
||||
struct hdr_log_writer* writer,
|
||||
FILE* file,
|
||||
const char* user_prefix,
|
||||
hdr_timespec* timestamp);
|
||||
|
||||
/**
|
||||
* Write an hdr_histogram entry to the log. It will be encoded in a similar
|
||||
* fashion to the approach used by the Java version of the HdrHistogram. It will
|
||||
* be a CSV line consisting of <start timestamp>,<end timestamp>,<max>,<histogram>
|
||||
* where <histogram> is the binary histogram gzip compressed and base64 encoded.
|
||||
*
|
||||
* Timestamp is a bit of misnomer for the start_timestamp and end_timestamp values
|
||||
* these could be offsets, e.g. start_timestamp could be offset from process start
|
||||
* time and end_timestamp could actually be the length of the recorded interval.
|
||||
*
|
||||
* @param writer 'This' pointer
|
||||
* @param file The stream to write the entry to.
|
||||
* @param start_timestamp The start timestamp to include in the logged entry.
|
||||
* @param end_timestamp The end timestamp to include in the logged entry.
|
||||
* @param histogram The histogram to encode and log.
|
||||
* @return Will return 0 if it successfully completed or an error number if there
|
||||
* was a failure. Errors include HDR_DEFLATE_INIT_FAIL, HDR_DEFLATE_FAIL if
|
||||
* something when wrong during gzip compression. ENOMEM if we failed to allocate
|
||||
* or reallocate the buffer used for encoding (out of memory problem). EIO if
|
||||
* write failed.
|
||||
*/
|
||||
int hdr_log_write(
|
||||
struct hdr_log_writer* writer,
|
||||
FILE* file,
|
||||
const hdr_timespec* start_timestamp,
|
||||
const hdr_timespec* end_timestamp,
|
||||
struct hdr_histogram* histogram);
|
||||
|
||||
/**
|
||||
* Write an hdr_histogram entry to the log. It will be encoded in a similar
|
||||
* fashion to the approach used by the Java version of the HdrHistogram. It will
|
||||
* be a CSV line consisting of [Tag=XXX,]<start timestamp>,<end timestamp>,<max>,<histogram>
|
||||
* where <histogram> is the binary histogram gzip compressed and base64 encoded.
|
||||
*
|
||||
* The tag is option and will only be written if the tag is non-NULL and the tag_len is
|
||||
* greater than 0.
|
||||
*
|
||||
* Timestamp is a bit of misnomer for the start_timestamp and end_timestamp values
|
||||
* these could be offsets, e.g. start_timestamp could be offset from process start
|
||||
* time and end_timestamp could actually be the length of the recorded interval.
|
||||
*
|
||||
* @param writer 'This' pointer
|
||||
* @param file The stream to write the entry to.
|
||||
* @param entry Prefix information for the log line, including timestamps and tag.
|
||||
* @param histogram The histogram to encode and log.
|
||||
* @return Will return 0 if it successfully completed or an error number if there
|
||||
* was a failure. Errors include HDR_DEFLATE_INIT_FAIL, HDR_DEFLATE_FAIL if
|
||||
* something when wrong during gzip compression. ENOMEM if we failed to allocate
|
||||
* or reallocate the buffer used for encoding (out of memory problem). EIO if
|
||||
* write failed.
|
||||
*/
|
||||
int hdr_log_write_entry(
|
||||
struct hdr_log_writer* writer,
|
||||
FILE* file,
|
||||
struct hdr_log_entry* entry,
|
||||
struct hdr_histogram* histogram);
|
||||
|
||||
struct hdr_log_reader
|
||||
{
|
||||
int major_version;
|
||||
int minor_version;
|
||||
hdr_timespec start_timestamp;
|
||||
};
|
||||
|
||||
/**
|
||||
* Initialise the log reader.
|
||||
*
|
||||
* @param reader 'This' pointer
|
||||
* @return 0 on success
|
||||
*/
|
||||
int hdr_log_reader_init(struct hdr_log_reader* reader);
|
||||
|
||||
/**
|
||||
* Reads the the header information from the log. Will capure information
|
||||
* such as version number and start timestamp from the header.
|
||||
*
|
||||
* @param hdr_log_reader 'This' pointer
|
||||
* @param file The data stream to read from.
|
||||
* @return 0 on success. An error number on failure.
|
||||
*/
|
||||
int hdr_log_read_header(struct hdr_log_reader* reader, FILE* file);
|
||||
|
||||
/**
|
||||
* Reads an entry from the log filling in the specified histogram, timestamp and
|
||||
* interval values. If the supplied pointer to the histogram for this method is
|
||||
* NULL then a new histogram will be allocated for the caller, however it will
|
||||
* become the callers responsibility to free it later. If the pointer is non-null
|
||||
* the histogram read from the log will be merged with the supplied histogram.
|
||||
*
|
||||
* @param reader 'This' pointer
|
||||
* @param file The stream to read the histogram from.
|
||||
* @param histogram Pointer to allocate a histogram to or merge into.
|
||||
* @param timestamp The first timestamp from the CSV entry.
|
||||
* @param interval The second timestamp from the CSV entry
|
||||
* @return Will return 0 on success or an error number if there was some wrong
|
||||
* when reading in the histogram. EOF (-1) will indicate that there are no more
|
||||
* histograms left to be read from 'file'.
|
||||
* HDR_INFLATE_INIT_FAIL or HDR_INFLATE_FAIL if
|
||||
* there was a problem with Gzip. HDR_COMPRESSION_COOKIE_MISMATCH or
|
||||
* HDR_ENCODING_COOKIE_MISMATCH if the cookie values are incorrect.
|
||||
* HDR_LOG_INVALID_VERSION if the log can not be parsed. ENOMEM if buffer space
|
||||
* or the histogram can not be allocated. EIO if there was an error during
|
||||
* the read. EINVAL in any input values are incorrect.
|
||||
*/
|
||||
int hdr_log_read(
|
||||
struct hdr_log_reader* reader, FILE* file, struct hdr_histogram** histogram,
|
||||
hdr_timespec* timestamp, hdr_timespec* interval);
|
||||
|
||||
/**
|
||||
* Reads an entry from the log filling in the specified histogram and log entry struct.
|
||||
* If the supplied pointer to the histogram for this method is
|
||||
* NULL then a new histogram will be allocated for the caller, however it will
|
||||
* become the callers responsibility to free it later. If the pointer is non-null
|
||||
* the histogram read from the log will be merged with the supplied histogram.
|
||||
* The entry struct contains a pointer to a buffer to load the tag into. If this
|
||||
* is NULL or the tag_len is 0 then it won't store the tag there. The tag value will be
|
||||
* NULL-terminated if there available space in the supplied buffer. If the tag is larger
|
||||
* than the supplied buffer then it will be truncated. If the caller sets the last element
|
||||
* in the buffer to '\0' before calling this function and it is not '\0' after the function
|
||||
* returns then the value has been truncated.
|
||||
*
|
||||
* @param reader 'This' pointer
|
||||
* @param file The stream to read the histogram from.
|
||||
* @param entry Contains all of the information from the log line that is not the histogram.
|
||||
* @param histogram Pointer to allocate a histogram to or merge into.
|
||||
* @return Will return 0 on success or an error number if there was some wrong
|
||||
* when reading in the histogram. EOF (-1) will indicate that there are no more
|
||||
* histograms left to be read from 'file'.
|
||||
* HDR_INFLATE_INIT_FAIL or HDR_INFLATE_FAIL if
|
||||
* there was a problem with Gzip. HDR_COMPRESSION_COOKIE_MISMATCH or
|
||||
* HDR_ENCODING_COOKIE_MISMATCH if the cookie values are incorrect.
|
||||
* HDR_LOG_INVALID_VERSION if the log can not be parsed. ENOMEM if buffer space
|
||||
* or the histogram can not be allocated. EIO if there was an error during
|
||||
* the read. EINVAL in any input values are incorrect.
|
||||
*/
|
||||
int hdr_log_read_entry(
|
||||
struct hdr_log_reader* reader, FILE* file, struct hdr_log_entry *entry, struct hdr_histogram** histogram);
|
||||
|
||||
/**
|
||||
* Returns a string representation of the error number.
|
||||
*
|
||||
* @param errnum The error response from a previous call.
|
||||
* @return The user readable representation of the error.
|
||||
*/
|
||||
const char* hdr_strerror(int errnum);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
171
src/main/hdr-histogram/hdr_histogram_log_no_op.c
Normal file
171
src/main/hdr-histogram/hdr_histogram_log_no_op.c
Normal file
|
|
@ -0,0 +1,171 @@
|
|||
/**
|
||||
* hdr_histogram_log.c
|
||||
* Written by Michael Barker and released to the public domain,
|
||||
* as explained at http://creativecommons.org/publicdomain/zero/1.0/
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "hdr-histogram/hdr_histogram.h"
|
||||
#include "hdr-histogram/hdr_histogram_log.h"
|
||||
#include "hdr-histogram/hdr_tests.h"
|
||||
|
||||
#define UNUSED(x) (void)(x)
|
||||
|
||||
const char* hdr_strerror(int errnum)
|
||||
{
|
||||
switch (errnum)
|
||||
{
|
||||
case HDR_COMPRESSION_COOKIE_MISMATCH:
|
||||
return "Compression cookie mismatch";
|
||||
case HDR_ENCODING_COOKIE_MISMATCH:
|
||||
return "Encoding cookie mismatch";
|
||||
case HDR_DEFLATE_INIT_FAIL:
|
||||
return "Deflate initialisation failed";
|
||||
case HDR_DEFLATE_FAIL:
|
||||
return "Deflate failed";
|
||||
case HDR_INFLATE_INIT_FAIL:
|
||||
return "Inflate initialisation failed";
|
||||
case HDR_INFLATE_FAIL:
|
||||
return "Inflate failed";
|
||||
case HDR_LOG_INVALID_VERSION:
|
||||
return "Log - invalid version in log header";
|
||||
case HDR_TRAILING_ZEROS_INVALID:
|
||||
return "Invalid number of trailing zeros";
|
||||
case HDR_VALUE_TRUNCATED:
|
||||
return "Truncated value found when decoding";
|
||||
case HDR_ENCODED_INPUT_TOO_LONG:
|
||||
return "The encoded input exceeds the size of the histogram";
|
||||
default:
|
||||
return strerror(errnum);
|
||||
}
|
||||
}
|
||||
|
||||
int hdr_encode_compressed(
|
||||
struct hdr_histogram* h,
|
||||
uint8_t** compressed_histogram,
|
||||
size_t* compressed_len)
|
||||
{
|
||||
UNUSED(h);
|
||||
UNUSED(compressed_histogram);
|
||||
UNUSED(compressed_len);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int hdr_decode_compressed(
|
||||
uint8_t* buffer, size_t length, struct hdr_histogram** histogram)
|
||||
{
|
||||
UNUSED(buffer);
|
||||
UNUSED(length);
|
||||
UNUSED(histogram);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int hdr_log_writer_init(struct hdr_log_writer* writer)
|
||||
{
|
||||
UNUSED(writer);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int hdr_log_write_header(
|
||||
struct hdr_log_writer* writer, FILE* file,
|
||||
const char* user_prefix, hdr_timespec* timestamp)
|
||||
{
|
||||
UNUSED(writer);
|
||||
UNUSED(file);
|
||||
UNUSED(user_prefix);
|
||||
UNUSED(timestamp);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int hdr_log_write(
|
||||
struct hdr_log_writer* writer,
|
||||
FILE* file,
|
||||
const hdr_timespec* start_timestamp,
|
||||
const hdr_timespec* end_timestamp,
|
||||
struct hdr_histogram* histogram)
|
||||
{
|
||||
UNUSED(writer);
|
||||
UNUSED(file);
|
||||
UNUSED(start_timestamp);
|
||||
UNUSED(end_timestamp);
|
||||
UNUSED(histogram);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int hdr_log_write_entry(
|
||||
struct hdr_log_writer* writer,
|
||||
FILE* file,
|
||||
struct hdr_log_entry* entry,
|
||||
struct hdr_histogram* histogram)
|
||||
{
|
||||
UNUSED(writer);
|
||||
UNUSED(file);
|
||||
UNUSED(entry);
|
||||
UNUSED(histogram);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int hdr_log_reader_init(struct hdr_log_reader* reader)
|
||||
{
|
||||
UNUSED(reader);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int hdr_log_read_header(struct hdr_log_reader* reader, FILE* file)
|
||||
{
|
||||
UNUSED(reader);
|
||||
UNUSED(file);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int hdr_log_read(
|
||||
struct hdr_log_reader* reader, FILE* file, struct hdr_histogram** histogram,
|
||||
hdr_timespec* timestamp, hdr_timespec* interval)
|
||||
{
|
||||
UNUSED(reader);
|
||||
UNUSED(file);
|
||||
UNUSED(histogram);
|
||||
UNUSED(timestamp);
|
||||
UNUSED(interval);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int hdr_log_read_entry(
|
||||
struct hdr_log_reader* reader, FILE* file, struct hdr_log_entry *entry, struct hdr_histogram** histogram)
|
||||
{
|
||||
UNUSED(reader);
|
||||
UNUSED(file);
|
||||
UNUSED(entry);
|
||||
UNUSED(histogram);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int hdr_log_encode(struct hdr_histogram* histogram, char** encoded_histogram)
|
||||
{
|
||||
UNUSED(histogram);
|
||||
UNUSED(encoded_histogram);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int hdr_log_decode(struct hdr_histogram** histogram, char* base64_histogram, size_t base64_len)
|
||||
{
|
||||
UNUSED(histogram);
|
||||
UNUSED(base64_histogram);
|
||||
UNUSED(base64_len);
|
||||
|
||||
return -1;
|
||||
}
|
||||
12
src/main/hdr-histogram/hdr_histogram_version.h
Normal file
12
src/main/hdr-histogram/hdr_histogram_version.h
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
/**
|
||||
* hdr_histogram_version.h
|
||||
* Written by Marco Ippolito, Michael Barker and released to the public domain,
|
||||
* as explained at http://creativecommons.org/publicdomain/zero/1.0/
|
||||
*/
|
||||
|
||||
#ifndef HDR_HISTOGRAM_VERSION_H
|
||||
#define HDR_HISTOGRAM_VERSION_H
|
||||
|
||||
#define HDR_HISTOGRAM_VERSION "0.11.8"
|
||||
|
||||
#endif // HDR_HISTOGRAM_VERSION_H
|
||||
227
src/main/hdr-histogram/hdr_interval_recorder.c
Normal file
227
src/main/hdr-histogram/hdr_interval_recorder.c
Normal file
|
|
@ -0,0 +1,227 @@
|
|||
/**
|
||||
* hdr_interval_recorder.h
|
||||
* Written by Michael Barker and released to the public domain,
|
||||
* as explained at http://creativecommons.org/publicdomain/zero/1.0/
|
||||
*/
|
||||
|
||||
#include "hdr-histogram/hdr_interval_recorder.h"
|
||||
#include "hdr-histogram/hdr_atomic.h"
|
||||
|
||||
#ifndef HDR_MALLOC_INCLUDE
|
||||
#define HDR_MALLOC_INCLUDE "hdr-histogram/hdr_malloc.h"
|
||||
#endif
|
||||
|
||||
#include HDR_MALLOC_INCLUDE
|
||||
|
||||
int hdr_interval_recorder_init(struct hdr_interval_recorder* r)
|
||||
{
|
||||
r->active = r->inactive = NULL;
|
||||
return hdr_writer_reader_phaser_init(&r->phaser);
|
||||
}
|
||||
|
||||
int hdr_interval_recorder_init_all(
|
||||
struct hdr_interval_recorder* r,
|
||||
int64_t lowest_discernible_value,
|
||||
int64_t highest_trackable_value,
|
||||
int significant_figures)
|
||||
{
|
||||
int result;
|
||||
|
||||
r->active = r->inactive = NULL;
|
||||
result = hdr_writer_reader_phaser_init(&r->phaser);
|
||||
result = result == 0
|
||||
? hdr_init(lowest_discernible_value, highest_trackable_value, significant_figures, &r->active)
|
||||
: result;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void hdr_interval_recorder_destroy(struct hdr_interval_recorder* r)
|
||||
{
|
||||
hdr_writer_reader_phaser_destroy(&r->phaser);
|
||||
if (r->active) {
|
||||
hdr_close(r->active);
|
||||
}
|
||||
if (r->inactive) {
|
||||
hdr_close(r->inactive);
|
||||
}
|
||||
}
|
||||
|
||||
struct hdr_histogram* hdr_interval_recorder_sample_and_recycle(
|
||||
struct hdr_interval_recorder* r,
|
||||
struct hdr_histogram* histogram_to_recycle)
|
||||
{
|
||||
struct hdr_histogram* old_active;
|
||||
|
||||
if (NULL == histogram_to_recycle)
|
||||
{
|
||||
int64_t lo = r->active->lowest_discernible_value;
|
||||
int64_t hi = r->active->highest_trackable_value;
|
||||
int significant_figures = r->active->significant_figures;
|
||||
hdr_init(lo, hi, significant_figures, &histogram_to_recycle);
|
||||
}
|
||||
else
|
||||
{
|
||||
hdr_reset(histogram_to_recycle);
|
||||
}
|
||||
|
||||
hdr_phaser_reader_lock(&r->phaser);
|
||||
|
||||
/* volatile read */
|
||||
old_active = hdr_atomic_load_pointer(&r->active);
|
||||
|
||||
/* volatile write */
|
||||
hdr_atomic_store_pointer(&r->active, histogram_to_recycle);
|
||||
|
||||
hdr_phaser_flip_phase(&r->phaser, 0);
|
||||
|
||||
hdr_phaser_reader_unlock(&r->phaser);
|
||||
|
||||
return old_active;
|
||||
}
|
||||
|
||||
struct hdr_histogram* hdr_interval_recorder_sample(struct hdr_interval_recorder* r)
|
||||
{
|
||||
r->inactive = hdr_interval_recorder_sample_and_recycle(r, r->inactive);
|
||||
return r->inactive;
|
||||
}
|
||||
|
||||
static void hdr_interval_recorder_update(
|
||||
struct hdr_interval_recorder* r,
|
||||
void(*update_action)(struct hdr_histogram*, void*),
|
||||
void* arg)
|
||||
{
|
||||
int64_t val = hdr_phaser_writer_enter(&r->phaser);
|
||||
|
||||
void* active = hdr_atomic_load_pointer(&r->active);
|
||||
|
||||
update_action(active, arg);
|
||||
|
||||
hdr_phaser_writer_exit(&r->phaser, val);
|
||||
}
|
||||
|
||||
static void update_values(struct hdr_histogram* data, void* arg)
|
||||
{
|
||||
struct hdr_histogram* h = data;
|
||||
int64_t* params = arg;
|
||||
params[2] = hdr_record_values(h, params[0], params[1]);
|
||||
}
|
||||
|
||||
static void update_values_atomic(struct hdr_histogram* data, void* arg)
|
||||
{
|
||||
struct hdr_histogram* h = data;
|
||||
int64_t* params = arg;
|
||||
params[2] = hdr_record_values_atomic(h, params[0], params[1]);
|
||||
}
|
||||
|
||||
int64_t hdr_interval_recorder_record_values(
|
||||
struct hdr_interval_recorder* r,
|
||||
int64_t value,
|
||||
int64_t count
|
||||
)
|
||||
{
|
||||
int64_t params[3];
|
||||
params[0] = value;
|
||||
params[1] = count;
|
||||
params[2] = 0;
|
||||
|
||||
hdr_interval_recorder_update(r, update_values, ¶ms[0]);
|
||||
return params[2];
|
||||
}
|
||||
|
||||
int64_t hdr_interval_recorder_record_value(
|
||||
struct hdr_interval_recorder* r,
|
||||
int64_t value
|
||||
)
|
||||
{
|
||||
return hdr_interval_recorder_record_values(r, value, 1);
|
||||
}
|
||||
|
||||
static void update_corrected_values(struct hdr_histogram* data, void* arg)
|
||||
{
|
||||
struct hdr_histogram* h = data;
|
||||
int64_t* params = arg;
|
||||
params[3] = hdr_record_corrected_values(h, params[0], params[1], params[2]);
|
||||
}
|
||||
|
||||
static void update_corrected_values_atomic(struct hdr_histogram* data, void* arg)
|
||||
{
|
||||
struct hdr_histogram* h = data;
|
||||
int64_t* params = arg;
|
||||
params[3] = hdr_record_corrected_values_atomic(h, params[0], params[1], params[2]);
|
||||
}
|
||||
|
||||
int64_t hdr_interval_recorder_record_corrected_values(
|
||||
struct hdr_interval_recorder* r,
|
||||
int64_t value,
|
||||
int64_t count,
|
||||
int64_t expected_interval
|
||||
)
|
||||
{
|
||||
int64_t params[4];
|
||||
params[0] = value;
|
||||
params[1] = count;
|
||||
params[2] = expected_interval;
|
||||
params[3] = 0;
|
||||
|
||||
hdr_interval_recorder_update(r, update_corrected_values, ¶ms[0]);
|
||||
return params[3];
|
||||
}
|
||||
|
||||
int64_t hdr_interval_recorder_record_corrected_value(
|
||||
struct hdr_interval_recorder* r,
|
||||
int64_t value,
|
||||
int64_t expected_interval
|
||||
)
|
||||
{
|
||||
return hdr_interval_recorder_record_corrected_values(r, value, 1, expected_interval);
|
||||
}
|
||||
|
||||
int64_t hdr_interval_recorder_record_value_atomic(
|
||||
struct hdr_interval_recorder* r,
|
||||
int64_t value
|
||||
)
|
||||
{
|
||||
return hdr_interval_recorder_record_values_atomic(r, value, 1);
|
||||
}
|
||||
|
||||
int64_t hdr_interval_recorder_record_values_atomic(
|
||||
struct hdr_interval_recorder* r,
|
||||
int64_t value,
|
||||
int64_t count
|
||||
)
|
||||
{
|
||||
int64_t params[3];
|
||||
params[0] = value;
|
||||
params[1] = count;
|
||||
params[2] = 0;
|
||||
|
||||
hdr_interval_recorder_update(r, update_values_atomic, ¶ms[0]);
|
||||
return params[2];
|
||||
}
|
||||
|
||||
int64_t hdr_interval_recorder_record_corrected_value_atomic(
|
||||
struct hdr_interval_recorder* r,
|
||||
int64_t value,
|
||||
int64_t expected_interval
|
||||
)
|
||||
{
|
||||
return hdr_interval_recorder_record_corrected_values_atomic(r, value, 1, expected_interval);
|
||||
}
|
||||
|
||||
int64_t hdr_interval_recorder_record_corrected_values_atomic(
|
||||
struct hdr_interval_recorder* r,
|
||||
int64_t value,
|
||||
int64_t count,
|
||||
int64_t expected_interval
|
||||
)
|
||||
{
|
||||
int64_t params[4];
|
||||
params[0] = value;
|
||||
params[1] = count;
|
||||
params[2] = expected_interval;
|
||||
params[3] = 0;
|
||||
|
||||
hdr_interval_recorder_update(r, update_corrected_values_atomic, ¶ms[0]);
|
||||
return params[3];
|
||||
}
|
||||
109
src/main/hdr-histogram/hdr_interval_recorder.h
Normal file
109
src/main/hdr-histogram/hdr_interval_recorder.h
Normal file
|
|
@ -0,0 +1,109 @@
|
|||
/**
|
||||
* hdr_interval_recorder.h
|
||||
* Written by Michael Barker and released to the public domain,
|
||||
* as explained at http://creativecommons.org/publicdomain/zero/1.0/
|
||||
*/
|
||||
|
||||
#ifndef HDR_INTERVAL_RECORDER_H
|
||||
#define HDR_INTERVAL_RECORDER_H 1
|
||||
|
||||
#include "hdr-histogram/hdr_writer_reader_phaser.h"
|
||||
#include "hdr-histogram/hdr_histogram.h"
|
||||
|
||||
HDR_ALIGN_PREFIX(8)
|
||||
struct hdr_interval_recorder
|
||||
{
|
||||
struct hdr_histogram* active;
|
||||
struct hdr_histogram* inactive;
|
||||
struct hdr_writer_reader_phaser phaser;
|
||||
}
|
||||
HDR_ALIGN_SUFFIX(8);
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
int hdr_interval_recorder_init(struct hdr_interval_recorder* r);
|
||||
|
||||
int hdr_interval_recorder_init_all(
|
||||
struct hdr_interval_recorder* r,
|
||||
int64_t lowest_trackable_value,
|
||||
int64_t highest_trackable_value,
|
||||
int significant_figures);
|
||||
|
||||
void hdr_interval_recorder_destroy(struct hdr_interval_recorder* r);
|
||||
|
||||
int64_t hdr_interval_recorder_record_value(
|
||||
struct hdr_interval_recorder* r,
|
||||
int64_t value
|
||||
);
|
||||
|
||||
int64_t hdr_interval_recorder_record_values(
|
||||
struct hdr_interval_recorder* r,
|
||||
int64_t value,
|
||||
int64_t count
|
||||
);
|
||||
|
||||
int64_t hdr_interval_recorder_record_corrected_value(
|
||||
struct hdr_interval_recorder* r,
|
||||
int64_t value,
|
||||
int64_t expected_interval
|
||||
);
|
||||
|
||||
int64_t hdr_interval_recorder_record_corrected_values(
|
||||
struct hdr_interval_recorder* r,
|
||||
int64_t value,
|
||||
int64_t count,
|
||||
int64_t expected_interval
|
||||
);
|
||||
|
||||
int64_t hdr_interval_recorder_record_value_atomic(
|
||||
struct hdr_interval_recorder* r,
|
||||
int64_t value
|
||||
);
|
||||
|
||||
int64_t hdr_interval_recorder_record_values_atomic(
|
||||
struct hdr_interval_recorder* r,
|
||||
int64_t value,
|
||||
int64_t count
|
||||
);
|
||||
|
||||
int64_t hdr_interval_recorder_record_corrected_value_atomic(
|
||||
struct hdr_interval_recorder* r,
|
||||
int64_t value,
|
||||
int64_t expected_interval
|
||||
);
|
||||
|
||||
int64_t hdr_interval_recorder_record_corrected_values_atomic(
|
||||
struct hdr_interval_recorder* r,
|
||||
int64_t value,
|
||||
int64_t count,
|
||||
int64_t expected_interval
|
||||
);
|
||||
|
||||
/**
|
||||
* This is generally the preferred approach for recycling histograms through
|
||||
* the recorder as it is safe when used from callers in multiple threads and
|
||||
* the returned histogram won't automatically become active without being
|
||||
* passed back into this method.
|
||||
*
|
||||
* @param r 'this' recorder
|
||||
* @param histogram_to_recycle
|
||||
* @return the histogram that was previous being recorded to.
|
||||
*/
|
||||
struct hdr_histogram* hdr_interval_recorder_sample_and_recycle(
|
||||
struct hdr_interval_recorder* r,
|
||||
struct hdr_histogram* histogram_to_recycle);
|
||||
|
||||
/**
|
||||
* @deprecated Prefer hdr_interval_recorder_sample_and_recycle
|
||||
* @param r 'this' recorder
|
||||
* @return the histogram that was previous being recorded to.
|
||||
*/
|
||||
struct hdr_histogram* hdr_interval_recorder_sample(struct hdr_interval_recorder* r);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
19
src/main/hdr-histogram/hdr_malloc.h
Normal file
19
src/main/hdr-histogram/hdr_malloc.h
Normal file
|
|
@ -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
|
||||
22
src/main/hdr-histogram/hdr_tests.h
Normal file
22
src/main/hdr-histogram/hdr_tests.h
Normal file
|
|
@ -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-histogram/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
|
||||
108
src/main/hdr-histogram/hdr_thread.c
Normal file
108
src/main/hdr-histogram/hdr_thread.c
Normal file
|
|
@ -0,0 +1,108 @@
|
|||
/**
|
||||
* hdr_thread.c
|
||||
* Written by Philip Orwig and released to the public domain,
|
||||
* as explained at http://creativecommons.org/publicdomain/zero/1.0/
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include "hdr-histogram/hdr_thread.h"
|
||||
|
||||
#ifndef HDR_MALLOC_INCLUDE
|
||||
#define HDR_MALLOC_INCLUDE "hdr-histogram/hdr_malloc.h"
|
||||
#endif
|
||||
|
||||
#include HDR_MALLOC_INCLUDE
|
||||
|
||||
struct hdr_mutex* hdr_mutex_alloc(void)
|
||||
{
|
||||
return hdr_malloc(sizeof(hdr_mutex));
|
||||
}
|
||||
|
||||
void hdr_mutex_free(struct hdr_mutex* mutex)
|
||||
{
|
||||
hdr_free(mutex);
|
||||
}
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64) || defined(__CYGWIN__)
|
||||
|
||||
#if !defined(WIN32_LEAN_AND_MEAN)
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#endif
|
||||
|
||||
#include <windows.h>
|
||||
#include <WinSock2.h>
|
||||
|
||||
int hdr_mutex_init(struct hdr_mutex* mutex)
|
||||
{
|
||||
InitializeCriticalSection((CRITICAL_SECTION*)(mutex->_critical_section));
|
||||
return 0;
|
||||
}
|
||||
|
||||
void hdr_mutex_destroy(struct hdr_mutex* mutex)
|
||||
{
|
||||
DeleteCriticalSection((CRITICAL_SECTION*)(mutex->_critical_section));
|
||||
}
|
||||
|
||||
void hdr_mutex_lock(struct hdr_mutex* mutex)
|
||||
{
|
||||
EnterCriticalSection((CRITICAL_SECTION*)(mutex->_critical_section));
|
||||
}
|
||||
|
||||
void hdr_mutex_unlock(struct hdr_mutex* mutex)
|
||||
{
|
||||
LeaveCriticalSection((CRITICAL_SECTION*)(mutex->_critical_section));
|
||||
}
|
||||
|
||||
void hdr_yield()
|
||||
{
|
||||
Sleep(0);
|
||||
}
|
||||
|
||||
int hdr_usleep(unsigned int useconds)
|
||||
{
|
||||
struct timeval tv;
|
||||
|
||||
tv.tv_sec = (long)useconds / 1000000;
|
||||
tv.tv_usec = useconds % 1000000;
|
||||
select(0, NULL, NULL, NULL, &tv);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#else
|
||||
#include <pthread.h>
|
||||
#include <unistd.h>
|
||||
|
||||
int hdr_mutex_init(struct hdr_mutex* mutex)
|
||||
{
|
||||
return pthread_mutex_init(&mutex->_mutex, NULL);
|
||||
}
|
||||
|
||||
void hdr_mutex_destroy(struct hdr_mutex* mutex)
|
||||
{
|
||||
pthread_mutex_destroy(&mutex->_mutex);
|
||||
}
|
||||
|
||||
void hdr_mutex_lock(struct hdr_mutex* mutex)
|
||||
{
|
||||
pthread_mutex_lock(&mutex->_mutex);
|
||||
}
|
||||
|
||||
void hdr_mutex_unlock(struct hdr_mutex* mutex)
|
||||
{
|
||||
pthread_mutex_unlock(&mutex->_mutex);
|
||||
}
|
||||
|
||||
void hdr_yield(void)
|
||||
{
|
||||
sched_yield();
|
||||
}
|
||||
|
||||
int hdr_usleep(unsigned int useconds)
|
||||
{
|
||||
return usleep(useconds);
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
55
src/main/hdr-histogram/hdr_thread.h
Normal file
55
src/main/hdr-histogram/hdr_thread.h
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
/**
|
||||
* hdr_thread.h
|
||||
* Written by Philip Orwig and released to the public domain,
|
||||
* as explained at http://creativecommons.org/publicdomain/zero/1.0/
|
||||
*/
|
||||
|
||||
#ifndef HDR_THREAD_H__
|
||||
#define HDR_THREAD_H__
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64) || defined(__CYGWIN__)
|
||||
|
||||
|
||||
#define HDR_ALIGN_PREFIX(alignment) __declspec( align(alignment) )
|
||||
#define HDR_ALIGN_SUFFIX(alignment)
|
||||
|
||||
typedef struct hdr_mutex
|
||||
{
|
||||
uint8_t _critical_section[40];
|
||||
} hdr_mutex;
|
||||
|
||||
#else
|
||||
|
||||
#include <pthread.h>
|
||||
|
||||
#define HDR_ALIGN_PREFIX(alignment)
|
||||
#define HDR_ALIGN_SUFFIX(alignment) __attribute__((aligned(alignment)))
|
||||
|
||||
typedef struct hdr_mutex
|
||||
{
|
||||
pthread_mutex_t _mutex;
|
||||
} hdr_mutex;
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct hdr_mutex* hdr_mutex_alloc(void);
|
||||
void hdr_mutex_free(struct hdr_mutex*);
|
||||
|
||||
int hdr_mutex_init(struct hdr_mutex* mutex);
|
||||
void hdr_mutex_destroy(struct hdr_mutex* mutex);
|
||||
|
||||
void hdr_mutex_lock(struct hdr_mutex* mutex);
|
||||
void hdr_mutex_unlock(struct hdr_mutex* mutex);
|
||||
|
||||
void hdr_yield(void);
|
||||
int hdr_usleep(unsigned int useconds);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
107
src/main/hdr-histogram/hdr_time.c
Normal file
107
src/main/hdr-histogram/hdr_time.c
Normal file
|
|
@ -0,0 +1,107 @@
|
|||
/**
|
||||
* 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-histogram/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;
|
||||
}
|
||||
|
||||
int64_t hdr_timespec_diff_us(const hdr_timespec* t0, const hdr_timespec* t1)
|
||||
{
|
||||
int64_t delta_us;
|
||||
|
||||
delta_us = (t1->tv_sec - t0->tv_sec) * 1000000;
|
||||
delta_us += (t1->tv_nsec - t0->tv_nsec) / 1000;
|
||||
|
||||
return delta_us;
|
||||
}
|
||||
50
src/main/hdr-histogram/hdr_time.h
Normal file
50
src/main/hdr-histogram/hdr_time.h
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
/**
|
||||
* 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 <stdint.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);
|
||||
|
||||
int64_t hdr_timespec_diff_us(const hdr_timespec* t0, const hdr_timespec* t1);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
142
src/main/hdr-histogram/hdr_writer_reader_phaser.c
Normal file
142
src/main/hdr-histogram/hdr_writer_reader_phaser.c
Normal file
|
|
@ -0,0 +1,142 @@
|
|||
/**
|
||||
* hdr_writer_reader_phaser.h
|
||||
* Written by Michael Barker and released to the public domain,
|
||||
* as explained at http://creativecommons.org/publicdomain/zero/1.0/
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "hdr-histogram/hdr_thread.h"
|
||||
#include "hdr-histogram/hdr_writer_reader_phaser.h"
|
||||
#include "hdr-histogram/hdr_atomic.h"
|
||||
|
||||
#ifndef HDR_MALLOC_INCLUDE
|
||||
#define HDR_MALLOC_INCLUDE "hdr-histogram/hdr_malloc.h"
|
||||
#endif
|
||||
|
||||
#include HDR_MALLOC_INCLUDE
|
||||
|
||||
static int64_t _hdr_phaser_get_epoch(int64_t* field)
|
||||
{
|
||||
return hdr_atomic_load_64(field);
|
||||
}
|
||||
|
||||
static void _hdr_phaser_set_epoch(int64_t* field, int64_t val)
|
||||
{
|
||||
hdr_atomic_store_64(field, val);
|
||||
}
|
||||
|
||||
static int64_t _hdr_phaser_reset_epoch(int64_t* field, int64_t initial_value)
|
||||
{
|
||||
return hdr_atomic_exchange_64(field, initial_value);
|
||||
}
|
||||
|
||||
int hdr_writer_reader_phaser_init(struct hdr_writer_reader_phaser* p)
|
||||
{
|
||||
int rc;
|
||||
if (NULL == p)
|
||||
{
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
p->start_epoch = 0;
|
||||
p->even_end_epoch = 0;
|
||||
p->odd_end_epoch = INT64_MIN;
|
||||
p->reader_mutex = hdr_mutex_alloc();
|
||||
|
||||
if (!p->reader_mutex)
|
||||
{
|
||||
return ENOMEM;
|
||||
}
|
||||
|
||||
rc = hdr_mutex_init(p->reader_mutex);
|
||||
if (0 != rc)
|
||||
{
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* TODO: Should I fence here. */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void hdr_writer_reader_phaser_destroy(struct hdr_writer_reader_phaser* p)
|
||||
{
|
||||
hdr_mutex_destroy(p->reader_mutex);
|
||||
hdr_mutex_free(p->reader_mutex);
|
||||
}
|
||||
|
||||
int64_t hdr_phaser_writer_enter(struct hdr_writer_reader_phaser* p)
|
||||
{
|
||||
return hdr_atomic_add_fetch_64(&p->start_epoch, 1);
|
||||
}
|
||||
|
||||
void hdr_phaser_writer_exit(
|
||||
struct hdr_writer_reader_phaser* p, int64_t critical_value_at_enter)
|
||||
{
|
||||
int64_t* end_epoch =
|
||||
(critical_value_at_enter < 0) ? &p->odd_end_epoch : &p->even_end_epoch;
|
||||
hdr_atomic_add_fetch_64(end_epoch, 1);
|
||||
}
|
||||
|
||||
void hdr_phaser_reader_lock(struct hdr_writer_reader_phaser* p)
|
||||
{
|
||||
hdr_mutex_lock(p->reader_mutex);
|
||||
}
|
||||
|
||||
void hdr_phaser_reader_unlock(struct hdr_writer_reader_phaser* p)
|
||||
{
|
||||
hdr_mutex_unlock(p->reader_mutex);
|
||||
}
|
||||
|
||||
void hdr_phaser_flip_phase(
|
||||
struct hdr_writer_reader_phaser* p, int64_t sleep_time_ns)
|
||||
{
|
||||
bool caught_up;
|
||||
int64_t start_value_at_flip;
|
||||
/* TODO: is_held_by_current_thread */
|
||||
unsigned int sleep_time_us = sleep_time_ns < 1000000000 ? (unsigned int) (sleep_time_ns / 1000) : 1000000;
|
||||
|
||||
int64_t start_epoch = _hdr_phaser_get_epoch(&p->start_epoch);
|
||||
|
||||
bool next_phase_is_even = (start_epoch < 0);
|
||||
|
||||
/* Clear currently used phase end epoch.*/
|
||||
int64_t initial_start_value;
|
||||
if (next_phase_is_even)
|
||||
{
|
||||
initial_start_value = 0;
|
||||
_hdr_phaser_set_epoch(&p->even_end_epoch, initial_start_value);
|
||||
}
|
||||
else
|
||||
{
|
||||
initial_start_value = INT64_MIN;
|
||||
_hdr_phaser_set_epoch(&p->odd_end_epoch, initial_start_value);
|
||||
}
|
||||
|
||||
/* Reset start value, indicating new phase.*/
|
||||
start_value_at_flip = _hdr_phaser_reset_epoch(&p->start_epoch, initial_start_value);
|
||||
|
||||
do
|
||||
{
|
||||
int64_t* end_epoch =
|
||||
next_phase_is_even ? &p->odd_end_epoch : &p->even_end_epoch;
|
||||
|
||||
caught_up = _hdr_phaser_get_epoch(end_epoch) == start_value_at_flip;
|
||||
|
||||
if (!caught_up)
|
||||
{
|
||||
if (sleep_time_us <= 0)
|
||||
{
|
||||
hdr_yield();
|
||||
}
|
||||
else
|
||||
{
|
||||
hdr_usleep(sleep_time_us);
|
||||
}
|
||||
}
|
||||
}
|
||||
while (!caught_up);
|
||||
}
|
||||
51
src/main/hdr-histogram/hdr_writer_reader_phaser.h
Normal file
51
src/main/hdr-histogram/hdr_writer_reader_phaser.h
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
/**
|
||||
* hdr_writer_reader_phaser.h
|
||||
* Written by Michael Barker and released to the public domain,
|
||||
* as explained at http://creativecommons.org/publicdomain/zero/1.0/
|
||||
*/
|
||||
|
||||
#ifndef HDR_WRITER_READER_PHASER_H
|
||||
#define HDR_WRITER_READER_PHASER_H 1
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "hdr-histogram/hdr_thread.h"
|
||||
|
||||
HDR_ALIGN_PREFIX(8)
|
||||
struct hdr_writer_reader_phaser
|
||||
{
|
||||
int64_t start_epoch;
|
||||
int64_t even_end_epoch;
|
||||
int64_t odd_end_epoch;
|
||||
hdr_mutex* reader_mutex;
|
||||
}
|
||||
HDR_ALIGN_SUFFIX(8);
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
int hdr_writer_reader_phaser_init(struct hdr_writer_reader_phaser* p);
|
||||
|
||||
void hdr_writer_reader_phaser_destroy(struct hdr_writer_reader_phaser* p);
|
||||
|
||||
int64_t hdr_phaser_writer_enter(struct hdr_writer_reader_phaser* p);
|
||||
|
||||
void hdr_phaser_writer_exit(
|
||||
struct hdr_writer_reader_phaser* p, int64_t critical_value_at_enter);
|
||||
|
||||
void hdr_phaser_reader_lock(struct hdr_writer_reader_phaser* p);
|
||||
|
||||
void hdr_phaser_reader_unlock(struct hdr_writer_reader_phaser* p);
|
||||
|
||||
void hdr_phaser_flip_phase(
|
||||
struct hdr_writer_reader_phaser* p, int64_t sleep_time_ns);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
9
src/main/iidxio-async/Module.mk
Normal file
9
src/main/iidxio-async/Module.mk
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
dlls += iidxio-async
|
||||
|
||||
ldflags_iidxio-async := \
|
||||
|
||||
libs_iidxio-async := \
|
||||
util \
|
||||
|
||||
src_iidxio-async := \
|
||||
iidxio.c \
|
||||
18
src/main/iidxio-async/iidxio-async.def
Normal file
18
src/main/iidxio-async/iidxio-async.def
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
LIBRARY iidxio
|
||||
|
||||
EXPORTS
|
||||
iidx_io_ep1_send
|
||||
iidx_io_ep1_set_deck_lights
|
||||
iidx_io_ep1_set_panel_lights
|
||||
iidx_io_ep1_set_top_lamps
|
||||
iidx_io_ep1_set_top_neons
|
||||
iidx_io_ep2_get_keys
|
||||
iidx_io_ep2_get_panel
|
||||
iidx_io_ep2_get_sys
|
||||
iidx_io_ep2_get_slider
|
||||
iidx_io_ep2_get_turntable
|
||||
iidx_io_ep2_recv
|
||||
iidx_io_ep3_write_16seg
|
||||
iidx_io_fini
|
||||
iidx_io_init
|
||||
iidx_io_set_loggers
|
||||
414
src/main/iidxio-async/iidxio.c
Normal file
414
src/main/iidxio-async/iidxio.c
Normal file
|
|
@ -0,0 +1,414 @@
|
|||
#define LOG_MODULE "iidxio-async"
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include <stdatomic.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "bemanitools/iidxio.h"
|
||||
|
||||
#include "util/log.h"
|
||||
#include "util/thread.h"
|
||||
#include "util/time.h"
|
||||
|
||||
typedef void (*iidx_io_set_loggers_t)(
|
||||
log_formatter_t misc,
|
||||
log_formatter_t info,
|
||||
log_formatter_t warning,
|
||||
log_formatter_t fatal);
|
||||
typedef bool (*iidx_io_init_t)(
|
||||
thread_create_t thread_create,
|
||||
thread_join_t thread_join,
|
||||
thread_destroy_t thread_destroy);
|
||||
typedef void (*iidx_io_fini_t)(void);
|
||||
typedef void (*iidx_io_ep1_set_deck_lights_t)(uint16_t deck_lights);
|
||||
typedef void (*iidx_io_ep1_set_panel_lights_t)(uint8_t panel_lights);
|
||||
typedef void (*iidx_io_ep1_set_top_lamps_t)(uint8_t top_lamps);
|
||||
typedef void (*iidx_io_ep1_set_top_neons_t)(bool top_neons);
|
||||
typedef bool (*iidx_io_ep1_send_t)(void);
|
||||
typedef bool (*iidx_io_ep2_recv_t)(void);
|
||||
typedef uint8_t (*iidx_io_ep2_get_turntable_t)(uint8_t player_no);
|
||||
typedef uint8_t (*iidx_io_ep2_get_slider_t)(uint8_t slider_no);
|
||||
typedef uint8_t (*iidx_io_ep2_get_sys_t)(void);
|
||||
typedef uint8_t (*iidx_io_ep2_get_panel_t)(void);
|
||||
typedef uint16_t (*iidx_io_ep2_get_keys_t)(void);
|
||||
typedef bool (*iidx_io_ep3_write_16seg_t)(const char *text);
|
||||
|
||||
static HMODULE _child_iidx_io_module;
|
||||
|
||||
static iidx_io_set_loggers_t _child_iidx_io_set_loggers;
|
||||
static iidx_io_init_t _child_iidx_io_init;
|
||||
static iidx_io_fini_t _child_iidx_io_fini;
|
||||
|
||||
static iidx_io_ep1_set_deck_lights_t _child_iidx_io_ep1_set_deck_lights;
|
||||
static iidx_io_ep1_set_panel_lights_t _child_iidx_io_ep1_set_panel_lights;
|
||||
static iidx_io_ep1_set_top_lamps_t _child_iidx_io_ep1_set_top_lamps;
|
||||
static iidx_io_ep1_set_top_neons_t _child_iidx_io_ep1_set_top_neons;
|
||||
static iidx_io_ep1_send_t _child_iidx_io_ep1_send;
|
||||
static iidx_io_ep2_recv_t _child_iidx_io_ep2_recv;
|
||||
static iidx_io_ep2_get_turntable_t _child_iidx_io_ep2_get_turntable;
|
||||
static iidx_io_ep2_get_slider_t _child_iidx_io_ep2_get_slider;
|
||||
static iidx_io_ep2_get_sys_t _child_iidx_io_ep2_get_sys;
|
||||
static iidx_io_ep2_get_panel_t _child_iidx_io_ep2_get_panel;
|
||||
static iidx_io_ep2_get_keys_t _child_iidx_io_ep2_get_keys;
|
||||
static iidx_io_ep3_write_16seg_t _child_iidx_io_ep3_write_16seg;
|
||||
|
||||
static log_formatter_t _log_formatter_misc;
|
||||
static log_formatter_t _log_formatter_info;
|
||||
static log_formatter_t _log_formatter_warning;
|
||||
static log_formatter_t _log_formatter_fatal;
|
||||
|
||||
static _Atomic(bool) _io_thread_proc_loop;
|
||||
static _Atomic(bool) _io_thread_proc_running;
|
||||
|
||||
static _Atomic(uint16_t) _child_iidx_io_deck_lights;
|
||||
static _Atomic(uint8_t) _child_iidx_io_panel_lights;
|
||||
static _Atomic(uint8_t) _child_iidx_io_top_lamps;
|
||||
static _Atomic(bool) _child_iidx_io_top_neons;
|
||||
|
||||
static _Atomic(uint8_t) _child_iidx_io_turntable_p1;
|
||||
static _Atomic(uint8_t) _child_iidx_io_turntable_p2;
|
||||
static _Atomic(uint8_t) _child_iidx_io_slider_1;
|
||||
static _Atomic(uint8_t) _child_iidx_io_slider_2;
|
||||
static _Atomic(uint8_t) _child_iidx_io_slider_3;
|
||||
static _Atomic(uint8_t) _child_iidx_io_slider_4;
|
||||
static _Atomic(uint8_t) _child_iidx_io_slider_5;
|
||||
static _Atomic(uint8_t) _child_iidx_io_sys;
|
||||
static _Atomic(uint8_t) _child_iidx_io_panel;
|
||||
static _Atomic(uint16_t) _child_iidx_io_keys;
|
||||
|
||||
static int _io_thread_proc(void *ctx)
|
||||
{
|
||||
uint64_t time_start;
|
||||
uint64_t time_end;
|
||||
uint64_t loop_counter;
|
||||
uint64_t total_time;
|
||||
|
||||
bool result;
|
||||
|
||||
// TODO compare previous outputs with new ones and only apply if changed? doesn't make sense for iidx as setting the values is not supposed to trigger any actual IO driving
|
||||
// uint32_t prev_child_ddr_io_data_extio_lights;
|
||||
// uint32_t prev_child_ddr_io_data_p3io_lights;
|
||||
|
||||
// uint32_t local_tmp;
|
||||
|
||||
atomic_store_explicit(&_io_thread_proc_running, true, memory_order_seq_cst);
|
||||
|
||||
log_info("IO thread running");
|
||||
|
||||
time_start = time_get_counter();
|
||||
loop_counter = 0;
|
||||
|
||||
// TODO have a setting to configure polling rates of inputs, outputs and 16seg separately
|
||||
while (atomic_load_explicit(&_io_thread_proc_loop, memory_order_seq_cst)) {
|
||||
// TODO measure time of expensive calls independently
|
||||
result = _child_iidx_io_ep2_recv();
|
||||
|
||||
if (!result) {
|
||||
log_warning("_child_iidx_io_ep2_recv returned false");
|
||||
atomic_store_explicit(
|
||||
&_io_thread_proc_running, false, memory_order_seq_cst);
|
||||
|
||||
log_info("IO thread shut down");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
atomic_store_explicit(&_child_iidx_io_turntable_p1, _child_iidx_io_ep2_get_turntable(0), memory_order_relaxed);
|
||||
atomic_store_explicit(&_child_iidx_io_turntable_p2, _child_iidx_io_ep2_get_turntable(1), memory_order_relaxed);
|
||||
atomic_store_explicit(&_child_iidx_io_slider_1, _child_iidx_io_ep2_get_slider(0), memory_order_relaxed);
|
||||
atomic_store_explicit(&_child_iidx_io_slider_2, _child_iidx_io_ep2_get_slider(1), memory_order_relaxed);
|
||||
atomic_store_explicit(&_child_iidx_io_slider_3, _child_iidx_io_ep2_get_slider(2), memory_order_relaxed);
|
||||
atomic_store_explicit(&_child_iidx_io_slider_4, _child_iidx_io_ep2_get_slider(3), memory_order_relaxed);
|
||||
atomic_store_explicit(&_child_iidx_io_slider_5, _child_iidx_io_ep2_get_slider(4), memory_order_relaxed);
|
||||
atomic_store_explicit(&_child_iidx_io_sys, _child_iidx_io_ep2_get_sys(), memory_order_relaxed);
|
||||
atomic_store_explicit(&_child_iidx_io_panel, _child_iidx_io_ep2_get_panel(), memory_order_relaxed);
|
||||
atomic_store_explicit(&_child_iidx_io_keys, _child_iidx_io_ep2_get_keys(), memory_order_relaxed);
|
||||
|
||||
_child_iidx_io_ep1_set_deck_lights(atomic_load_explicit(&_child_iidx_io_deck_lights, memory_order_relaxed));
|
||||
_child_iidx_io_ep1_set_panel_lights(atomic_load_explicit(&_child_iidx_io_panel_lights, memory_order_relaxed));
|
||||
_child_iidx_io_ep1_set_top_lamps(atomic_load_explicit(&_child_iidx_io_top_lamps, memory_order_relaxed));
|
||||
_child_iidx_io_ep1_set_top_neons(atomic_load_explicit(&_child_iidx_io_top_neons, memory_order_relaxed));
|
||||
|
||||
// TODO guard and only update every X loops? -> configurable?
|
||||
result = _child_iidx_io_ep1_send();
|
||||
|
||||
if (!result) {
|
||||
log_warning("_child_iidx_io_ep1_send returned false");
|
||||
atomic_store_explicit(
|
||||
&_io_thread_proc_running, false, memory_order_seq_cst);
|
||||
|
||||
log_info("IO thread shut down");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// TODO atomic write of 16seg with mutex?
|
||||
// result = _child_iidx_io_ep3_write_16seg();
|
||||
|
||||
// if (!result) {
|
||||
// log_warning("_child_iidx_io_ep3_write_16seg returned false");
|
||||
// atomic_store_explicit(
|
||||
// &_io_thread_proc_running, false, memory_order_seq_cst);
|
||||
|
||||
// log_info("IO thread shut down");
|
||||
|
||||
// return 0;
|
||||
// }
|
||||
|
||||
// local_tmp = _child_ddr_io_read_pad();
|
||||
|
||||
// atomic_store_explicit(
|
||||
// &_child_ddr_io_data_pad, local_tmp, memory_order_relaxed);
|
||||
|
||||
|
||||
// local_tmp = atomic_load_explicit(
|
||||
// &_child_ddr_io_data_extio_lights, memory_order_relaxed);
|
||||
|
||||
// if (local_tmp != prev_child_ddr_io_data_extio_lights) {
|
||||
// _child_ddr_io_set_lights_extio(local_tmp);
|
||||
// prev_child_ddr_io_data_extio_lights = local_tmp;
|
||||
// }
|
||||
|
||||
// local_tmp = atomic_load_explicit(
|
||||
// &_child_ddr_io_data_p3io_lights, memory_order_relaxed);
|
||||
|
||||
// if (local_tmp != prev_child_ddr_io_data_p3io_lights) {
|
||||
// _child_ddr_io_set_lights_p3io(local_tmp);
|
||||
// prev_child_ddr_io_data_p3io_lights = local_tmp;
|
||||
// }
|
||||
|
||||
// Don't hog the CPU
|
||||
SwitchToThread();
|
||||
|
||||
loop_counter++;
|
||||
}
|
||||
|
||||
time_end = time_get_counter();
|
||||
total_time = time_get_elapsed_us(time_end - time_start);
|
||||
|
||||
log_info(
|
||||
"IO thread performance: total iterations %lld, avg. loop cycle time %f "
|
||||
"us",
|
||||
loop_counter,
|
||||
((double) total_time) / loop_counter);
|
||||
|
||||
atomic_store_explicit(
|
||||
&_io_thread_proc_running, false, memory_order_seq_cst);
|
||||
|
||||
log_info("IO thread shut down");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void *_load_function(HMODULE module, const char *name)
|
||||
{
|
||||
void *ptr;
|
||||
|
||||
ptr = GetProcAddress(module, name);
|
||||
|
||||
if (ptr == NULL) {
|
||||
log_fatal("Could not find function %s in iidxio child library", name);
|
||||
}
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void iidx_io_set_loggers(
|
||||
log_formatter_t misc,
|
||||
log_formatter_t info,
|
||||
log_formatter_t warning,
|
||||
log_formatter_t fatal)
|
||||
{
|
||||
_log_formatter_misc = misc;
|
||||
_log_formatter_info = info;
|
||||
_log_formatter_warning = warning;
|
||||
_log_formatter_fatal = fatal;
|
||||
|
||||
log_to_external(misc, info, warning, fatal);
|
||||
}
|
||||
|
||||
bool iidx_io_init(
|
||||
thread_create_t thread_create,
|
||||
thread_join_t thread_join,
|
||||
thread_destroy_t thread_destroy)
|
||||
{
|
||||
log_info("Loading iidxio-async-child.dll as child iidxio library...");
|
||||
|
||||
_child_iidx_io_module = LoadLibraryA("iidxio-async-child.dll");
|
||||
|
||||
if (_child_iidx_io_module == NULL) {
|
||||
log_warning("Loading iidxio-async-child.dll failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
_child_iidx_io_set_loggers =
|
||||
_load_function(_child_iidx_io_module, "iidx_io_set_loggers");
|
||||
_child_iidx_io_init = _load_function(_child_iidx_io_module, "iidx_io_init");
|
||||
_child_iidx_io_fini = _load_function(_child_iidx_io_module, "iidx_io_fini");
|
||||
|
||||
_child_iidx_io_ep1_set_deck_lights =
|
||||
_load_function(_child_iidx_io_module, "iidx_io_ep1_set_deck_lights");
|
||||
_child_iidx_io_ep1_set_panel_lights =
|
||||
_load_function(_child_iidx_io_module, "iidx_io_ep1_set_panel_lights");
|
||||
_child_iidx_io_ep1_set_top_lamps =
|
||||
_load_function(_child_iidx_io_module, "iidx_io_ep1_set_top_lamps");
|
||||
_child_iidx_io_ep1_set_top_neons =
|
||||
_load_function(_child_iidx_io_module, "iidx_io_ep1_set_top_neons");
|
||||
_child_iidx_io_ep1_send =
|
||||
_load_function(_child_iidx_io_module, "iidx_io_ep1_send");
|
||||
_child_iidx_io_ep2_recv =
|
||||
_load_function(_child_iidx_io_module, "iidx_io_ep2_recv");
|
||||
_child_iidx_io_ep2_get_turntable =
|
||||
_load_function(_child_iidx_io_module, "iidx_io_ep2_get_turntable");
|
||||
_child_iidx_io_ep2_get_slider =
|
||||
_load_function(_child_iidx_io_module, "iidx_io_ep2_get_slider");
|
||||
_child_iidx_io_ep2_get_sys =
|
||||
_load_function(_child_iidx_io_module, "iidx_io_ep2_get_sys");
|
||||
_child_iidx_io_ep2_get_panel =
|
||||
_load_function(_child_iidx_io_module, "iidx_io_ep2_get_panel");
|
||||
_child_iidx_io_ep2_get_keys =
|
||||
_load_function(_child_iidx_io_module, "iidx_io_ep2_get_keys");
|
||||
_child_iidx_io_ep3_write_16seg =
|
||||
_load_function(_child_iidx_io_module, "iidx_io_ep3_write_16seg");
|
||||
|
||||
_child_iidx_io_set_loggers(
|
||||
_log_formatter_misc,
|
||||
_log_formatter_info,
|
||||
_log_formatter_warning,
|
||||
_log_formatter_fatal);
|
||||
|
||||
log_info("Calling child iidx_io_init...");
|
||||
|
||||
if (!_child_iidx_io_init(thread_create, thread_join, thread_destroy)) {
|
||||
log_warning("Child iidx_io_init failed");
|
||||
FreeLibrary(_child_iidx_io_module);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
atomic_store_explicit(&_io_thread_proc_loop, true, memory_order_seq_cst);
|
||||
|
||||
if (!thread_create(_io_thread_proc, NULL, 16384, 0)) {
|
||||
log_warning("Creating IO thread failed");
|
||||
|
||||
_child_iidx_io_fini();
|
||||
FreeLibrary(_child_iidx_io_module);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void iidx_io_fini(void)
|
||||
{
|
||||
atomic_store_explicit(&_io_thread_proc_loop, false, memory_order_seq_cst);
|
||||
|
||||
log_info("Shutting down IO thread and waiting for it to finish...");
|
||||
|
||||
while (
|
||||
atomic_load_explicit(&_io_thread_proc_running, memory_order_seq_cst)) {
|
||||
Sleep(1);
|
||||
}
|
||||
|
||||
log_info("IO thread finished");
|
||||
|
||||
_child_iidx_io_fini();
|
||||
|
||||
FreeLibrary(_child_iidx_io_module);
|
||||
}
|
||||
|
||||
void iidx_io_ep1_set_deck_lights(uint16_t deck_lights)
|
||||
{
|
||||
atomic_store_explicit(
|
||||
&_child_iidx_io_deck_lights, deck_lights, memory_order_relaxed);
|
||||
}
|
||||
|
||||
void iidx_io_ep1_set_panel_lights(uint8_t panel_lights)
|
||||
{
|
||||
atomic_store_explicit(
|
||||
&_child_iidx_io_panel_lights, panel_lights, memory_order_relaxed);
|
||||
}
|
||||
|
||||
void iidx_io_ep1_set_top_lamps(uint8_t top_lamps)
|
||||
{
|
||||
atomic_store_explicit(
|
||||
&_child_iidx_io_top_lamps, top_lamps, memory_order_relaxed);
|
||||
}
|
||||
|
||||
void iidx_io_ep1_set_top_neons(bool top_neons)
|
||||
{
|
||||
atomic_store_explicit(
|
||||
&_child_iidx_io_top_neons, top_neons, memory_order_relaxed);
|
||||
}
|
||||
|
||||
bool iidx_io_ep1_send(void)
|
||||
{
|
||||
// Any sending and receiving is executed async in a separate thread
|
||||
return true;
|
||||
}
|
||||
|
||||
bool iidx_io_ep2_recv(void)
|
||||
{
|
||||
// Any sending and receiving is executed async in a separate thread
|
||||
return true;
|
||||
}
|
||||
|
||||
uint8_t iidx_io_ep2_get_turntable(uint8_t player_no)
|
||||
{
|
||||
switch (player_no)
|
||||
{
|
||||
case 0:
|
||||
return atomic_load_explicit(&_child_iidx_io_turntable_p1, memory_order_relaxed);
|
||||
case 1:
|
||||
return atomic_load_explicit(&_child_iidx_io_turntable_p2, memory_order_relaxed);
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t iidx_io_ep2_get_slider(uint8_t slider_no)
|
||||
{
|
||||
switch (slider_no)
|
||||
{
|
||||
case 0:
|
||||
return atomic_load_explicit(&_child_iidx_io_slider_1, memory_order_relaxed);
|
||||
case 1:
|
||||
return atomic_load_explicit(&_child_iidx_io_slider_2, memory_order_relaxed);
|
||||
case 2:
|
||||
return atomic_load_explicit(&_child_iidx_io_slider_3, memory_order_relaxed);
|
||||
case 3:
|
||||
return atomic_load_explicit(&_child_iidx_io_slider_4, memory_order_relaxed);
|
||||
case 4:
|
||||
return atomic_load_explicit(&_child_iidx_io_slider_5, memory_order_relaxed);
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t iidx_io_ep2_get_sys(void)
|
||||
{
|
||||
return atomic_load_explicit(&_child_iidx_io_sys, memory_order_relaxed);
|
||||
}
|
||||
|
||||
uint8_t iidx_io_ep2_get_panel(void)
|
||||
{
|
||||
return atomic_load_explicit(&_child_iidx_io_panel, memory_order_relaxed);
|
||||
}
|
||||
|
||||
uint16_t iidx_io_ep2_get_keys(void)
|
||||
{
|
||||
return atomic_load_explicit(&_child_iidx_io_keys, memory_order_relaxed);
|
||||
}
|
||||
|
||||
bool iidx_io_ep3_write_16seg(const char *text)
|
||||
{
|
||||
// TODO atomic copy with mutex?
|
||||
|
||||
return true;
|
||||
}
|
||||
10
src/main/iidxio-perf/Module.mk
Normal file
10
src/main/iidxio-perf/Module.mk
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
dlls += iidxio-perf
|
||||
|
||||
ldflags_iidxio-perf := \
|
||||
|
||||
libs_iidxio-perf := \
|
||||
hdr-histogram \
|
||||
util \
|
||||
|
||||
src_iidxio-perf := \
|
||||
iidxio.c \
|
||||
18
src/main/iidxio-perf/iidxio-perf.def
Normal file
18
src/main/iidxio-perf/iidxio-perf.def
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
LIBRARY iidxio
|
||||
|
||||
EXPORTS
|
||||
iidx_io_ep1_send
|
||||
iidx_io_ep1_set_deck_lights
|
||||
iidx_io_ep1_set_panel_lights
|
||||
iidx_io_ep1_set_top_lamps
|
||||
iidx_io_ep1_set_top_neons
|
||||
iidx_io_ep2_get_keys
|
||||
iidx_io_ep2_get_panel
|
||||
iidx_io_ep2_get_sys
|
||||
iidx_io_ep2_get_slider
|
||||
iidx_io_ep2_get_turntable
|
||||
iidx_io_ep2_recv
|
||||
iidx_io_ep3_write_16seg
|
||||
iidx_io_fini
|
||||
iidx_io_init
|
||||
iidx_io_set_loggers
|
||||
306
src/main/iidxio-perf/iidxio.c
Normal file
306
src/main/iidxio-perf/iidxio.c
Normal file
|
|
@ -0,0 +1,306 @@
|
|||
#define LOG_MODULE "iidxio-perf"
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <stdatomic.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "bemanitools/iidxio.h"
|
||||
|
||||
#include "hdr-histogram/hdr_histogram.h"
|
||||
#include "hdr-histogram/hdr_time.h"
|
||||
|
||||
#include "util/log.h"
|
||||
#include "util/thread.h"
|
||||
#include "util/time.h"
|
||||
|
||||
typedef void (*iidx_io_set_loggers_t)(
|
||||
log_formatter_t misc,
|
||||
log_formatter_t info,
|
||||
log_formatter_t warning,
|
||||
log_formatter_t fatal);
|
||||
typedef bool (*iidx_io_init_t)(
|
||||
thread_create_t thread_create,
|
||||
thread_join_t thread_join,
|
||||
thread_destroy_t thread_destroy);
|
||||
typedef void (*iidx_io_fini_t)(void);
|
||||
typedef void (*iidx_io_ep1_set_deck_lights_t)(uint16_t deck_lights);
|
||||
typedef void (*iidx_io_ep1_set_panel_lights_t)(uint8_t panel_lights);
|
||||
typedef void (*iidx_io_ep1_set_top_lamps_t)(uint8_t top_lamps);
|
||||
typedef void (*iidx_io_ep1_set_top_neons_t)(bool top_neons);
|
||||
typedef bool (*iidx_io_ep1_send_t)(void);
|
||||
typedef bool (*iidx_io_ep2_recv_t)(void);
|
||||
typedef uint8_t (*iidx_io_ep2_get_turntable_t)(uint8_t player_no);
|
||||
typedef uint8_t (*iidx_io_ep2_get_slider_t)(uint8_t slider_no);
|
||||
typedef uint8_t (*iidx_io_ep2_get_sys_t)(void);
|
||||
typedef uint8_t (*iidx_io_ep2_get_panel_t)(void);
|
||||
typedef uint16_t (*iidx_io_ep2_get_keys_t)(void);
|
||||
typedef bool (*iidx_io_ep3_write_16seg_t)(const char *text);
|
||||
|
||||
static HMODULE _child_iidx_io_module;
|
||||
|
||||
static iidx_io_set_loggers_t _child_iidx_io_set_loggers;
|
||||
static iidx_io_init_t _child_iidx_io_init;
|
||||
static iidx_io_fini_t _child_iidx_io_fini;
|
||||
|
||||
static iidx_io_ep1_set_deck_lights_t _child_iidx_io_ep1_set_deck_lights;
|
||||
static iidx_io_ep1_set_panel_lights_t _child_iidx_io_ep1_set_panel_lights;
|
||||
static iidx_io_ep1_set_top_lamps_t _child_iidx_io_ep1_set_top_lamps;
|
||||
static iidx_io_ep1_set_top_neons_t _child_iidx_io_ep1_set_top_neons;
|
||||
static iidx_io_ep1_send_t _child_iidx_io_ep1_send;
|
||||
static iidx_io_ep2_recv_t _child_iidx_io_ep2_recv;
|
||||
static iidx_io_ep2_get_turntable_t _child_iidx_io_ep2_get_turntable;
|
||||
static iidx_io_ep2_get_slider_t _child_iidx_io_ep2_get_slider;
|
||||
static iidx_io_ep2_get_sys_t _child_iidx_io_ep2_get_sys;
|
||||
static iidx_io_ep2_get_panel_t _child_iidx_io_ep2_get_panel;
|
||||
static iidx_io_ep2_get_keys_t _child_iidx_io_ep2_get_keys;
|
||||
static iidx_io_ep3_write_16seg_t _child_iidx_io_ep3_write_16seg;
|
||||
|
||||
static log_formatter_t _log_formatter_misc;
|
||||
static log_formatter_t _log_formatter_info;
|
||||
static log_formatter_t _log_formatter_warning;
|
||||
static log_formatter_t _log_formatter_fatal;
|
||||
|
||||
struct hdr_histogram* _histogram_ep1_send;
|
||||
struct hdr_histogram* _histogram_ep2_recv;
|
||||
struct hdr_histogram* _histogram_ep3_write_16seg;
|
||||
|
||||
static void *_load_function(HMODULE module, const char *name)
|
||||
{
|
||||
void *ptr;
|
||||
|
||||
ptr = GetProcAddress(module, name);
|
||||
|
||||
if (ptr == NULL) {
|
||||
log_fatal("Could not find function %s in iidxio child library", name);
|
||||
}
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void iidx_io_set_loggers(
|
||||
log_formatter_t misc,
|
||||
log_formatter_t info,
|
||||
log_formatter_t warning,
|
||||
log_formatter_t fatal)
|
||||
{
|
||||
_log_formatter_misc = misc;
|
||||
_log_formatter_info = info;
|
||||
_log_formatter_warning = warning;
|
||||
_log_formatter_fatal = fatal;
|
||||
|
||||
log_to_external(misc, info, warning, fatal);
|
||||
}
|
||||
|
||||
bool iidx_io_init(
|
||||
thread_create_t thread_create,
|
||||
thread_join_t thread_join,
|
||||
thread_destroy_t thread_destroy)
|
||||
{
|
||||
size_t histogram_memory_usage_bytes;
|
||||
|
||||
log_info("Loading iidxio-perf-child.dll as child iidxio library...");
|
||||
|
||||
_child_iidx_io_module = LoadLibraryA("iidxio-perf-child.dll");
|
||||
|
||||
if (_child_iidx_io_module == NULL) {
|
||||
log_warning("Loading iidxio-perf-child.dll failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
_child_iidx_io_set_loggers =
|
||||
_load_function(_child_iidx_io_module, "iidx_io_set_loggers");
|
||||
_child_iidx_io_init = _load_function(_child_iidx_io_module, "iidx_io_init");
|
||||
_child_iidx_io_fini = _load_function(_child_iidx_io_module, "iidx_io_fini");
|
||||
|
||||
_child_iidx_io_ep1_set_deck_lights =
|
||||
_load_function(_child_iidx_io_module, "iidx_io_ep1_set_deck_lights");
|
||||
_child_iidx_io_ep1_set_panel_lights =
|
||||
_load_function(_child_iidx_io_module, "iidx_io_ep1_set_panel_lights");
|
||||
_child_iidx_io_ep1_set_top_lamps =
|
||||
_load_function(_child_iidx_io_module, "iidx_io_ep1_set_top_lamps");
|
||||
_child_iidx_io_ep1_set_top_neons =
|
||||
_load_function(_child_iidx_io_module, "iidx_io_ep1_set_top_neons");
|
||||
_child_iidx_io_ep1_send =
|
||||
_load_function(_child_iidx_io_module, "iidx_io_ep1_send");
|
||||
_child_iidx_io_ep2_recv =
|
||||
_load_function(_child_iidx_io_module, "iidx_io_ep2_recv");
|
||||
_child_iidx_io_ep2_get_turntable =
|
||||
_load_function(_child_iidx_io_module, "iidx_io_ep2_get_turntable");
|
||||
_child_iidx_io_ep2_get_slider =
|
||||
_load_function(_child_iidx_io_module, "iidx_io_ep2_get_slider");
|
||||
_child_iidx_io_ep2_get_sys =
|
||||
_load_function(_child_iidx_io_module, "iidx_io_ep2_get_sys");
|
||||
_child_iidx_io_ep2_get_panel =
|
||||
_load_function(_child_iidx_io_module, "iidx_io_ep2_get_panel");
|
||||
_child_iidx_io_ep2_get_keys =
|
||||
_load_function(_child_iidx_io_module, "iidx_io_ep2_get_keys");
|
||||
_child_iidx_io_ep3_write_16seg =
|
||||
_load_function(_child_iidx_io_module, "iidx_io_ep3_write_16seg");
|
||||
|
||||
_child_iidx_io_set_loggers(
|
||||
_log_formatter_misc,
|
||||
_log_formatter_info,
|
||||
_log_formatter_warning,
|
||||
_log_formatter_fatal);
|
||||
|
||||
log_info("Initialising histograms...");
|
||||
|
||||
hdr_init(1, INT64_C(3600000000), 3, &_histogram_ep1_send);
|
||||
hdr_init(1, INT64_C(3600000000), 3, &_histogram_ep2_recv);
|
||||
hdr_init(1, INT64_C(3600000000), 3, &_histogram_ep3_write_16seg);
|
||||
|
||||
histogram_memory_usage_bytes =
|
||||
hdr_get_memory_size(_histogram_ep1_send) +
|
||||
hdr_get_memory_size(_histogram_ep2_recv) +
|
||||
hdr_get_memory_size(_histogram_ep3_write_16seg);
|
||||
|
||||
log_misc("Histogram total memory usage: %" PRIdPTR " bytes", histogram_memory_usage_bytes);
|
||||
|
||||
log_info("Calling child iidx_io_init...");
|
||||
|
||||
if (!_child_iidx_io_init(thread_create, thread_join, thread_destroy)) {
|
||||
log_warning("Child iidx_io_init failed");
|
||||
FreeLibrary(_child_iidx_io_module);
|
||||
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
void iidx_io_fini(void)
|
||||
{
|
||||
_child_iidx_io_fini();
|
||||
|
||||
log_info("----------------------------------------------------------------");
|
||||
log_info("Printing histograms...");
|
||||
log_info("All values are times in microseconds (us)");
|
||||
|
||||
log_info("----------------------------------------------------------------");
|
||||
log_info(">>> EP1 send");
|
||||
hdr_percentiles_print(_histogram_ep1_send, stdout, 5, 1.0, CLASSIC);
|
||||
log_info("----------------------------------------------------------------");
|
||||
log_info(">>> EP2 recv");
|
||||
hdr_percentiles_print(_histogram_ep2_recv, stdout, 5, 1.0, CLASSIC);
|
||||
log_info("----------------------------------------------------------------");
|
||||
log_info(">>> EP3 write 16seg");
|
||||
hdr_percentiles_print(_histogram_ep3_write_16seg, stdout, 5, 1.0, CLASSIC);
|
||||
|
||||
log_info("----------------------------------------------------------------");
|
||||
|
||||
fflush(stdout);
|
||||
|
||||
hdr_close(_histogram_ep1_send);
|
||||
hdr_close(_histogram_ep2_recv);
|
||||
hdr_close(_histogram_ep3_write_16seg);
|
||||
|
||||
FreeLibrary(_child_iidx_io_module);
|
||||
}
|
||||
|
||||
void iidx_io_ep1_set_deck_lights(uint16_t deck_lights)
|
||||
{
|
||||
return _child_iidx_io_ep1_set_deck_lights(deck_lights);
|
||||
}
|
||||
|
||||
void iidx_io_ep1_set_panel_lights(uint8_t panel_lights)
|
||||
{
|
||||
return _child_iidx_io_ep1_set_panel_lights(panel_lights);
|
||||
}
|
||||
|
||||
void iidx_io_ep1_set_top_lamps(uint8_t top_lamps)
|
||||
{
|
||||
return _child_iidx_io_ep1_set_top_lamps(top_lamps);
|
||||
}
|
||||
|
||||
void iidx_io_ep1_set_top_neons(bool top_neons)
|
||||
{
|
||||
return _child_iidx_io_ep1_set_top_neons(top_neons);
|
||||
}
|
||||
|
||||
bool iidx_io_ep1_send(void)
|
||||
{
|
||||
hdr_timespec start_time;
|
||||
hdr_timespec end_time;
|
||||
int64_t diff_us;
|
||||
bool result;
|
||||
|
||||
hdr_gettime(&start_time);
|
||||
|
||||
result = _child_iidx_io_ep1_send();
|
||||
|
||||
hdr_gettime(&end_time);
|
||||
diff_us = hdr_timespec_diff_us(&start_time, &end_time);
|
||||
|
||||
hdr_record_value(_histogram_ep1_send, diff_us);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool iidx_io_ep2_recv(void)
|
||||
{
|
||||
hdr_timespec start_time;
|
||||
hdr_timespec end_time;
|
||||
int64_t diff_us;
|
||||
bool result;
|
||||
|
||||
hdr_gettime(&start_time);
|
||||
|
||||
result = _child_iidx_io_ep2_recv();
|
||||
|
||||
hdr_gettime(&end_time);
|
||||
diff_us = hdr_timespec_diff_us(&start_time, &end_time);
|
||||
|
||||
hdr_record_value(_histogram_ep2_recv, diff_us);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
uint8_t iidx_io_ep2_get_turntable(uint8_t player_no)
|
||||
{
|
||||
return _child_iidx_io_ep2_get_turntable(player_no);
|
||||
}
|
||||
|
||||
uint8_t iidx_io_ep2_get_slider(uint8_t slider_no)
|
||||
{
|
||||
return _child_iidx_io_ep2_get_slider(slider_no);
|
||||
}
|
||||
|
||||
uint8_t iidx_io_ep2_get_sys(void)
|
||||
{
|
||||
return _child_iidx_io_ep2_get_sys();
|
||||
}
|
||||
|
||||
uint8_t iidx_io_ep2_get_panel(void)
|
||||
{
|
||||
return _child_iidx_io_ep2_get_panel();
|
||||
}
|
||||
|
||||
uint16_t iidx_io_ep2_get_keys(void)
|
||||
{
|
||||
return _child_iidx_io_ep2_get_keys();
|
||||
}
|
||||
|
||||
bool iidx_io_ep3_write_16seg(const char *text)
|
||||
{
|
||||
hdr_timespec start_time;
|
||||
hdr_timespec end_time;
|
||||
int64_t diff_us;
|
||||
bool result;
|
||||
|
||||
hdr_gettime(&start_time);
|
||||
|
||||
result = _child_iidx_io_ep3_write_16seg(text);
|
||||
|
||||
hdr_gettime(&end_time);
|
||||
diff_us = hdr_timespec_diff_us(&start_time, &end_time);
|
||||
|
||||
hdr_record_value(_histogram_ep3_write_16seg, diff_us);
|
||||
|
||||
return result;
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user