diff options
author | Christian Grothoff <christian@grothoff.org> | 2015-02-08 13:04:27 +0000 |
---|---|---|
committer | Christian Grothoff <christian@grothoff.org> | 2015-02-08 13:04:27 +0000 |
commit | b644458a5800a53f3b0196fe559d51a21dca70b9 (patch) | |
tree | fa7f8b8a497d5306b68f9f2fe41e565365f8c5c9 /src/ats/gnunet-service-ats_normalization.c | |
parent | 6115a1150c65bd4a33ed61c6e96594c4a73d86ac (diff) | |
download | gnunet-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.c | 275 |
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 | */ |
41 | struct Property | 42 | struct 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 | */ |
68 | static struct Property properties[GNUNET_ATS_QualityPropertiesCount]; | 69 | static 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 | */ | ||
79 | const double * | ||
80 | GAS_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 | */ |
104 | static uint32_t | 80 | static void |
105 | property_average (struct ATS_Address *address, | 81 | property_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 | */ |
229 | static int | 171 | static int |
230 | normalize_address (void *cls, | 172 | normalize_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 | */ |
276 | static void | 216 | static int |
277 | property_normalize (struct Property *p, | 217 | notify_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 | ¬ify_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 | |||
404 | GAS_normalization_start () | 327 | GAS_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 | { |