2 This file is part of GNUnet.
3 Copyright (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
29 #include "gnunet_ats_service.h"
30 #include "gnunet-service-ats_addresses.h"
31 #include "gnunet-service-ats_normalization.h"
32 #include "gnunet-service-ats_plugins.h"
34 #define LOG(kind,...) GNUNET_log_from (kind, "ats-normalization",__VA_ARGS__)
38 * Range information for normalization of quality properties.
43 * Index into the properties array.
48 * Corresponding enum value of the respective quality property.
50 enum GNUNET_ATS_Property atsi_type;
53 * Minimum value we see for this property across all addresses.
58 * Maximum value we see for this property across all addresses.
65 * Range information for all quality properties we see.
67 static struct Property properties[GNUNET_ATS_QualityPropertiesCount];
72 * Add the value from @a atsi to the running average of the
73 * given @a ni quality property.
75 * @param ni normalization information to update
76 * @param atsi the ats information
79 property_average (struct GAS_NormalizationInfo *ni,
80 const struct GNUNET_ATS_Information *atsi)
88 current_val = ntohl (atsi->value);
89 GNUNET_assert (GNUNET_ATS_VALUE_UNDEFINED != current_val);
90 ni->atsi_abs[ni->avg_queue_index++] = current_val;
91 if (GAS_normalization_queue_length == ni->avg_queue_index)
92 ni->avg_queue_index = 0;
95 for (c1 = 0; c1 < GAS_normalization_queue_length; c1++)
97 if (GNUNET_ATS_VALUE_UNDEFINED != ni->atsi_abs[c1])
100 sum += ni->atsi_abs[c1];
103 GNUNET_assert (0 != count);
110 * Closure for #find_min_max_it().
115 * Property we are looking for.
120 * Set to mimimum value observed.
125 * Set to maximum value observed.
132 * Function called for all addresses and peers to find the minimum and
133 * maximum (averaged) values for a given quality property. Given
134 * those, we can then calculate the normalized score.
136 * @param cls the `struct FindMinMaxCtx`
137 * @param h which peer are we looking at (ignored)
138 * @param k the address for that peer
139 * @return #GNUNET_OK (continue to iterate)
142 find_min_max_it (void *cls,
143 const struct GNUNET_PeerIdentity *h,
146 struct FindMinMaxCtx *find_res = cls;
147 const struct ATS_Address *a = k;
149 find_res->max = GNUNET_MAX (find_res->max,
150 a->atsin[find_res->p->prop_type].avg);
151 find_res->min = GNUNET_MIN (find_res->min,
152 a->atsin[find_res->p->prop_type].avg);
158 * Normalize the property value for a given address based
159 * on the range we know that property value has globally.
161 * @param cls the `struct Property` with details on the
162 * property and its global range
163 * @param key which peer are we looking at (ignored)
164 * @param value the address for that peer, from where we get
165 * the original value and where we write the
167 * @return #GNUNET_OK (continue to iterate)
170 normalize_address (void *cls,
171 const struct GNUNET_PeerIdentity *key,
174 struct Property *p = cls;
175 struct ATS_Address *address = value;
180 avg_value = address->atsin[p->prop_type].avg;
181 delta = p->max - p->min;
182 /* max - 2 * min + avg_value / (max - min) */
183 if (delta > DBL_EPSILON)
184 update = DEFAULT_REL_QUALITY + (avg_value - p->min) / delta;
186 update = DEFAULT_REL_QUALITY;
188 if (update == address->atsin[p->prop_type].norm)
190 address->atsin[p->prop_type].norm = update;
192 LOG (GNUNET_ERROR_TYPE_DEBUG,
193 "Normalize `%s' address %p's '%s' with value %u to range [%u..%u] = %.3f\n",
194 GNUNET_i2s (&address->peer),
196 GNUNET_ATS_print_property_type (p->atsi_type),
197 address->atsin[p->prop_type].avg,
200 address->atsin[p->prop_type].norm);
206 * Notify about change in normalized property.
208 * @param cls the `struct Property` with details on the
209 * property and its global range
210 * @param key which peer are we looking at (ignored)
211 * @param value the address for that peer
212 * @return #GNUNET_OK (continue to iterate)
215 notify_change (void *cls,
216 const struct GNUNET_PeerIdentity *key,
219 struct Property *p = cls;
220 struct ATS_Address *address = value;
222 GAS_plugin_notify_property_changed (address,
224 address->atsin[p->prop_type].norm);
230 * Update and normalize atsi performance information
232 * @param address the address to update
233 * @param atsi the array of performance information
234 * @param atsi_count the number of atsi information in the array
237 GAS_normalization_update_property (struct ATS_Address *address,
238 const struct GNUNET_ATS_Information *atsi,
243 uint32_t current_type;
245 struct FindMinMaxCtx find_ctx;
248 LOG (GNUNET_ERROR_TYPE_DEBUG,
249 "Updating %u elements for peer `%s'\n",
251 GNUNET_i2s (&address->peer));
252 GAS_plugin_solver_lock ();
253 for (c1 = 0; c1 < atsi_count; c1++)
255 current_type = ntohl (atsi[c1].type);
257 for (c2 = 0; c2 < GNUNET_ATS_QualityPropertiesCount; c2++)
258 if (current_type == properties[c2].atsi_type)
260 if (GNUNET_ATS_QualityPropertiesCount == c2)
262 /* Not a quality property, continue with next element */
265 /* Calculate running average */
266 old = address->atsin[c2].avg;
267 property_average (&address->atsin[c2],
269 if (old == address->atsin[c2].avg)
270 continue; /* no change */
271 range_changed = GNUNET_NO;
272 if ( (old == properties[c2].min) ||
273 (old == properties[c2].max) ||
274 (address->atsin[c2].avg < properties[c2].min) ||
275 (address->atsin[c2].avg > properties[c2].max) )
277 /* need to re-calculate min/max range, as it may have changed */
278 find_ctx.p = &properties[c2];
280 find_ctx.min = UINT32_MAX;
282 GNUNET_CONTAINER_multipeermap_iterate (GSA_addresses,
289 if ( (find_ctx.min != properties[c2].min) ||
290 (find_ctx.max != properties[c2].max) )
292 properties[c2].min = find_ctx.min;
293 properties[c2].max = find_ctx.max;
294 /* limits changed, (re)normalize all addresses */
295 range_changed = GNUNET_YES;
298 if (GNUNET_YES == range_changed)
299 GNUNET_CONTAINER_multipeermap_iterate (GSA_addresses,
303 normalize_address (&properties[c2],
306 /* after all peers have been updated, notify about changes */
307 if (GNUNET_YES == range_changed)
308 GNUNET_CONTAINER_multipeermap_iterate (GSA_addresses,
312 notify_change (&properties[c2],
317 GAS_plugin_solver_unlock ();
322 * Start the normalization component
325 GAS_normalization_start ()
328 const unsigned int existing_properties[] = GNUNET_ATS_QualityProperties;
330 for (c1 = 0; c1 < GNUNET_ATS_QualityPropertiesCount; c1++)
332 properties[c1].prop_type = c1;
333 properties[c1].atsi_type = existing_properties[c1];
334 properties[c1].min = UINT32_MAX;
335 properties[c1].max = 0;
341 * Stop the normalization component and free all items
344 GAS_normalization_stop ()
350 /* end of gnunet-service-ats_normalization.c */