<commit_before>#include "brubeck.h"

static inline struct brubeck_metric *
new_metric(struct brubeck_server *server, const char *key, size_t key_len, uint8_t type)
{
	struct brubeck_metric *metric;

	/* slab allocation cannot fail */
	metric = brubeck_slab_alloc(&server->slab,
		sizeof(struct brubeck_metric) + key_len + 1);

	memset(metric, 0x0, sizeof(struct brubeck_metric));

	memcpy(metric->key, key, key_len);
	metric->key[key_len] = '\0';
	metric->key_len = (uint16_t)key_len;

	metric->expire = BRUBECK_EXPIRE_ACTIVE;
	metric->type = type;
	pthread_spin_init(&metric->lock, PTHREAD_PROCESS_PRIVATE);

#ifdef BRUBECK_METRICS_FLOW
	metric->flow = 0;
#else
	/* Compile time assert: ensure that the metric struct can be packed
	 * in a single slab */
	ct_assert(sizeof(struct brubeck_metric) <= (SLAB_SIZE));
#endif

	return metric;
}

typedef void (*mt_prototype_record)(struct brubeck_metric *, value_t, value_t, uint8_t);
typedef void (*mt_prototype_sample)(struct brubeck_metric *, brubeck_sample_cb, void *);


/*********************************************
 * Gauge
 *
 * ALLOC: mt + 4 bytes
 *********************************************/
static void
gauge__record(struct brubeck_metric *metric, value_t value, value_t sample_freq, uint8_t modifiers)
{
	pthread_spin_lock(&metric->lock);
	{
		if (modifiers & BRUBECK_MOD_RELATIVE_VALUE) {
			metric->as.gauge.value += value;
		} else {
			metric->as.gauge.value = value;
		}
	}
	pthread_spin_unlock(&metric->lock);
}

static void
gauge__sample(struct brubeck_metric *metric, brubeck_sample_cb sample, void *opaque)
{
	value_t value;

	pthread_spin_lock(&metric->lock);
	{
		value = metric->as.gauge.value;
	}
	pthread_spin_unlock(&metric->lock);

	sample(metric->key, value, opaque);
}


/*********************************************
 * Meter
 *
 * ALLOC: mt + 4
 *********************************************/
static void
meter__record(struct brubeck_metric *metric, value_t value, value_t sample_freq, uint8_t modifiers)
{
	/* upsample */
	value *= sample_freq;

	pthread_spin_lock(&metric->lock);
	{
		metric->as.meter.value += value;
	}
	pthread_spin_unlock(&metric->lock);
}

static void
meter__sample(struct brubeck_metric *metric, brubeck_sample_cb sample, void *opaque)
{
	value_t value;

	pthread_spin_lock(&metric->lock);
	{
		value = metric->as.meter.value;
		metric->as.meter.value = 0.0;
	}
	pthread_spin_unlock(&metric->lock);

	sample(metric->key, value, opaque);
}


/*********************************************
 * Counter
 *
 * ALLOC: mt + 4 + 4 + 4
 *********************************************/
static void
counter__record(struct brubeck_metric *metric, value_t value, value_t sample_freq, uint8_t modifiers)
{
	/* upsample */
	value *= sample_freq;

	pthread_spin_lock(&metric->lock);
	{
		if (metric->as.counter.previous > 0.0) {
			value_t diff = (value >= metric->as.counter.previous) ?
				(value - metric->as.counter.previous) :
				(value);

			metric->as.counter.value += diff;
		}

		metric->as.counter.previous = value;
	}
	pthread_spin_unlock(&metric->lock);
}

static void
counter__sample(struct brubeck_metric *metric, brubeck_sample_cb sample, void *opaque)
{
	value_t value;

	pthread_spin_lock(&metric->lock);
	{
		value = metric->as.counter.value;
		metric->as.counter.value = 0.0;
	}
	pthread_spin_unlock(&metric->lock);

	sample(metric->key, value, opaque);
}


