wip iidxio-async

Summary:

Test Plan:
This commit is contained in:
icex2 2025-01-18 23:26:54 +01:00
parent ce1a004bf6
commit 3d868e33d4
28 changed files with 5796 additions and 0 deletions

View File

@ -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 \

View 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 \

View 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__ */

View 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;
}

View 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 */

View 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

File diff suppressed because it is too large Load Diff

View 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

File diff suppressed because it is too large Load Diff

View 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

View 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;
}

View 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

View 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, &params[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, &params[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, &params[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, &params[0]);
return params[3];
}

View 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

View 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

View 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

View 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

View 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

View 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;
}

View 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

View 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);
}

View 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

View File

@ -0,0 +1,9 @@
dlls += iidxio-async
ldflags_iidxio-async := \
libs_iidxio-async := \
util \
src_iidxio-async := \
iidxio.c \

View 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

View 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;
}

View File

@ -0,0 +1,10 @@
dlls += iidxio-perf
ldflags_iidxio-perf := \
libs_iidxio-perf := \
hdr-histogram \
util \
src_iidxio-perf := \
iidxio.c \

View 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

View 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;
}