Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
document last changes
[simgrid.git] / src / nws_portability / timeouts.c
1 /* $Id$ */
2
3 #include "config_portability.h"
4
5 #include <stdlib.h>
6 #include <string.h>
7 #ifdef HAVE_MATH_H
8 #include <math.h>
9 #endif
10
11 #include "timeouts.h"
12 #include "diagnostic.h"
13 #include "forecast_api.h"
14 #include "osutil.h"
15
16 /* the default MAX timeout */
17 #define DEFAULT_MAX_TIMEOUT (120.0)
18 #define DEFAULT_MIN_TIMEOUT (5.0)
19
20 /* we have this number of entries */
21 #define HOW_MANY_ENTRIES (1024)
22
23 /* keep track of the measurements we got */
24 typedef struct {
25         IPAddress addr;
26         FORECASTAPI_ForecastState *state[TIMEOUT_TYPES_NUMBER];
27 } timeOutStruct;
28
29 static void *lock = NULL;                       /* local mutex */
30
31 /* we have few types to keep track of */
32 static timeOutStruct timeOuts[HOW_MANY_ENTRIES]; 
33
34 /* keep track of the current limits on the timeouts */
35 static double to_limits[TIMEOUT_TYPES_NUMBER*2];
36
37 /* helper to work with modulo HOW_MANY_ENTRIES */
38 #define MODPLUS(a,b,m) (((a) + (b)) % (m))
39 #define MODMINUS(a,b,m) (((a) - (b) + (m)) % (m))
40
41 /*
42  * Initialize the Hash structure 
43  */
44 static void 
45 InitHashStructure() {
46         unsigned int i,j;
47         static int initialized = 0;
48
49         /* let's do it only once */
50         if (initialized != 0) {
51                 return;
52         }
53
54         GetNWSLock(&lock);
55         initialized = 1;
56
57         for (i=0; i < HOW_MANY_ENTRIES; i++) {
58                 timeOuts[i].addr = 0;
59                 for (j=0; j < TIMEOUT_TYPES_NUMBER; j++) {
60                         timeOuts[i].state[j] = NULL;
61                 }
62         }
63         ReleaseNWSLock(&lock);
64
65         for (j=0; j < TIMEOUT_TYPES_NUMBER; j++) {
66                 /* set defaults to sane state */
67                 SetDefaultTimeout(j, DEFAULT_MIN_TIMEOUT, DEFAULT_MAX_TIMEOUT);
68         }
69 }
70
71 /* we use a simple hash table structure to speed up the access to the
72  * timeout structures. If #addr# is not in the table it is added and if
73  * the table is full, space is made for the addr.  
74  * Returns      # the index at which addr is been found
75  */
76 static int 
77 HashIndex(IPAddress addr) {
78         unsigned int i, end;
79
80         /* initialize the structure */
81         InitHashStructure();
82
83         i = addr % HOW_MANY_ENTRIES;
84         end = MODMINUS(i, 1, HOW_MANY_ENTRIES);
85
86         GetNWSLock(&lock);
87         for (; i != end; i = MODPLUS(i, 1, HOW_MANY_ENTRIES)) {
88                 if ((timeOuts[i].addr == addr) || (timeOuts[i].addr == 0)) {
89                         /* either we found it, or emtpy slot: is good */
90                         break;
91                 }
92                         
93         }
94         if (i == end) {
95                 /* table is full: emtpying one slot */
96                 i = addr % HOW_MANY_ENTRIES;
97                 timeOuts[i].addr = 0;
98         }
99
100         /* if this is the first time we have the item, get it to a sane
101          * state */
102         if (timeOuts[i].addr == 0) {
103                 timeOuts[i].addr = addr;
104                 for (end=0; end < TIMEOUT_TYPES_NUMBER; end++) {
105                         /* Initialize the forecaster state */
106                         if (timeOuts[i].state[end] != NULL) {
107                                 FORECASTAPI_FreeForecastState(&timeOuts[i].state[end]);
108                         }
109                         timeOuts[i].state[end] = FORECASTAPI_NewForecastState();
110                 }
111         }
112
113         ReleaseNWSLock(&lock);
114
115         return i;
116 }
117
118 void
119 SetDefaultTimeout(timeoutTypes type, double min, double max) {
120         /* sanity check */
121         if (type < RECV || type > USER3) {
122                 WARN("SetDefaultTimeout: unknown type\n");
123                 return;
124         }
125         if (min < 0) {
126                 min = 1;
127         }
128         if (max < min) {
129                 max = 2*min;
130         }
131
132         GetNWSLock(&lock);
133         to_limits[type*2] = min;
134         to_limits[type*2 + 1] = max;
135         ReleaseNWSLock(&lock);
136 }
137
138 void 
139 GetDefaultTimeout(timeoutTypes type, double *min, double *max) {
140         /* sanity check */
141         if (type < RECV || type > USER3) {
142                 WARN("SetDefaultTimeout: unknown type\n");
143                 return;
144         }
145         GetNWSLock(&lock);
146         *min = to_limits[type*2];
147         *max = to_limits[type*2 + 1];
148         ReleaseNWSLock(&lock);
149 }
150
151
152 double 
153 GetTimeOut(timeoutTypes type, IPAddress addr, long size) {
154         unsigned int i = -1;
155         double ret;
156         FORECASTAPI_ForecastCollection forecast;
157
158         /* sanity check */
159         if (type < 0 || type > USER3) {
160                 WARN("GetTimeOut: type out of range\n");
161                 return 0;
162         }
163
164         /* if addr is 0 (for example if it's a pipe) we pick the minimums
165          * timeout */
166         if (addr == 0) {
167                 return to_limits[type*2];
168         }
169
170         i = HashIndex(addr);
171
172         /* let's get a forecast */
173         GetNWSLock(&lock);
174         if (FORECASTAPI_ComputeForecast(timeOuts[i].state[type], &forecast) != 0) {
175                 forecast.forecasts[type].forecast = to_limits[type*2 + 1];
176         }
177         ReleaseNWSLock(&lock);
178
179         /* let's get 3 standard deviations (if we have sqrt) */
180 #ifdef HAVE_SQRT
181         ret = forecast.forecasts[0].forecast + 3 * sqrt(forecast.forecasts[FORECASTAPI_MSE_FORECAST].error);
182 #else
183         ret = forecast.forecasts[0].forecast + 2 * forecast.forecasts[FORECASTAPI_MAE_FORECAST].error;
184 #endif
185
186         /* adjust for the size of the packet */
187         if (size > 0) {
188                 ret = ret * size;
189         }
190
191         if (ret > to_limits[type*2 + 1]) {
192                 ret = to_limits[type*2 + 1];
193         } else if (ret < to_limits[type*2]) {
194                 ret = to_limits[type*2];
195         }
196
197         return ret;
198 }
199
200 void
201 SetTimeOut(timeoutTypes type, IPAddress addr, double duration, long size, int timedOut) {
202         unsigned int i;
203         FORECASTAPI_Measurement m;
204
205         /* sanity check */
206         if (type < 0 || type > USER3) {
207                 WARN("SetTimeOut: type out of range\n");
208                 return;
209         }
210         if (duration < 0) {
211                 WARN("SetTimeOut: duration negative?\n");
212                 return;
213         }
214
215         /* if addr is 0 (for example if it's a pipe) we return */
216         if (addr == 0) {
217                 return;
218         }
219
220         i = HashIndex(addr);
221
222         m.timeStamp = CurrentTime();
223         /* adjust for the size of the packet */
224         if (size > 0) {
225                 m.measurement = duration / size;
226         } else {
227                 m.measurement = duration;
228         }
229
230         /* adjustments if we timed out before */
231         if (timedOut) {
232                 m.measurement += 5;
233         }
234         GetNWSLock(&lock);
235         FORECASTAPI_UpdateForecast(timeOuts[i].state[type], &m, 1);
236         ReleaseNWSLock(&lock);
237 }