aboutsummaryrefslogtreecommitdiff
path: root/src/ats/gnunet-service-ats_normalization.c
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2015-02-08 13:04:27 +0000
committerChristian Grothoff <christian@grothoff.org>2015-02-08 13:04:27 +0000
commitb644458a5800a53f3b0196fe559d51a21dca70b9 (patch)
treefa7f8b8a497d5306b68f9f2fe41e565365f8c5c9 /src/ats/gnunet-service-ats_normalization.c
parent6115a1150c65bd4a33ed61c6e96594c4a73d86ac (diff)
downloadgnunet-b644458a5800a53f3b0196fe559d51a21dca70b9.tar.gz
gnunet-b644458a5800a53f3b0196fe559d51a21dca70b9.zip
simplify normalization logic, also have clients access norm array of address directly
Diffstat (limited to 'src/ats/gnunet-service-ats_normalization.c')
-rw-r--r--src/ats/gnunet-service-ats_normalization.c275
1 files changed, 99 insertions, 176 deletions
diff --git a/src/ats/gnunet-service-ats_normalization.c b/src/ats/gnunet-service-ats_normalization.c
index 23b7b0cb7..b3d8eba3f 100644
--- a/src/ats/gnunet-service-ats_normalization.c
+++ b/src/ats/gnunet-service-ats_normalization.c
@@ -27,6 +27,7 @@
27 * FIXME: rename to 'properties'!? merge with addresses!? 27 * FIXME: rename to 'properties'!? merge with addresses!?
28 */ 28 */
29#include "platform.h" 29#include "platform.h"
30#include <float.h>
30#include "gnunet_ats_service.h" 31#include "gnunet_ats_service.h"
31#include "gnunet-service-ats_addresses.h" 32#include "gnunet-service-ats_addresses.h"
32#include "gnunet-service-ats_normalization.h" 33#include "gnunet-service-ats_normalization.h"
@@ -36,7 +37,7 @@
36 37
37 38
38/** 39/**
39 * Quality Normalization 40 * Range information for normalization of quality properties.
40 */ 41 */
41struct Property 42struct Property
42{ 43{
@@ -46,9 +47,9 @@ struct Property
46 uint32_t prop_type; 47 uint32_t prop_type;
47 48
48 /** 49 /**
49 * Corresponding enum value. FIXME: type? 50 * Corresponding enum value of the respective quality property.
50 */ 51 */
51 uint32_t atsi_type; 52 enum GNUNET_ATS_Property atsi_type;
52 53
53 /** 54 /**
54 * Minimum value we see for this property across all addresses. 55 * Minimum value we see for this property across all addresses.
@@ -63,80 +64,34 @@ struct Property
63 64
64 65
65/** 66/**
66 * Range information for all properties we see. 67 * Range information for all quality properties we see.
67 */ 68 */
68static struct Property properties[GNUNET_ATS_QualityPropertiesCount]; 69static struct Property properties[GNUNET_ATS_QualityPropertiesCount];
69 70
70 71
71/**
72 * Get the normalized properties values for a specific peer or
73 * the default values if no normalized values are available.
74 *
75 * @param cls ignored
76 * @param address the address
77 * @return pointer to the values, can be indexed with GNUNET_ATS_PreferenceKind
78 */
79const double *
80GAS_normalization_get_properties (void *cls,
81 const struct ATS_Address *address)
82{
83 static double norm_values[GNUNET_ATS_QualityPropertiesCount];
84 unsigned int i;
85
86 for (i = 0; i < GNUNET_ATS_QualityPropertiesCount; i++)
87 {
88 if ((address->atsin[i].norm >= 1.0) && (address->atsin[i].norm <= 2.0))
89 norm_values[i] = address->atsin[i].norm;
90 else
91 norm_values[i] = DEFAULT_REL_QUALITY;
92 }
93 return norm_values;
94}
95
96 72
97/** 73/**
98 * Normalize a specific ATS type with the values in queue. 74 * Add the value from @a atsi to the running average of the
75 * given @a ni quality property.
99 * 76 *
100 * @param address the address 77 * @param ni normalization information to update
101 * @param atsi the ats information 78 * @param atsi the ats information
102 * @return the new average or #GNUNET_ATS_VALUE_UNDEFINED
103 */ 79 */
104static uint32_t 80static void
105property_average (struct ATS_Address *address, 81property_average (struct GAS_NormalizationInfo *ni,
106 const struct GNUNET_ATS_Information *atsi) 82 const struct GNUNET_ATS_Information *atsi)
107{ 83{
108 struct GAS_NormalizationInfo *ni;
109 uint32_t current_type;
110 uint32_t current_val; 84 uint32_t current_val;
111 uint32_t res; 85 uint32_t res;
112 uint64_t sum; 86 uint64_t sum;
113 uint32_t count; 87 uint32_t count;
114 unsigned int c1; 88 unsigned int c1;
115 unsigned int index;
116 unsigned int props[] = GNUNET_ATS_QualityProperties;
117 89
118 /* Average the values of this property */
119 current_type = ntohl (atsi->type);
120 current_val = ntohl (atsi->value); 90 current_val = ntohl (atsi->value);
121 91 GNUNET_assert (GNUNET_ATS_VALUE_UNDEFINED != current_val);
122 for (c1 = 0; c1 < GNUNET_ATS_QualityPropertiesCount; c1++) 92 ni->atsi_abs[ni->avg_queue_index++] = current_val;
123 {
124 if (current_type == props[c1])
125 break;
126 }
127 if (c1 == GNUNET_ATS_QualityPropertiesCount)
128 {
129 GNUNET_break(0);
130 return GNUNET_ATS_VALUE_UNDEFINED;
131 }
132 index = c1;
133
134 ni = &address->atsin[index];
135 ni->atsi_abs[ni->avg_queue_index] = current_val;
136 ni->avg_queue_index++;
137 if (GAS_normalization_queue_length == ni->avg_queue_index) 93 if (GAS_normalization_queue_length == ni->avg_queue_index)
138 ni->avg_queue_index = 0; 94 ni->avg_queue_index = 0;
139
140 count = 0; 95 count = 0;
141 sum = 0; 96 sum = 0;
142 for (c1 = 0; c1 < GAS_normalization_queue_length; c1++) 97 for (c1 = 0; c1 < GAS_normalization_queue_length; c1++)
@@ -144,26 +99,12 @@ property_average (struct ATS_Address *address,
144 if (GNUNET_ATS_VALUE_UNDEFINED != ni->atsi_abs[c1]) 99 if (GNUNET_ATS_VALUE_UNDEFINED != ni->atsi_abs[c1])
145 { 100 {
146 count++; 101 count++;
147 if (GNUNET_ATS_VALUE_UNDEFINED > (sum + ni->atsi_abs[c1])) 102 sum += ni->atsi_abs[c1];
148 sum += ni->atsi_abs[c1];
149 else
150 {
151 sum = GNUNET_ATS_VALUE_UNDEFINED - 1;
152 GNUNET_break(0);
153 }
154 } 103 }
155 } 104 }
156 GNUNET_assert(0 != count); 105 GNUNET_assert (0 != count);
157 res = sum / count; 106 res = sum / count;
158 LOG(GNUNET_ERROR_TYPE_DEBUG,
159 "New average of `%s' created by adding %u from %u elements: %u\n",
160 GNUNET_ATS_print_property_type (current_type),
161 current_val,
162 count,
163 res,
164 sum);
165 ni->avg = res; 107 ni->avg = res;
166 return res;
167} 108}
168 109
169 110
@@ -190,8 +131,9 @@ struct FindMinMaxCtx
190 131
191 132
192/** 133/**
193 * Function called on X to find the minimum and maximum 134 * Function called for all addresses and peers to find the minimum and
194 * values for a given property. 135 * maximum (averaged) values for a given quality property. Given
136 * those, we can then calculate the normalized score.
195 * 137 *
196 * @param cls the `struct FindMinMaxCtx` 138 * @param cls the `struct FindMinMaxCtx`
197 * @param h which peer are we looking at (ignored) 139 * @param h which peer are we looking at (ignored)
@@ -220,34 +162,34 @@ find_min_max_it (void *cls,
220 * 162 *
221 * @param cls the `struct Property` with details on the 163 * @param cls the `struct Property` with details on the
222 * property and its global range 164 * property and its global range
223 * @param h which peer are we looking at (ignored) 165 * @param key which peer are we looking at (ignored)
224 * @param k the address for that peer, from where we get 166 * @param value the address for that peer, from where we get
225 * the original value and where we write the 167 * the original value and where we write the
226 * normalized value 168 * normalized value
227 * @return #GNUNET_OK (continue to iterate) 169 * @return #GNUNET_OK (continue to iterate)
228 */ 170 */
229static int 171static int
230normalize_address (void *cls, 172normalize_address (void *cls,
231 const struct GNUNET_PeerIdentity *h, 173 const struct GNUNET_PeerIdentity *key,
232 void *k) 174 void *value)
233{ 175{
234 struct Property *p = cls; 176 struct Property *p = cls;
235 struct ATS_Address *address = k; 177 struct ATS_Address *address = value;
236 double delta; 178 double delta;
237 double backup; 179 double update;
238 uint32_t avg_value; 180 uint32_t avg_value;
239 181
240 backup = address->atsin[p->prop_type].norm;
241 avg_value = address->atsin[p->prop_type].avg; 182 avg_value = address->atsin[p->prop_type].avg;
242 delta = p->max - p->min; 183 delta = p->max - p->min;
243 /* max - 2 * min + avg_value / max - min */ 184 /* max - 2 * min + avg_value / (max - min) */
244 if (0 != delta) 185 if (delta > DBL_EPSILON)
245 address->atsin[p->prop_type].norm = (delta + (avg_value - p->min)) / (delta); 186 update = DEFAULT_REL_QUALITY + (avg_value - p->min) / delta;
246 else 187 else
247 address->atsin[p->prop_type].norm = DEFAULT_REL_QUALITY; 188 update = DEFAULT_REL_QUALITY;
248 189
249 if (backup == address->atsin[p->prop_type].norm) 190 if (update == address->atsin[p->prop_type].norm)
250 return GNUNET_OK; 191 return GNUNET_OK;
192 address->atsin[p->prop_type].norm = update;
251 193
252 LOG (GNUNET_ERROR_TYPE_DEBUG, 194 LOG (GNUNET_ERROR_TYPE_DEBUG,
253 "Normalize `%s' address %p's '%s' with value %u to range [%u..%u] = %.3f\n", 195 "Normalize `%s' address %p's '%s' with value %u to range [%u..%u] = %.3f\n",
@@ -258,84 +200,31 @@ normalize_address (void *cls,
258 p->min, 200 p->min,
259 p->max, 201 p->max,
260 address->atsin[p->prop_type].norm); 202 address->atsin[p->prop_type].norm);
261 GAS_normalized_property_changed (address,
262 p->atsi_type,
263 address->atsin[p->prop_type].norm);
264 return GNUNET_OK; 203 return GNUNET_OK;
265} 204}
266 205
267 206
268/** 207/**
269 * Normalize @a avg_value to a range of values between [1.0, 2.0] 208 * Notify about change in normalized property.
270 * based on min/max values currently known.
271 * 209 *
272 * @param p the property 210 * @param cls the `struct Property` with details on the
273 * @param address the address 211 * property and its global range
274 * @param avg_value the value to normalize 212 * @param key which peer are we looking at (ignored)
213 * @param value the address for that peer
214 * @return #GNUNET_OK (continue to iterate)
275 */ 215 */
276static void 216static int
277property_normalize (struct Property *p, 217notify_change (void *cls,
278 struct ATS_Address *address, 218 const struct GNUNET_PeerIdentity *key,
279 uint32_t avg_value) 219 void *value)
280{ 220{
281 struct FindMinMaxCtx find_ctx; 221 struct Property *p = cls;
282 int addr_count; 222 struct ATS_Address *address = value;
283 int limits_changed;
284
285 find_ctx.p = p;
286 find_ctx.max = 0;
287 find_ctx.min = UINT32_MAX;
288 addr_count = GNUNET_CONTAINER_multipeermap_iterate (GSA_addresses,
289 &find_min_max_it,
290 &find_ctx);
291 if (0 == addr_count)
292 {
293 GNUNET_break(0);
294 return;
295 }
296
297 limits_changed = GNUNET_NO;
298 if (find_ctx.max != p->max)
299 {
300 LOG (GNUNET_ERROR_TYPE_DEBUG,
301 "Normalizing %s: new maximum %u -> recalculate all values\n",
302 GNUNET_ATS_print_property_type (p->atsi_type),
303 find_ctx.max);
304 p->max = find_ctx.max;
305 limits_changed = GNUNET_YES;
306 }
307
308 if ((find_ctx.min != p->min) && (find_ctx.min < p->max))
309 {
310 LOG (GNUNET_ERROR_TYPE_DEBUG,
311 "Normalizing %s: new minimum %u -> recalculate all values\n",
312 GNUNET_ATS_print_property_type (p->atsi_type),
313 find_ctx.min,
314 find_ctx.max);
315 p->min = find_ctx.min;
316 limits_changed = GNUNET_YES;
317 }
318 else if (find_ctx.min == p->max)
319 {
320 /* Only one value, so minimum has to be 0 */
321 p->min = 0;
322 }
323 223
324 /* Normalize the values of this property */ 224 GAS_normalized_property_changed (address,
325 if (GNUNET_NO == limits_changed) 225 p->atsi_type,
326 { 226 address->atsin[p->prop_type].norm);
327 /* normalize just this address */ 227 return GNUNET_OK;
328 normalize_address (p,
329 &address->peer,
330 address);
331 }
332 else
333 {
334 /* limits changed, normalize all addresses */
335 GNUNET_CONTAINER_multipeermap_iterate (GSA_addresses,
336 &normalize_address,
337 p);
338 }
339} 228}
340 229
341 230
@@ -351,12 +240,12 @@ GAS_normalization_normalize_property (struct ATS_Address *address,
351 const struct GNUNET_ATS_Information *atsi, 240 const struct GNUNET_ATS_Information *atsi,
352 uint32_t atsi_count) 241 uint32_t atsi_count)
353{ 242{
354 struct Property *cur_prop;
355 unsigned int c1; 243 unsigned int c1;
356 unsigned int c2; 244 unsigned int c2;
357 uint32_t current_type; 245 uint32_t current_type;
358 uint32_t current_val; 246 uint32_t old;
359 unsigned int existing_properties[] = GNUNET_ATS_QualityProperties; 247 struct FindMinMaxCtx find_ctx;
248 int range_changed;
360 249
361 LOG (GNUNET_ERROR_TYPE_DEBUG, 250 LOG (GNUNET_ERROR_TYPE_DEBUG,
362 "Updating %u elements for peer `%s'\n", 251 "Updating %u elements for peer `%s'\n",
@@ -368,30 +257,64 @@ GAS_normalization_normalize_property (struct ATS_Address *address,
368 current_type = ntohl (atsi[c1].type); 257 current_type = ntohl (atsi[c1].type);
369 258
370 for (c2 = 0; c2 < GNUNET_ATS_QualityPropertiesCount; c2++) 259 for (c2 = 0; c2 < GNUNET_ATS_QualityPropertiesCount; c2++)
371 { 260 if (current_type == properties[c2].atsi_type)
372 /* Check if type is valid */
373 if (current_type == existing_properties[c2])
374 break; 261 break;
375 }
376 if (GNUNET_ATS_QualityPropertiesCount == c2) 262 if (GNUNET_ATS_QualityPropertiesCount == c2)
377 { 263 {
378 /* Invalid property, continue with next element */ 264 /* Not a quality property, continue with next element */
379 continue; 265 continue;
380 } 266 }
381 /* Averaging */ 267 /* Calculate running average */
382 current_val = property_average (address, &atsi[c1]); 268 old = address->atsin[c2].avg;
383 if (GNUNET_ATS_VALUE_UNDEFINED == current_val) 269 property_average (&address->atsin[c2],
270 &atsi[c1]);
271 if (old == address->atsin[c2].avg)
272 continue; /* no change */
273 range_changed = GNUNET_NO;
274 if ( (old == properties[c2].min) ||
275 (old == properties[c2].max) ||
276 (address->atsin[c2].avg < properties[c2].min) ||
277 (address->atsin[c2].avg > properties[c2].max) )
384 { 278 {
385 GNUNET_break(0); 279 /* need to re-calculate min/max range, as it may have changed */
386 continue; 280 find_ctx.p = &properties[c2];
281 find_ctx.max = 0;
282 find_ctx.min = UINT32_MAX;
283 if (0 ==
284 GNUNET_CONTAINER_multipeermap_iterate (GSA_addresses,
285 &find_min_max_it,
286 &find_ctx))
287 {
288 GNUNET_break(0);
289 continue;
290 }
291 if ( (find_ctx.min != properties[c2].min) ||
292 (find_ctx.max != properties[c2].max) )
293 {
294 properties[c2].min = find_ctx.min;
295 properties[c2].max = find_ctx.max;
296 /* limits changed, (re)normalize all addresses */
297 range_changed = GNUNET_YES;
298 }
387 } 299 }
300 if (GNUNET_YES == range_changed)
301 GNUNET_CONTAINER_multipeermap_iterate (GSA_addresses,
302 &normalize_address,
303 &properties[c2]);
304 else
305 normalize_address (&properties[c2],
306 &address->peer,
307 address);
308 /* after all peers have been updated, notify about changes */
309 if (GNUNET_YES == range_changed)
310 GNUNET_CONTAINER_multipeermap_iterate (GSA_addresses,
311 &notify_change,
312 &properties[c2]);
313 else
314 notify_change (&properties[c2],
315 &address->peer,
316 address);
388 317
389 /* Normalizing */
390 /* Check min, max */
391 cur_prop = &properties[c2];
392 property_normalize (cur_prop,
393 address,
394 current_val);
395 } 318 }
396 GAS_plugin_solver_unlock (); 319 GAS_plugin_solver_unlock ();
397} 320}
@@ -404,7 +327,7 @@ void
404GAS_normalization_start () 327GAS_normalization_start ()
405{ 328{
406 unsigned int c1; 329 unsigned int c1;
407 unsigned int existing_properties[] = GNUNET_ATS_QualityProperties; 330 const unsigned int existing_properties[] = GNUNET_ATS_QualityProperties;
408 331
409 for (c1 = 0; c1 < GNUNET_ATS_QualityPropertiesCount; c1++) 332 for (c1 = 0; c1 < GNUNET_ATS_QualityPropertiesCount; c1++)
410 { 333 {