blob: 6dec970024973d486d7b3e708e094fe263cc920b [file] [log] [blame]
Willy Tarreau7f062c42009-03-05 18:43:00 +01001/*
2 * Event rate calculation functions.
3 *
Willy Tarreau2970b0b2010-06-20 07:15:43 +02004 * Copyright 2000-2010 Willy Tarreau <w@1wt.eu>
Willy Tarreau7f062c42009-03-05 18:43:00 +01005 *
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>
Willy Tarreau79584222009-03-06 09:18:27 +010016#include <common/tools.h>
Willy Tarreau7f062c42009-03-05 18:43:00 +010017#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.
Willy Tarreau79584222009-03-06 09:18:27 +010026 *
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.
Willy Tarreau7f062c42009-03-05 18:43:00 +010030 */
31unsigned int read_freq_ctr(struct freq_ctr *ctr)
32{
Willy Tarreau3d8c5532009-03-06 14:29:25 +010033 unsigned int curr, past;
34 unsigned int age;
Willy Tarreau7f062c42009-03-05 18:43:00 +010035
Willy Tarreau3d8c5532009-03-06 14:29:25 +010036 age = now.tv_sec - ctr->curr_sec;
37 if (unlikely(age > 1))
38 return 0;
39
40 curr = 0;
41 past = ctr->curr_ctr;
42 if (likely(!age)) {
43 curr = past;
44 past = ctr->prev_ctr;
45 }
Willy Tarreau7f062c42009-03-05 18:43:00 +010046
Willy Tarreau3d8c5532009-03-06 14:29:25 +010047 if (past <= 1 && !curr)
48 return past; /* very low rate, avoid flapping */
49
Willy Tarreaueab777c2012-12-29 21:50:07 +010050 return curr + mul32hi(past, ms_left_scaled);
Willy Tarreau7f062c42009-03-05 18:43:00 +010051}
52
Willy Tarreau79584222009-03-06 09:18:27 +010053/* returns the number of remaining events that can occur on this freq counter
54 * while respecting <freq> and taking into account that <pend> events are
55 * already known to be pending. Returns 0 if limit was reached.
56 */
57unsigned int freq_ctr_remain(struct freq_ctr *ctr, unsigned int freq, unsigned int pend)
58{
Willy Tarreau3d8c5532009-03-06 14:29:25 +010059 unsigned int curr, past;
60 unsigned int age;
Willy Tarreau79584222009-03-06 09:18:27 +010061
Willy Tarreau3d8c5532009-03-06 14:29:25 +010062 curr = 0;
63 age = now.tv_sec - ctr->curr_sec;
Willy Tarreau79584222009-03-06 09:18:27 +010064
Willy Tarreau3d8c5532009-03-06 14:29:25 +010065 if (likely(age <= 1)) {
66 past = ctr->curr_ctr;
67 if (likely(!age)) {
68 curr = past;
69 past = ctr->prev_ctr;
70 }
Willy Tarreaueab777c2012-12-29 21:50:07 +010071 curr += mul32hi(past, ms_left_scaled);
Willy Tarreau3d8c5532009-03-06 14:29:25 +010072 }
73 curr += pend;
74
75 if (curr >= freq)
Willy Tarreau79584222009-03-06 09:18:27 +010076 return 0;
Willy Tarreau3d8c5532009-03-06 14:29:25 +010077 return freq - curr;
Willy Tarreau79584222009-03-06 09:18:27 +010078}
79
80/* return the expected wait time in ms before the next event may occur,
81 * respecting frequency <freq>, and assuming there may already be some pending
82 * events. It returns zero if we can proceed immediately, otherwise the wait
83 * time, which will be rounded down 1ms for better accuracy, with a minimum
84 * of one ms.
85 */
86unsigned int next_event_delay(struct freq_ctr *ctr, unsigned int freq, unsigned int pend)
87{
Willy Tarreau3d8c5532009-03-06 14:29:25 +010088 unsigned int curr, past;
89 unsigned int wait, age;
Willy Tarreau79584222009-03-06 09:18:27 +010090
Willy Tarreau3d8c5532009-03-06 14:29:25 +010091 past = 0;
92 curr = 0;
93 age = now.tv_sec - ctr->curr_sec;
Willy Tarreau79584222009-03-06 09:18:27 +010094
Willy Tarreau3d8c5532009-03-06 14:29:25 +010095 if (likely(age <= 1)) {
96 past = ctr->curr_ctr;
97 if (likely(!age)) {
98 curr = past;
99 past = ctr->prev_ctr;
100 }
Willy Tarreaueab777c2012-12-29 21:50:07 +0100101 curr += mul32hi(past, ms_left_scaled);
Willy Tarreau3d8c5532009-03-06 14:29:25 +0100102 }
103 curr += pend;
Willy Tarreau79584222009-03-06 09:18:27 +0100104
Willy Tarreau3d8c5532009-03-06 14:29:25 +0100105 if (curr < freq)
Willy Tarreau79584222009-03-06 09:18:27 +0100106 return 0;
107
Willy Tarreau3d8c5532009-03-06 14:29:25 +0100108 wait = 999 / curr;
Willy Tarreau79584222009-03-06 09:18:27 +0100109 return MAX(wait, 1);
110}
111
Willy Tarreau2970b0b2010-06-20 07:15:43 +0200112/* Reads a frequency counter taking history into account for missing time in
113 * current period. The period has to be passed in number of ticks and must
114 * match the one used to feed the counter. The counter value is reported for
115 * current date (now_ms). The return value has the same precision as one input
116 * data sample, so low rates over the period will be inaccurate but still
117 * appropriate for max checking. One trick we use for low values is to specially
118 * handle the case where the rate is between 0 and 1 in order to avoid flapping
119 * while waiting for the next event.
120 *
121 * For immediate limit checking, it's recommended to use freq_ctr_period_remain()
122 * instead which does not have the flapping correction, so that even frequencies
123 * as low as one event/period are properly handled.
124 *
125 * For measures over a 1-second period, it's better to use the implicit functions
126 * above.
127 */
128unsigned int read_freq_ctr_period(struct freq_ctr_period *ctr, unsigned int period)
129{
130 unsigned int curr, past;
131 unsigned int remain;
132
133 curr = ctr->curr_ctr;
134 past = ctr->prev_ctr;
135
136 remain = ctr->curr_tick + period - now_ms;
137 if (unlikely((int)remain < 0)) {
138 /* We're past the first period, check if we can still report a
139 * part of last period or if we're too far away.
140 */
141 remain += period;
142 if ((int)remain < 0)
143 return 0;
144 past = curr;
145 curr = 0;
146 }
147 if (past <= 1 && !curr)
148 return past; /* very low rate, avoid flapping */
149
150 curr += div64_32((unsigned long long)past * remain, period);
151 return curr;
152}
153
154/* Returns the number of remaining events that can occur on this freq counter
155 * while respecting <freq> events per period, and taking into account that
156 * <pend> events are already known to be pending. Returns 0 if limit was reached.
157 */
158unsigned int freq_ctr_remain_period(struct freq_ctr_period *ctr, unsigned int period,
159 unsigned int freq, unsigned int pend)
160{
161 unsigned int curr, past;
162 unsigned int remain;
163
164 curr = ctr->curr_ctr;
165 past = ctr->prev_ctr;
166
167 remain = ctr->curr_tick + period - now_ms;
168 if (likely((int)remain < 0)) {
169 /* We're past the first period, check if we can still report a
170 * part of last period or if we're too far away.
171 */
172 past = curr;
173 curr = 0;
174 remain += period;
175 if ((int)remain < 0)
176 past = 0;
177 }
178 if (likely(past))
179 curr += div64_32((unsigned long long)past * remain, period);
180
181 curr += pend;
182 freq -= curr;
183 if ((int)freq < 0)
184 freq = 0;
185 return freq;
186}
187
Willy Tarreau7f062c42009-03-05 18:43:00 +0100188
189/*
190 * Local variables:
191 * c-indent-level: 8
192 * c-basic-offset: 8
193 * End:
194 */