1 /*
2  * Event rate calculation functions.
3  *
4  * Copyright 2000-2010 Willy Tarreau <w@1wt.eu>
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version
9  * 2 of the License, or (at your option) any later version.
10  *
11  */
12 
13 #include <common/config.h>
14 #include <common/standard.h>
15 #include <common/time.h>
16 #include <common/tools.h>
17 #include <proto/freq_ctr.h>
18 
19 /* Read a frequency counter taking history into account for missing time in
20  * current period. Current second is sub-divided in 1000 chunks of one ms,
21  * and the missing ones are read proportionally from previous value. The
22  * return value has the same precision as one input data sample, so low rates
23  * will be inaccurate still appropriate for max checking. One trick we use for
24  * low values is to specially handle the case where the rate is between 0 and 1
25  * in order to avoid flapping while waiting for the next event.
26  *
27  * For immediate limit checking, it's recommended to use freq_ctr_remain() and
28  * next_event_delay() instead which do not have the flapping correction, so
29  * that even frequencies as low as one event/period are properly handled.
30  */
read_freq_ctr(struct freq_ctr * ctr)31 unsigned int read_freq_ctr(struct freq_ctr *ctr)
32 {
33 	unsigned int curr, past, _curr, _past;
34 	unsigned int age, curr_sec, _curr_sec;
35 
36 	while (1) {
37 		_curr = ctr->curr_ctr;
38 		HA_BARRIER();
39 		_past = ctr->prev_ctr;
40 		HA_BARRIER();
41 		_curr_sec = ctr->curr_sec;
42 		HA_BARRIER();
43 		if (_curr_sec & 0x80000000)
44 			continue;
45 		curr = ctr->curr_ctr;
46 		HA_BARRIER();
47 		past = ctr->prev_ctr;
48 		HA_BARRIER();
49 		curr_sec = ctr->curr_sec;
50 		HA_BARRIER();
51 		if (_curr == curr && _past == past && _curr_sec == curr_sec)
52 			break;
53 	}
54 
55 	age = (global_now >> 32) - curr_sec;
56 	if (unlikely(age > 1))
57 		return 0;
58 
59 	if (unlikely(age)) {
60 		past = curr;
61 		curr = 0;
62 	}
63 
64 	if (past <= 1 && !curr)
65 		return past; /* very low rate, avoid flapping */
66 
67 	return curr + mul32hi(past, ms_left_scaled);
68 }
69 
70 /* returns the number of remaining events that can occur on this freq counter
71  * while respecting <freq> and taking into account that <pend> events are
72  * already known to be pending. Returns 0 if limit was reached.
73  */
freq_ctr_remain(struct freq_ctr * ctr,unsigned int freq,unsigned int pend)74 unsigned int freq_ctr_remain(struct freq_ctr *ctr, unsigned int freq, unsigned int pend)
75 {
76 	unsigned int curr, past, _curr, _past;
77 	unsigned int age, curr_sec, _curr_sec;
78 
79 	while (1) {
80 		_curr = ctr->curr_ctr;
81 		HA_BARRIER();
82 		_past = ctr->prev_ctr;
83 		HA_BARRIER();
84 		_curr_sec = ctr->curr_sec;
85 		HA_BARRIER();
86 		if (_curr_sec & 0x80000000)
87 			continue;
88 		curr = ctr->curr_ctr;
89 		HA_BARRIER();
90 		past = ctr->prev_ctr;
91 		HA_BARRIER();
92 		curr_sec = ctr->curr_sec;
93 		HA_BARRIER();
94 		if (_curr == curr && _past == past && _curr_sec == curr_sec)
95 			break;
96 	}
97 
98 	age = (global_now >> 32) - curr_sec;
99 	if (unlikely(age > 1))
100 		curr = 0;
101 	else {
102 		if (unlikely(age == 1)) {
103 			past = curr;
104 			curr = 0;
105 		}
106 		curr += mul32hi(past, ms_left_scaled);
107 	}
108 	curr += pend;
109 
110 	if (curr >= freq)
111 		return 0;
112 	return freq - curr;
113 }
114 
115 /* return the expected wait time in ms before the next event may occur,
116  * respecting frequency <freq>, and assuming there may already be some pending
117  * events. It returns zero if we can proceed immediately, otherwise the wait
118  * time, which will be rounded down 1ms for better accuracy, with a minimum
119  * of one ms.
120  */
next_event_delay(struct freq_ctr * ctr,unsigned int freq,unsigned int pend)121 unsigned int next_event_delay(struct freq_ctr *ctr, unsigned int freq, unsigned int pend)
122 {
123 	unsigned int curr, past, _curr, _past;
124 	unsigned int wait, age, curr_sec, _curr_sec;
125 
126 	while (1) {
127 		_curr = ctr->curr_ctr;
128 		HA_BARRIER();
129 		_past = ctr->prev_ctr;
130 		HA_BARRIER();
131 		_curr_sec = ctr->curr_sec;
132 		HA_BARRIER();
133 		if (_curr_sec & 0x80000000)
134 			continue;
135 		curr = ctr->curr_ctr;
136 		HA_BARRIER();
137 		past = ctr->prev_ctr;
138 		HA_BARRIER();
139 		curr_sec = ctr->curr_sec;
140 		HA_BARRIER();
141 		if (_curr == curr && _past == past && _curr_sec == curr_sec)
142 			break;
143 	}
144 
145 	age = (global_now >> 32) - curr_sec;
146 	if (unlikely(age > 1))
147 		curr = 0;
148 	else {
149 		if (unlikely(age == 1)) {
150 			past = curr;
151 			curr = 0;
152 		}
153 		curr += mul32hi(past, ms_left_scaled);
154 	}
155 	curr += pend;
156 
157 	if (curr < freq)
158 		return 0;
159 
160 	wait = 999 / curr;
161 	return MAX(wait, 1);
162 }
163 
164 /* Reads a frequency counter taking history into account for missing time in
165  * current period. The period has to be passed in number of ticks and must
166  * match the one used to feed the counter. The counter value is reported for
167  * current global date. The return value has the same precision as one input
168  * data sample, so low rates over the period will be inaccurate but still
169  * appropriate for max checking. One trick we use for low values is to specially
170  * handle the case where the rate is between 0 and 1 in order to avoid flapping
171  * while waiting for the next event.
172  *
173  * For immediate limit checking, it's recommended to use freq_ctr_period_remain()
174  * instead which does not have the flapping correction, so that even frequencies
175  * as low as one event/period are properly handled.
176  *
177  * For measures over a 1-second period, it's better to use the implicit functions
178  * above.
179  */
read_freq_ctr_period(struct freq_ctr_period * ctr,unsigned int period)180 unsigned int read_freq_ctr_period(struct freq_ctr_period *ctr, unsigned int period)
181 {
182 	unsigned int _curr, _past, curr, past;
183 	unsigned int remain, _curr_tick, curr_tick;
184 
185 	while (1) {
186 		_curr = ctr->curr_ctr;
187 		HA_BARRIER();
188 		_past = ctr->prev_ctr;
189 		HA_BARRIER();
190 		_curr_tick = ctr->curr_tick;
191 		HA_BARRIER();
192 		if (_curr_tick & 0x1)
193 			continue;
194 		curr = ctr->curr_ctr;
195 		HA_BARRIER();
196 		past = ctr->prev_ctr;
197 		HA_BARRIER();
198 		curr_tick = ctr->curr_tick;
199 		HA_BARRIER();
200 		if (_curr == curr && _past == past && _curr_tick == curr_tick)
201 			break;
202 	};
203 
204 	remain = curr_tick + period - (uint32_t)global_now / 1000;
205 	if (unlikely((int)remain < 0)) {
206 		/* We're past the first period, check if we can still report a
207 		 * part of last period or if we're too far away.
208 		 */
209 		remain += period;
210 		if ((int)remain < 0)
211 			return 0;
212 		past = curr;
213 		curr = 0;
214 	}
215 	if (past <= 1 && !curr)
216 		return past; /* very low rate, avoid flapping */
217 
218 	curr += div64_32((unsigned long long)past * remain, period);
219 	return curr;
220 }
221 
222 /* Returns the number of remaining events that can occur on this freq counter
223  * while respecting <freq> events per period, and taking into account that
224  * <pend> events are already known to be pending. Returns 0 if limit was reached.
225  */
freq_ctr_remain_period(struct freq_ctr_period * ctr,unsigned int period,unsigned int freq,unsigned int pend)226 unsigned int freq_ctr_remain_period(struct freq_ctr_period *ctr, unsigned int period,
227 				    unsigned int freq, unsigned int pend)
228 {
229 	unsigned int _curr, _past, curr, past;
230 	unsigned int remain, _curr_tick, curr_tick;
231 
232 	while (1) {
233 		_curr = ctr->curr_ctr;
234 		HA_BARRIER();
235 		_past = ctr->prev_ctr;
236 		HA_BARRIER();
237 		_curr_tick = ctr->curr_tick;
238 		HA_BARRIER();
239 		if (_curr_tick & 0x1)
240 			continue;
241 		curr = ctr->curr_ctr;
242 		HA_BARRIER();
243 		past = ctr->prev_ctr;
244 		HA_BARRIER();
245 		curr_tick = ctr->curr_tick;
246 		HA_BARRIER();
247 		if (_curr == curr && _past == past && _curr_tick == curr_tick)
248 			break;
249 	};
250 
251 	remain = curr_tick + period - (uint32_t)global_now / 1000;
252 	if (likely((int)remain < 0)) {
253 		/* We're past the first period, check if we can still report a
254 		 * part of last period or if we're too far away.
255 		 */
256 		past = curr;
257 		curr = 0;
258 		remain += period;
259 		if ((int)remain < 0)
260 			past = 0;
261 	}
262 	if (likely(past))
263 		curr += div64_32((unsigned long long)past * remain, period);
264 
265 	curr += pend;
266 	freq -= curr;
267 	if ((int)freq < 0)
268 		freq = 0;
269 	return freq;
270 }
271 
272 
273 /*
274  * Local variables:
275  *  c-indent-level: 8
276  *  c-basic-offset: 8
277  * End:
278  */
279