gnunet-service-ats_normalization.c 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301
  1. /*
  2. This file is part of GNUnet.
  3. Copyright (C) 2011-2015 Christian Grothoff (and other contributing authors)
  4. GNUnet is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published
  6. by the Free Software Foundation; either version 3, or (at your
  7. option) any later version.
  8. GNUnet is distributed in the hope that it will be useful, but
  9. WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  11. General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with GNUnet; see the file COPYING. If not, write to the
  14. Free Software Foundation, Inc., 59 Temple Place - Suite 330,
  15. Boston, MA 02111-1307, USA.
  16. */
  17. /**
  18. * @file ats/gnunet-service-ats_normalization.c
  19. * @brief ats service address: management of ATS properties and preferences normalization
  20. * @author Matthias Wachs
  21. * @author Christian Grothoff
  22. */
  23. #include "platform.h"
  24. #include <float.h>
  25. #include "gnunet_ats_service.h"
  26. #include "gnunet-service-ats_addresses.h"
  27. #include "gnunet-service-ats_normalization.h"
  28. #include "gnunet-service-ats_plugins.h"
  29. #define LOG(kind,...) GNUNET_log_from (kind, "ats-normalization",__VA_ARGS__)
  30. /**
  31. * Range information for normalization of quality properties.
  32. */
  33. struct PropertyRange
  34. {
  35. /**
  36. * Minimum value we see for this property across all addresses.
  37. */
  38. struct GNUNET_ATS_Properties min;
  39. /**
  40. * Maximum value we see for this property across all addresses.
  41. */
  42. struct GNUNET_ATS_Properties max;
  43. };
  44. /**
  45. * Range information for all quality properties we see.
  46. */
  47. static struct PropertyRange property_range;
  48. /**
  49. * Add the value from @a atsi to the running average of the
  50. * given @a ni quality property.
  51. *
  52. * @param current_val the updated value
  53. * @param ni normalization information to update
  54. */
  55. static void
  56. update_avg (uint64_t current_val,
  57. struct GAS_NormalizationInfo *ni)
  58. {
  59. double sum;
  60. uint32_t count;
  61. unsigned int c1;
  62. ni->atsi_abs[ni->avg_queue_index++] = current_val;
  63. if (GAS_normalization_queue_length == ni->avg_queue_index)
  64. ni->avg_queue_index = 0;
  65. count = 0;
  66. sum = 0.0;
  67. for (c1 = 0; c1 < GAS_normalization_queue_length; c1++)
  68. {
  69. if (UINT64_MAX != ni->atsi_abs[c1])
  70. {
  71. count++;
  72. sum += (double) ni->atsi_abs[c1];
  73. }
  74. }
  75. GNUNET_assert (0 != count);
  76. ni->avg = sum / count;
  77. }
  78. /**
  79. * Function called for all addresses and peers to find the minimum and
  80. * maximum (averaged) values for a given quality property. Given
  81. * those, we can then calculate the normalized score.
  82. *
  83. * @param cls the `struct PropertyRange`
  84. * @param h which peer are we looking at (ignored)
  85. * @param k the address for that peer
  86. * @return #GNUNET_OK (continue to iterate)
  87. */
  88. static int
  89. find_min_max_it (void *cls,
  90. const struct GNUNET_PeerIdentity *h,
  91. void *k)
  92. {
  93. struct PropertyRange *pr = cls;
  94. const struct ATS_Address *a = k;
  95. pr->max.utilization_out = GNUNET_MAX (pr->max.utilization_out,
  96. a->properties.utilization_out);
  97. pr->max.utilization_in = GNUNET_MAX (pr->max.utilization_in,
  98. a->properties.utilization_in);
  99. pr->max.distance = GNUNET_MAX (pr->max.distance,
  100. a->properties.distance);
  101. pr->max.delay = GNUNET_TIME_relative_max (pr->max.delay,
  102. a->properties.delay);
  103. pr->min.utilization_out = GNUNET_MIN (pr->min.utilization_out,
  104. a->properties.utilization_out);
  105. pr->min.utilization_in = GNUNET_MIN (pr->min.utilization_in,
  106. a->properties.utilization_in);
  107. pr->min.distance = GNUNET_MIN (pr->min.distance,
  108. a->properties.distance);
  109. pr->min.delay = GNUNET_TIME_relative_min (pr->min.delay,
  110. a->properties.delay);
  111. return GNUNET_OK;
  112. }
  113. /**
  114. * Compute the normalized value from the given @a ni range
  115. * data and the average value.
  116. *
  117. * @param min minimum value
  118. * @param max maximum value
  119. * @param ni normalization information to update
  120. */
  121. static void
  122. update_norm (uint64_t min,
  123. uint64_t max,
  124. struct GAS_NormalizationInfo *ni)
  125. {
  126. /* max - 2 * min + avg_value / (max - min) */
  127. if (min < max)
  128. ni->norm = DEFAULT_REL_QUALITY + (ni->avg - min) / (double) (max - min);
  129. else
  130. ni->norm = DEFAULT_REL_QUALITY;
  131. }
  132. /**
  133. * Normalize the property value for a given address based
  134. * on the range we know that property values have globally.
  135. *
  136. * @param cls NULL
  137. * @param key which peer are we looking at (ignored)
  138. * @param value the address for that peer, from where we get
  139. * the original value and where we write the
  140. * normalized value
  141. * @return #GNUNET_OK (continue to iterate)
  142. */
  143. static int
  144. normalize_address (void *cls,
  145. const struct GNUNET_PeerIdentity *key,
  146. void *value)
  147. {
  148. struct ATS_Address *address = value;
  149. update_norm (property_range.min.delay.rel_value_us,
  150. property_range.max.delay.rel_value_us,
  151. &address->norm_delay);
  152. update_norm (property_range.min.distance,
  153. property_range.max.distance,
  154. &address->norm_distance);
  155. update_norm (property_range.min.utilization_in,
  156. property_range.max.utilization_in,
  157. &address->norm_utilization_in);
  158. update_norm (property_range.min.utilization_out,
  159. property_range.max.utilization_out,
  160. &address->norm_utilization_out);
  161. return GNUNET_OK;
  162. }
  163. /**
  164. * Notify about change in normalized property.
  165. *
  166. * @param cls NULL
  167. * @param key which peer are we looking at (ignored)
  168. * @param value the address for that peer
  169. * @return #GNUNET_OK (continue to iterate)
  170. */
  171. static int
  172. notify_change (void *cls,
  173. const struct GNUNET_PeerIdentity *key,
  174. void *value)
  175. {
  176. struct ATS_Address *address = value;
  177. GAS_plugin_notify_property_changed (address);
  178. return GNUNET_OK;
  179. }
  180. /**
  181. * Initialize property range to the values corresponding
  182. * to an empty set.
  183. *
  184. * @param pr range to initialize
  185. */
  186. static void
  187. init_range (struct PropertyRange *pr)
  188. {
  189. memset (pr, 0, sizeof (struct PropertyRange));
  190. pr->min.utilization_out = UINT32_MAX;
  191. pr->min.utilization_in = UINT32_MAX;
  192. pr->min.distance = UINT32_MAX;
  193. pr->min.delay = GNUNET_TIME_UNIT_FOREVER_REL;
  194. }
  195. /**
  196. * Update and normalize atsi performance information
  197. *
  198. * @param address the address to update
  199. */
  200. void
  201. GAS_normalization_update_property (struct ATS_Address *address)
  202. {
  203. const struct GNUNET_ATS_Properties *prop = &address->properties;
  204. struct PropertyRange range;
  205. int range_changed;
  206. LOG (GNUNET_ERROR_TYPE_DEBUG,
  207. "Updating properties for peer `%s'\n",
  208. GNUNET_i2s (&address->peer));
  209. GAS_plugin_solver_lock ();
  210. update_avg (prop->delay.rel_value_us,
  211. &address->norm_delay);
  212. update_avg (prop->distance,
  213. &address->norm_distance);
  214. update_avg (prop->utilization_in,
  215. &address->norm_utilization_in);
  216. update_avg (prop->utilization_in,
  217. &address->norm_utilization_out);
  218. init_range (&range);
  219. GNUNET_CONTAINER_multipeermap_iterate (GSA_addresses,
  220. &find_min_max_it,
  221. &range);
  222. if (0 != memcmp (&range,
  223. &property_range,
  224. sizeof (struct PropertyRange)))
  225. {
  226. /* limits changed, (re)normalize all addresses */
  227. property_range = range;
  228. range_changed = GNUNET_YES;
  229. }
  230. if (GNUNET_YES == range_changed)
  231. GNUNET_CONTAINER_multipeermap_iterate (GSA_addresses,
  232. &normalize_address,
  233. NULL);
  234. else
  235. normalize_address (NULL,
  236. &address->peer,
  237. address);
  238. /* after all peers have been updated, notify about changes */
  239. if (GNUNET_YES == range_changed)
  240. GNUNET_CONTAINER_multipeermap_iterate (GSA_addresses,
  241. &notify_change,
  242. NULL);
  243. else
  244. notify_change (NULL,
  245. &address->peer,
  246. address);
  247. GAS_plugin_solver_unlock ();
  248. }
  249. /**
  250. * Start the normalization component
  251. */
  252. void
  253. GAS_normalization_start ()
  254. {
  255. init_range (&property_range);
  256. }
  257. /**
  258. * Stop the normalization component and free all items
  259. */
  260. void
  261. GAS_normalization_stop ()
  262. {
  263. /* nothing to do */
  264. }
  265. /* end of gnunet-service-ats_normalization.c */