/*
 * Event rate calculation functions.
 *
 * Copyright 2000-2010 Willy Tarreau <w@1wt.eu>
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version
 * 2 of the License, or (at your option) any later version.
 *
 */

#include <haproxy/api.h>
#include <haproxy/freq_ctr.h>
#include <haproxy/tools.h>

/* Update a frequency counter by <inc> incremental units. It is automatically
 * rotated if the period is over. It is important that it correctly initializes
 * a null area. This one works on frequency counters which have a period
 * different from one second. It relies on the process-wide clock that is
 * guaranteed to be monotonic. It's important to avoid forced rotates between
 * threads. A faster wrapper (update_freq_ctr_period) should be used instead,
 * which uses the thread's local time whenever possible and falls back to this
 * one when needed (less than 0.003% of the time).
 */
uint update_freq_ctr_period_slow(struct freq_ctr *ctr, uint period, uint inc)
{
	uint curr_tick;
	uint32_t now_ms_tmp;

	/* atomically update the counter if still within the period, even if
	 * a rotation is in progress (no big deal).
	 */
	for (;; __ha_cpu_relax()) {
		curr_tick  = HA_ATOMIC_LOAD(&ctr->curr_tick);
		now_ms_tmp = HA_ATOMIC_LOAD(&global_now_ms);

		if (now_ms_tmp - curr_tick < period)
			return HA_ATOMIC_ADD_FETCH(&ctr->curr_ctr, inc);

		/* a rotation is needed. While extremely rare, contention may
		 * happen because it will be triggered on time, and all threads
		 * see the time change simultaneously.
		 */
		if (!(curr_tick & 1) &&
		    HA_ATOMIC_CAS(&ctr->curr_tick, &curr_tick, curr_tick | 0x1))
			break;
	}

	/* atomically switch the new period into the old one without losing any
	 * potential concurrent update. We're the only one performing the rotate
	 * (locked above), others are only adding positive values to curr_ctr.
	 */
	HA_ATOMIC_STORE(&ctr->prev_ctr, HA_ATOMIC_XCHG(&ctr->curr_ctr, inc));
	curr_tick += period;
	if (likely(now_ms_tmp - curr_tick >= period)) {
		/* we missed at least two periods */
		HA_ATOMIC_STORE(&ctr->prev_ctr, 0);
		curr_tick = now_ms_tmp;
	}

	/* release the lock and update the time in case of rotate. */
	HA_ATOMIC_STORE(&ctr->curr_tick, curr_tick & ~1);
	return inc;
}

/* Returns the total number of events over the current + last period, including
 * a number of already pending events <pend>. The average frequency will be
 * obtained by dividing the output by <period>. This is essentially made to
 * ease implementation of higher-level read functions.
 *
 * As a special case, if pend < 0, it's assumed there are no pending
 * events and a flapping correction must be applied at the end. This is used by
 * read_freq_ctr_period() to avoid reporting ups and downs on low-frequency
 * events when the past value is <= 1.
 */
ullong freq_ctr_total(const struct freq_ctr *ctr, uint period, int pend)
{
	ullong curr, past, old_curr, old_past;
	uint tick, old_tick;
	int remain;

	tick = HA_ATOMIC_LOAD(&ctr->curr_tick);
	curr = HA_ATOMIC_LOAD(&ctr->curr_ctr);
	past = HA_ATOMIC_LOAD(&ctr->prev_ctr);

	while (1) {
		if (tick & 0x1) // change in progress
			goto redo0;

		old_tick = tick;
		old_curr = curr;
		old_past = past;

		/* now let's load the values a second time and make sure they
		 * did not change, which will indicate it was a stable reading.
		 */

		tick = HA_ATOMIC_LOAD(&ctr->curr_tick);
		if (tick & 0x1) // change in progress
			goto redo0;

		if (tick != old_tick)
			goto redo1;

		curr = HA_ATOMIC_LOAD(&ctr->curr_ctr);
		if (curr != old_curr)
			goto redo2;

		past = HA_ATOMIC_LOAD(&ctr->prev_ctr);
		if (past != old_past)
			goto redo3;

		/* all values match between two loads, they're stable, let's
		 * quit now.
		 */
		break;
	redo0:
		tick = HA_ATOMIC_LOAD(&ctr->curr_tick);
	redo1:
		curr = HA_ATOMIC_LOAD(&ctr->curr_ctr);
	redo2:
		past = HA_ATOMIC_LOAD(&ctr->prev_ctr);
	redo3:
		__ha_cpu_relax();
	};

	remain = tick + period - HA_ATOMIC_LOAD(&global_now_ms);
	if (unlikely(remain < 0)) {
		/* We're past the first period, check if we can still report a
		 * part of last period or if we're too far away.
		 */
		remain += period;
		past = (remain >= 0) ? curr : 0;
		curr = 0;
	}

	if (pend < 0) {
		/* enable flapping correction at very low rates */
		pend = 0;
		if (!curr && past <= 1)
			return past * period;
	}

	/* compute the total number of confirmed events over the period */
	return past * remain + (curr + pend) * period;
}

/* Returns the excess of events (may be negative) over the current period for
 * target frequency <freq>. It returns 0 if the counter is in the future or if
 * the counter is empty. The result considers the position of the current time
 * within the current period.
 *
 * The caller may safely add new events if result is negative or null.
 */
int freq_ctr_overshoot_period(const struct freq_ctr *ctr, uint period, uint freq)
{
	uint curr, old_curr;
	uint tick, old_tick;
	int elapsed;

	tick = HA_ATOMIC_LOAD(&ctr->curr_tick);
	curr = HA_ATOMIC_LOAD(&ctr->curr_ctr);

	while (1) {
		if (tick & 0x1) // change in progress
			goto redo0;

		old_tick = tick;
		old_curr = curr;

		/* now let's load the values a second time and make sure they
		 * did not change, which will indicate it was a stable reading.
		 */

		tick = HA_ATOMIC_LOAD(&ctr->curr_tick);
		if (tick & 0x1) // change in progress
			goto redo0;

		if (tick != old_tick)
			goto redo1;

		curr = HA_ATOMIC_LOAD(&ctr->curr_ctr);
		if (curr != old_curr)
			goto redo2;

		/* all values match between two loads, they're stable, let's
		 * quit now.
		 */
		break;
	redo0:
		tick = HA_ATOMIC_LOAD(&ctr->curr_tick);
	redo1:
		curr = HA_ATOMIC_LOAD(&ctr->curr_ctr);
	redo2:
		__ha_cpu_relax();
	};

	if (!curr && !tick) {
		/* The counter is empty, there is no overshoot */
		return 0;
	}

	elapsed = HA_ATOMIC_LOAD(&global_now_ms) - tick;
	if (unlikely(elapsed < 0)) {
		/* The counter is in the future, there is no overshoot */
		return 0;
	}

	return curr - div64_32((uint64_t)elapsed * freq, period);
}

/*
 * Local variables:
 *  c-indent-level: 8
 *  c-basic-offset: 8
 * End:
 */
