2 This file is part of GNUnet.
3 (C) 2011-2015 Christian Grothoff (and other contributing authors)
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 option) any later version.
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
22 * @file ats/gnunet-service-ats_normalization.c
23 * @brief ats service address: management of ATS properties and preferences normalization
24 * @author Matthias Wachs
25 * @author Christian Grothoff
27 * FIXME: rename to 'properties'!? merge with addresses!?
30 #include "gnunet_ats_service.h"
31 #include "gnunet-service-ats_addresses.h"
32 #include "gnunet-service-ats_normalization.h"
33 #include "gnunet-service-ats_plugins.h"
35 #define LOG(kind,...) GNUNET_log_from (kind, "ats-normalization",__VA_ARGS__)
39 * Quality Normalization
44 * Index into the properties array.
49 * Corresponding enum value. FIXME: type?
54 * Minimum value we see for this property across all addresses.
59 * Maximum value we see for this property across all addresses.
66 * Range information for all properties we see.
68 static struct Property properties[GNUNET_ATS_QualityPropertiesCount];
72 * Get the normalized properties values for a specific peer or
73 * the default values if no normalized values are available.
76 * @param address the address
77 * @return pointer to the values, can be indexed with GNUNET_ATS_PreferenceKind,
78 * default preferences if peer does not exist
81 GAS_normalization_get_properties (void *cls,
82 const struct ATS_Address *address)
84 static double norm_values[GNUNET_ATS_QualityPropertiesCount];
87 for (i = 0; i < GNUNET_ATS_QualityPropertiesCount; i++)
89 if ((address->atsin[i].norm >= 1.0) && (address->atsin[i].norm <= 2.0))
90 norm_values[i] = address->atsin[i].norm;
92 norm_values[i] = DEFAULT_REL_QUALITY;
99 * Normalize a specific ATS type with the values in queue.
101 * @param address the address
102 * @param atsi the ats information
103 * @return the new average or GNUNET_ATS_VALUE_UNDEFINED
106 property_average (struct ATS_Address *address,
107 const struct GNUNET_ATS_Information *atsi)
109 struct GAS_NormalizationInfo *ni;
110 uint32_t current_type;
111 uint32_t current_val;
117 unsigned int props[] = GNUNET_ATS_QualityProperties;
119 /* Average the values of this property */
120 current_type = ntohl (atsi->type);
121 current_val = ntohl (atsi->value);
123 for (c1 = 0; c1 < GNUNET_ATS_QualityPropertiesCount; c1++)
125 if (current_type == props[c1])
128 if (c1 == GNUNET_ATS_QualityPropertiesCount)
131 return GNUNET_ATS_VALUE_UNDEFINED;
135 ni = &address->atsin[index];
136 ni->atsi_abs[ni->avg_queue_index] = current_val;
137 ni->avg_queue_index++;
138 if (GAS_normalization_queue_length == ni->avg_queue_index)
139 ni->avg_queue_index = 0;
143 for (c1 = 0; c1 < GAS_normalization_queue_length; c1++)
145 if (GNUNET_ATS_VALUE_UNDEFINED != ni->atsi_abs[c1])
148 if (GNUNET_ATS_VALUE_UNDEFINED > (sum + ni->atsi_abs[c1]))
149 sum += ni->atsi_abs[c1];
152 sum = GNUNET_ATS_VALUE_UNDEFINED - 1;
157 GNUNET_assert(0 != count);
159 LOG(GNUNET_ERROR_TYPE_DEBUG,
160 "New average of `%s' created by adding %u from %u elements: %u\n",
161 GNUNET_ATS_print_property_type (current_type),
172 * Closure for #find_min_max_it().
177 * Property we are looking for.
182 * Set to mimimum value observed.
187 * Set to maximum value observed.
194 * Function called on X to find the minimum and maximum
195 * values for a given property.
197 * @param cls the `struct FindMinMaxCtx`
198 * @param h which peer are we looking at (ignored)
199 * @param k the address for that peer
200 * @return #GNUNET_OK (continue to iterate)
203 find_min_max_it (void *cls,
204 const struct GNUNET_PeerIdentity *h,
207 struct FindMinMaxCtx *find_res = cls;
208 const struct ATS_Address *a = k;
210 find_res->max = GNUNET_MAX (find_res->max,
211 a->atsin[find_res->p->prop_type].avg);
212 find_res->min = GNUNET_MIN (find_res->min,
213 a->atsin[find_res->p->prop_type].avg);
219 * Normalize the property value for a given address based
220 * on the range we know that property value has globally.
222 * @param cls the `struct Property` with details on the
223 * property and its global range
224 * @param h which peer are we looking at (ignored)
225 * @param k the address for that peer, from where we get
226 * the original value and where we write the
228 * @return #GNUNET_OK (continue to iterate)
231 normalize_address (void *cls,
232 const struct GNUNET_PeerIdentity *h,
235 struct Property *p = cls;
236 struct ATS_Address *address = k;
241 backup = address->atsin[p->prop_type].norm;
242 avg_value = address->atsin[p->prop_type].avg;
243 delta = p->max - p->min;
244 /* max - 2 * min + avg_value / max - min */
246 address->atsin[p->prop_type].norm = (delta + (avg_value - p->min)) / (delta);
248 address->atsin[p->prop_type].norm = DEFAULT_REL_QUALITY;
250 if (backup == address->atsin[p->prop_type].norm)
253 LOG (GNUNET_ERROR_TYPE_DEBUG,
254 "Normalize `%s' address %p's '%s' with value %u to range [%u..%u] = %.3f\n",
255 GNUNET_i2s (&address->peer), address,
256 GNUNET_ATS_print_property_type (p->atsi_type),
257 address->atsin[p->prop_type].avg, p->min, p->max,
258 address->atsin[p->prop_type].norm);
259 GAS_normalized_property_changed (address,
261 address->atsin[p->prop_type].norm);
267 * Normalize @a avg_value to a range of values between [1.0, 2.0]
268 * based on min/max values currently known.
270 * @param p the property
271 * @param address the address
272 * @param avg_value the value to normalize
275 property_normalize (struct Property *p,
276 struct ATS_Address *address,
279 struct FindMinMaxCtx find_ctx;
285 find_ctx.min = UINT32_MAX;
286 addr_count = GNUNET_CONTAINER_multipeermap_iterate (GSA_addresses,
295 limits_changed = GNUNET_NO;
296 if (find_ctx.max != p->max)
298 LOG (GNUNET_ERROR_TYPE_DEBUG,
299 "Normalizing %s: new maximum %u -> recalculate all values\n",
300 GNUNET_ATS_print_property_type (p->atsi_type),
302 p->max = find_ctx.max;
303 limits_changed = GNUNET_YES;
306 if ((find_ctx.min != p->min) && (find_ctx.min < p->max))
308 LOG (GNUNET_ERROR_TYPE_DEBUG,
309 "Normalizing %s: new minimum %u -> recalculate all values\n",
310 GNUNET_ATS_print_property_type (p->atsi_type),
313 p->min = find_ctx.min;
314 limits_changed = GNUNET_YES;
316 else if (find_ctx.min == p->max)
318 /* Only one value, so minimum has to be 0 */
322 /* Normalize the values of this property */
323 if (GNUNET_NO == limits_changed)
325 /* normalize just this address */
326 normalize_address (p,
332 /* limits changed, normalize all addresses */
333 GNUNET_CONTAINER_multipeermap_iterate (GSA_addresses,
341 * Update and normalize atsi performance information
343 * @param address the address to update
344 * @param atsi the array of performance information
345 * @param atsi_count the number of atsi information in the array
348 GAS_normalization_normalize_property (struct ATS_Address *address,
349 const struct GNUNET_ATS_Information *atsi,
352 struct Property *cur_prop;
355 uint32_t current_type;
356 uint32_t current_val;
357 unsigned int existing_properties[] = GNUNET_ATS_QualityProperties;
359 LOG (GNUNET_ERROR_TYPE_DEBUG,
360 "Updating %u elements for peer `%s'\n",
362 GNUNET_i2s (&address->peer));
363 GAS_plugin_solver_lock ();
364 for (c1 = 0; c1 < atsi_count; c1++)
366 current_type = ntohl (atsi[c1].type);
368 for (c2 = 0; c2 < GNUNET_ATS_QualityPropertiesCount; c2++)
370 /* Check if type is valid */
371 if (current_type == existing_properties[c2])
374 if (GNUNET_ATS_QualityPropertiesCount == c2)
376 /* Invalid property, continue with next element */
380 current_val = property_average (address, &atsi[c1]);
381 if (GNUNET_ATS_VALUE_UNDEFINED == current_val)
389 cur_prop = &properties[c2];
390 property_normalize (cur_prop,
394 GAS_plugin_solver_unlock ();
399 * Start the normalization component
402 GAS_normalization_start ()
405 unsigned int existing_properties[] = GNUNET_ATS_QualityProperties;
407 for (c1 = 0; c1 < GNUNET_ATS_QualityPropertiesCount; c1++)
409 properties[c1].prop_type = c1;
410 properties[c1].atsi_type = existing_properties[c1];
411 properties[c1].min = UINT32_MAX;
412 properties[c1].max = 0;
418 * Stop the normalization component and free all items
421 GAS_normalization_stop ()
427 /* end of gnunet-service-ats_normalization.c */