/*********************************************
 * Histogram / Timer
 *
 * ALLOC: mt + 16 + 4
 *********************************************/
static void
histogram__record(struct brubeck_metric *metric, value_t value, value_t sample_freq, uint8_t modifiers)
{
	pthread_spin_lock(&metric->lock);
	{
		brubeck_histo_push(&metric->as.histogram, value, sample_freq);
	}
	pthread_spin_unlock(&metric->lock);
}

static void
histogram__sample(struct brubeck_metric *metric, brubeck_sample_cb sample, void *opaque)
{
	struct brubeck_histo_sample hsample;
	char *key;

	pthread_spin_lock(&metric->lock);
	{
		brubeck_histo_sample(&hsample, &metric->as.histogram);
	}
	pthread_spin_unlock(&metric->lock);

	/* alloc space for this on the stack. we need enough for:
	 * key_length + longest_suffix + null terminator
	 */
	key = alloca(metric->key_len + strlen(".percentile.999") + 1);
	memcpy(key, metric->key, metric->key_len);

	WITH_SUFFIX(".min") {
		sample(key, hsample.min, opaque);
	}

	WITH_SUFFIX(".max") {
		sample(key, hsample.max, opaque);
	}

	WITH_SUFFIX(".sum") {
		sample(key, hsample.sum, opaque);
	}

	WITH_SUFFIX(".mean") {
		sample(key, hsample.mean, opaque);
	}

	WITH_SUFFIX(".count") {
		sample(key, hsample.count, opaque);
	}

	WITH_SUFFIX(".median") {
		sample(key, hsample.median, opaque);
	}

	WITH_SUFFIX(".percentile.75") {
		sample(key, hsample.percentile[PC_75], opaque);<commit_msg>histogram: Do not report samples if our period is empty<commit_after>#include "brubeck.h"

static inline struct brubeck_metric *
new_metric(struct brubeck_server *server, const char *key, size_t key_len, uint8_t type)
{
	struct brubeck_metric *metric;

	/* slab allocation cannot fail */
	metric = brubeck_slab_alloc(&server->slab,
		sizeof(struct brubeck_metric) + key_len + 1);

	memset(metric, 0x0, sizeof(struct brubeck_metric));

	memcpy(metric->key, key, key_len);
	metric->key[key_len] = '\0';
	metric->key_len = (uint16_t)key_len;

	metric->expire = BRUBECK_EXPIRE_ACTIVE;
	metric->type = type;
	pthread_spin_init(&metric->lock, PTHREAD_PROCESS_PRIVATE);

#ifdef BRUBECK_METRICS_FLOW
	metric->flow = 0;
#else
	/* Compile time assert: ensure that the metric struct can be packed
	 * in a single slab */
	ct_assert(sizeof(struct brubeck_metric) <= (SLAB_SIZE));
#endif

	return metric;
}

typedef void (*mt_prototype_record)(struct brubeck_metric *, value_t, value_t, uint8_t);
typedef void (*mt_prototype_sample)(struct brubeck_metric *, brubeck_sample_cb, void *);


/*********************************************
 * Gauge
 *
 * ALLOC: mt + 4 bytes
 *********************************************/
static void
gauge__record(struct brubeck_metric *metric, value_t value, value_t sample_freq, uint8_t modifiers)
{
	pthread_spin_lock(&metric->lock);
	{
		if (modifiers & BRUBECK_MOD_RELATIVE_VALUE) {
			metric->as.gauge.value += value;
		} else {
			metric->as.gauge.value = value;
		}
	}
	pthread_spin_unlock(&metric->lock);
}

static void
gauge__sample(struct brubeck_metric *metric, brubeck_sample_cb sample, void *opaque)
{
	value_t value;

	pthread_spin_lock(&metric->lock);
	{
		value = metric->as.gauge.value;
	}
	pthread_spin_unlock(&metric->lock);

	sample(metric->key, value, opaque);
}


/*********************************************
 * Meter
 *
 * ALLOC: mt + 4
 *********************************************/
static void
meter__record(struct brubeck_metric *metric, value_t value, value_t sample_freq, uint8_t modifiers)
{
	/* upsample */
	value *= sample_freq;

	pthread_spin_lock(&metric->lock);
	{
		metric->as.meter.value += value;
	}
	pthread_spin_unlock(&metric->lock);
}

static void
meter__sample(struct brubeck_metric *metric, brubeck_sample_cb sample, void *opaque)
{
	value_t value;

	pthread_spin_lock(&metric->lock);
	{
		value = metric->as.meter.value;
		metric->as.meter.value = 0.0;
	}
	pthread_spin_unlock(&metric->lock);

	sample(metric->key, value, opaque);
}


/*********************************************
 * Counter
 *
 * ALLOC: mt + 4 + 4 + 4
 *********************************************/
static void
counter__record(struct brubeck_metric *metric, value_t value, value_t sample_freq, uint8_t modifiers)
{
	/* upsample */
	value *= sample_freq;

	pthread_spin_lock(&metric->lock);
	{
		if (metric->as.counter.previous > 0.0) {
			value_t diff = (value >= metric->as.counter.previous) ?
				(value - metric->as.counter.previous) :
				(value);

			metric->as.counter.value += diff;
		}

		metric->as.counter.previous = value;
	}
	pthread_spin_unlock(&metric->lock);
}

static void
counter__sample(struct brubeck_metric *metric, brubeck_sample_cb sample, void *opaque)
{
	value_t value;

	pthread_spin_lock(&metric->lock);
	{
		value = metric->as.counter.value;
		metric->as.counter.value = 0.0;
	}
	pthread_spin_unlock(&metric->lock);

	sample(metric->key, value, opaque);
}


/*********************************************
 * Histogram / Timer
 *
 * ALLOC: mt + 16 + 4
 *********************************************/
static void
histogram__record(struct brubeck_metric *metric, value_t value, value_t sample_freq, uint8_t modifiers)
{
	pthread_spin_lock(&metric->lock);
	{
		brubeck_histo_push(&metric->as.histogram, value, sample_freq);
	}
	pthread_spin_unlock(&metric->lock);
}

static void
histogram__sample(struct brubeck_metric *metric, brubeck_sample_cb sample, void *opaque)
{
	struct brubeck_histo_sample hsample;
	char *key;

	pthread_spin_lock(&metric->lock);
	{
		brubeck_histo_sample(&hsample, &metric->as.histogram);
	}
	pthread_spin_unlock(&metric->lock);

	/* alloc space for this on the stack. we need enough for:
	 * key_length + longest_suffix + null terminator
	 */
	key = alloca(metric->key_len + strlen(".percentile.999") + 1);
	memcpy(key, metric->key, metric->key_len);


	WITH_SUFFIX(".count") {
		sample(key, hsample.count, opaque);
	}

	/* if there have been no metrics during this sampling period,
	 * we don't need to report any of the histogram samples */
	if (hsample.count == 0.0)
		return;

	WITH_SUFFIX(".min") {
		sample(key, hsample.min, opaque);
	}

	WITH_SUFFIX(".max") {
		sample(key, hsample.max, opaque);
	}

	WITH_SUFFIX(".sum") {
		sample(key, hsample.sum, opaque);
	}

	WITH_SUFFIX(".mean") {
		sample(key, hsample.mean, opaque);
	}

	WITH_SUFFIX(".median") {
		sample(key, hsample.median, opaque);
	}

	WITH_SUFFIX(".percentile.75") {
		sample(key, hsample.percentile[PC_75], opaque);
{'fraction_non_alphanumeric': 0.20195071868583162, 'fraction_numerical': 0.007392197125256674, 'mean_word_length': 5.204458598726115, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 97, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '597755', 'n_tokens_mistral': 3642, 'n_tokens_neox': 3394, 'n_words': 668}