gnunet-service-ats_normalization.c 8.4 KB

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