diff options
Diffstat (limited to 'src/ats/plugin_ats_mlp.c')
-rw-r--r-- | src/ats/plugin_ats_mlp.c | 2924 |
1 files changed, 0 insertions, 2924 deletions
diff --git a/src/ats/plugin_ats_mlp.c b/src/ats/plugin_ats_mlp.c deleted file mode 100644 index 6ab823b1e..000000000 --- a/src/ats/plugin_ats_mlp.c +++ /dev/null | |||
@@ -1,2924 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2011-2014 GNUnet e.V. | ||
4 | |||
5 | GNUnet is free software: you can redistribute it and/or modify it | ||
6 | under the terms of the GNU Affero General Public License as published | ||
7 | by the Free Software Foundation, either version 3 of the License, | ||
8 | or (at your option) any later version. | ||
9 | |||
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 | Affero General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Affero General Public License | ||
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | */ | ||
20 | |||
21 | /** | ||
22 | * @file ats/plugin_ats_mlp.c | ||
23 | * @brief ats mlp problem solver | ||
24 | * @author Matthias Wachs | ||
25 | * @author Christian Grothoff | ||
26 | */ | ||
27 | #include "platform.h" | ||
28 | #include "gnunet_util_lib.h" | ||
29 | #include "gnunet_ats_service.h" | ||
30 | #include "gnunet_ats_plugin.h" | ||
31 | #include "gnunet-service-ats_addresses.h" | ||
32 | #include "gnunet_statistics_service.h" | ||
33 | #include <float.h> | ||
34 | #include <glpk.h> | ||
35 | |||
36 | |||
37 | #define BIG_M_VALUE (UINT32_MAX) / 10 | ||
38 | #define BIG_M_STRING "unlimited" | ||
39 | |||
40 | #define MLP_AVERAGING_QUEUE_LENGTH 3 | ||
41 | |||
42 | #define MLP_MAX_EXEC_DURATION GNUNET_TIME_relative_multiply ( \ | ||
43 | GNUNET_TIME_UNIT_SECONDS, 10) | ||
44 | #define MLP_MAX_ITERATIONS 4096 | ||
45 | |||
46 | #define MLP_DEFAULT_D 1.0 | ||
47 | #define MLP_DEFAULT_R 1.0 | ||
48 | #define MLP_DEFAULT_U 1.0 | ||
49 | #define MLP_DEFAULT_QUALITY 1.0 | ||
50 | #define MLP_DEFAULT_MIN_CONNECTIONS 4 | ||
51 | #define MLP_DEFAULT_PEER_PREFERENCE 1.0 | ||
52 | |||
53 | #define MLP_NaN -1 | ||
54 | #define MLP_UNDEFINED 0 | ||
55 | #define GLP_YES 1.0 | ||
56 | #define GLP_NO 0.0 | ||
57 | |||
58 | enum MLP_Output_Format | ||
59 | { | ||
60 | MLP_MPS, | ||
61 | MLP_CPLEX, | ||
62 | MLP_GLPK | ||
63 | }; | ||
64 | |||
65 | |||
66 | enum QualityMetrics | ||
67 | { | ||
68 | RQ_QUALITY_METRIC_DELAY = 0, | ||
69 | RQ_QUALITY_METRIC_DISTANCE = 1, | ||
70 | RQ_QUALITY_METRIC_COUNT = 2 | ||
71 | }; | ||
72 | |||
73 | |||
74 | static const char * | ||
75 | print_quality_type (enum QualityMetrics qm) | ||
76 | { | ||
77 | switch (qm) | ||
78 | { | ||
79 | case RQ_QUALITY_METRIC_DELAY: | ||
80 | return "delay"; | ||
81 | |||
82 | case RQ_QUALITY_METRIC_DISTANCE: | ||
83 | return "distance"; | ||
84 | |||
85 | default: | ||
86 | GNUNET_break (0); | ||
87 | return NULL; | ||
88 | } | ||
89 | } | ||
90 | |||
91 | |||
92 | struct MLP_Solution | ||
93 | { | ||
94 | int lp_res; | ||
95 | int lp_presolv; | ||
96 | int mip_res; | ||
97 | int mip_presolv; | ||
98 | |||
99 | double lp_objective_value; | ||
100 | double mlp_objective_value; | ||
101 | double mlp_gap; | ||
102 | double lp_mlp_gap; | ||
103 | |||
104 | int p_elements; | ||
105 | int p_cols; | ||
106 | int p_rows; | ||
107 | |||
108 | int n_peers; | ||
109 | int n_addresses; | ||
110 | }; | ||
111 | |||
112 | struct ATS_Peer | ||
113 | { | ||
114 | struct GNUNET_PeerIdentity id; | ||
115 | |||
116 | /* Was this peer already added to the current problem? */ | ||
117 | int processed; | ||
118 | |||
119 | /* constraint 2: 1 address per peer*/ | ||
120 | unsigned int r_c2; | ||
121 | |||
122 | /* constraint 9: relativity */ | ||
123 | unsigned int r_c9; | ||
124 | |||
125 | /* Legacy preference value */ | ||
126 | double f; | ||
127 | }; | ||
128 | |||
129 | struct MLP_Problem | ||
130 | { | ||
131 | /** | ||
132 | * GLPK (MLP) problem object | ||
133 | */ | ||
134 | glp_prob *prob; | ||
135 | |||
136 | /* Number of addresses in problem */ | ||
137 | unsigned int num_addresses; | ||
138 | /* Number of peers in problem */ | ||
139 | unsigned int num_peers; | ||
140 | /* Number of elements in problem matrix */ | ||
141 | unsigned int num_elements; | ||
142 | |||
143 | /* Row index constraint 2: */ | ||
144 | unsigned int r_c2; | ||
145 | /* Row index constraint 4: minimum connections */ | ||
146 | unsigned int r_c4; | ||
147 | /* Row index constraint 6: maximize diversity */ | ||
148 | unsigned int r_c6; | ||
149 | /* Row index constraint 8: utilization*/ | ||
150 | unsigned int r_c8; | ||
151 | /* Row index constraint 9: relativity*/ | ||
152 | unsigned int r_c9; | ||
153 | /* Row indices quality metrics */ | ||
154 | int r_q[RQ_QUALITY_METRIC_COUNT]; | ||
155 | /* Row indices ATS network quotas */ | ||
156 | int r_quota[GNUNET_NT_COUNT]; | ||
157 | |||
158 | /* Column index Diversity (D) column */ | ||
159 | int c_d; | ||
160 | /* Column index Utilization (U) column */ | ||
161 | int c_u; | ||
162 | /* Column index Proportionality (R) column */ | ||
163 | int c_r; | ||
164 | /* Column index quality metrics */ | ||
165 | int c_q[RQ_QUALITY_METRIC_COUNT]; | ||
166 | |||
167 | /* Problem matrix */ | ||
168 | /* Current index */ | ||
169 | unsigned int ci; | ||
170 | /* Row index array */ | ||
171 | int *ia; | ||
172 | /* Column index array */ | ||
173 | int *ja; | ||
174 | /* Column index value */ | ||
175 | double *ar; | ||
176 | }; | ||
177 | |||
178 | struct MLP_Variables | ||
179 | { | ||
180 | /* Big M value for bandwidth capping */ | ||
181 | double BIG_M; | ||
182 | |||
183 | /* MIP Gap */ | ||
184 | double mip_gap; | ||
185 | |||
186 | /* LP MIP Gap */ | ||
187 | double lp_mip_gap; | ||
188 | |||
189 | /* Number of quality metrics @deprecated, use RQ_QUALITY_METRIC_COUNT */ | ||
190 | int m_q; | ||
191 | |||
192 | /* Number of quality metrics */ | ||
193 | int m_rc; | ||
194 | |||
195 | /* Quality metric coefficients*/ | ||
196 | double co_Q[RQ_QUALITY_METRIC_COUNT]; | ||
197 | |||
198 | /* Ressource costs coefficients*/ | ||
199 | double co_RC[RQ_QUALITY_METRIC_COUNT]; | ||
200 | |||
201 | /* Diversity coefficient */ | ||
202 | double co_D; | ||
203 | |||
204 | /* Utility coefficient */ | ||
205 | double co_U; | ||
206 | |||
207 | /* Relativity coefficient */ | ||
208 | double co_R; | ||
209 | |||
210 | /* Minimum bandwidth assigned to an address */ | ||
211 | unsigned int b_min; | ||
212 | |||
213 | /* Minimum number of addresses with bandwidth assigned */ | ||
214 | unsigned int n_min; | ||
215 | |||
216 | /* Quotas */ | ||
217 | /* Array mapping array index to ATS network */ | ||
218 | int quota_index[GNUNET_NT_COUNT]; | ||
219 | /* Outbound quotas */ | ||
220 | unsigned long long quota_out[GNUNET_NT_COUNT]; | ||
221 | /* Inbound quotas */ | ||
222 | |||
223 | unsigned long long quota_in[GNUNET_NT_COUNT]; | ||
224 | |||
225 | /* ATS ressource costs | ||
226 | * array with GNUNET_ATS_QualityPropertiesCount elements | ||
227 | * contains mapping to GNUNET_ATS_Property | ||
228 | * */ | ||
229 | int rc[RQ_QUALITY_METRIC_COUNT]; | ||
230 | }; | ||
231 | |||
232 | /** | ||
233 | * MLP Handle | ||
234 | */ | ||
235 | struct GAS_MLP_Handle | ||
236 | { | ||
237 | struct GNUNET_ATS_PluginEnvironment *env; | ||
238 | |||
239 | /** | ||
240 | * Exclude peer from next result propagation | ||
241 | */ | ||
242 | const struct GNUNET_PeerIdentity *exclude_peer; | ||
243 | |||
244 | /** | ||
245 | * Encapsulation for the MLP problem | ||
246 | */ | ||
247 | struct MLP_Problem p; | ||
248 | |||
249 | /** | ||
250 | * Encapsulation for the MLP problem variables | ||
251 | */ | ||
252 | struct MLP_Variables pv; | ||
253 | |||
254 | /** | ||
255 | * Encapsulation for the MLP solution | ||
256 | */ | ||
257 | struct MLP_Solution ps; | ||
258 | |||
259 | /** | ||
260 | * Bulk lock | ||
261 | */ | ||
262 | int stat_bulk_lock; | ||
263 | |||
264 | /** | ||
265 | * Number of changes while solver was locked | ||
266 | */ | ||
267 | int stat_bulk_requests; | ||
268 | |||
269 | /** | ||
270 | * GLPK LP control parameter | ||
271 | */ | ||
272 | glp_smcp control_param_lp; | ||
273 | |||
274 | /** | ||
275 | * GLPK LP control parameter | ||
276 | */ | ||
277 | glp_iocp control_param_mlp; | ||
278 | |||
279 | /** | ||
280 | * Peers with pending address requests | ||
281 | */ | ||
282 | struct GNUNET_CONTAINER_MultiPeerMap *requested_peers; | ||
283 | |||
284 | /** | ||
285 | * Was the problem updated since last solution | ||
286 | */ | ||
287 | int stat_mlp_prob_updated; | ||
288 | |||
289 | /** | ||
290 | * Has the problem size changed since last solution | ||
291 | */ | ||
292 | int stat_mlp_prob_changed; | ||
293 | |||
294 | /** | ||
295 | * Solve the problem automatically when updates occur? | ||
296 | * Default: GNUNET_YES | ||
297 | * Can be disabled for test and measurements | ||
298 | */ | ||
299 | int opt_mlp_auto_solve; | ||
300 | |||
301 | /** | ||
302 | * Write all MILP problems to a MPS file | ||
303 | */ | ||
304 | int opt_dump_problem_all; | ||
305 | |||
306 | /** | ||
307 | * Write all MILP problem solutions to a file | ||
308 | */ | ||
309 | int opt_dump_solution_all; | ||
310 | |||
311 | /** | ||
312 | * Write MILP problems to a MPS file when solver fails | ||
313 | */ | ||
314 | int opt_dump_problem_on_fail; | ||
315 | |||
316 | /** | ||
317 | * Write MILP problem solutions to a file when solver fails | ||
318 | */ | ||
319 | int opt_dump_solution_on_fail; | ||
320 | |||
321 | /** | ||
322 | * solve feasibility only | ||
323 | */ | ||
324 | int opt_dbg_feasibility_only; | ||
325 | |||
326 | /** | ||
327 | * solve autoscale the problem | ||
328 | */ | ||
329 | int opt_dbg_autoscale_problem; | ||
330 | |||
331 | /** | ||
332 | * use the intopt presolver instead of simplex | ||
333 | */ | ||
334 | int opt_dbg_intopt_presolver; | ||
335 | |||
336 | /** | ||
337 | * Print GLPK output | ||
338 | */ | ||
339 | int opt_dbg_glpk_verbose; | ||
340 | |||
341 | /** | ||
342 | * solve autoscale the problem | ||
343 | */ | ||
344 | int opt_dbg_optimize_relativity; | ||
345 | |||
346 | /** | ||
347 | * solve autoscale the problem | ||
348 | */ | ||
349 | int opt_dbg_optimize_diversity; | ||
350 | |||
351 | /** | ||
352 | * solve autoscale the problem | ||
353 | */ | ||
354 | int opt_dbg_optimize_quality; | ||
355 | |||
356 | /** | ||
357 | * solve autoscale the problem | ||
358 | */ | ||
359 | int opt_dbg_optimize_utility; | ||
360 | |||
361 | |||
362 | /** | ||
363 | * Output format | ||
364 | */ | ||
365 | enum MLP_Output_Format opt_log_format; | ||
366 | }; | ||
367 | |||
368 | /** | ||
369 | * Address specific MLP information | ||
370 | */ | ||
371 | struct MLP_information | ||
372 | { | ||
373 | /** | ||
374 | * Bandwidth assigned outbound | ||
375 | */ | ||
376 | uint32_t b_out; | ||
377 | |||
378 | /** | ||
379 | * Bandwidth assigned inbound | ||
380 | */ | ||
381 | uint32_t b_in; | ||
382 | |||
383 | /** | ||
384 | * Address selected | ||
385 | */ | ||
386 | int n; | ||
387 | |||
388 | /** | ||
389 | * bandwidth column index | ||
390 | */ | ||
391 | signed int c_b; | ||
392 | |||
393 | /** | ||
394 | * address usage column | ||
395 | */ | ||
396 | signed int c_n; | ||
397 | |||
398 | /* row indexes */ | ||
399 | |||
400 | /** | ||
401 | * constraint 1: bandwidth capping | ||
402 | */ | ||
403 | unsigned int r_c1; | ||
404 | |||
405 | /** | ||
406 | * constraint 3: minimum bandwidth | ||
407 | */ | ||
408 | unsigned int r_c3; | ||
409 | }; | ||
410 | |||
411 | |||
412 | |||
413 | /** | ||
414 | * | ||
415 | * NOTE: Do not modify this documentation. This documentation is based on | ||
416 | * gnunet.org:/vcs/fsnsg/ats-paper.git/tech-doku/ats-tech-guide.tex | ||
417 | * use build_txt.sh to generate plaintext output | ||
418 | * | ||
419 | * The MLP solver (mlp) tries to finds an optimal bandwidth assignmentby | ||
420 | * optimizing an mixed integer programming problem. The MLP solver uses a | ||
421 | * number of constraints to find the best adddress for a peer and an optimal | ||
422 | * bandwidth assignment. mlp uses the GNU Linear Programming Kit to solve the | ||
423 | * MLP problem. | ||
424 | * | ||
425 | * We defined a constraint system to find an optimal bandwidth assignment. | ||
426 | * This constraint system uses as an input data addresses, bandwidth quotas, | ||
427 | * preferences and quality values. This constraint system is stored in an | ||
428 | * matrix based equotation system. | ||
429 | * | ||
430 | * 5 Using GLPK | ||
431 | * | ||
432 | * A (M)LP problem consists of a target function to optimizes, constraints | ||
433 | * and rows and columns. FIXME GLP uses three arrays to index the matrix: two | ||
434 | * integer arrays storing the row and column indices in the matrix and an | ||
435 | * float array to store the coeeficient. | ||
436 | * | ||
437 | * To solve the problem we first find an initial solution for the LP problem | ||
438 | * using the LP solver and then find an MLP solution based on this solution | ||
439 | * using the MLP solver. | ||
440 | * | ||
441 | * Solving (M)LP problems has the property that finding an initial solution | ||
442 | * for the LP problem is computationally expensive and finding the MLP | ||
443 | * solution is cheaper. This is especially interesting an existing LP | ||
444 | * solution can be reused if only coefficients in the matrix have changed | ||
445 | * (addresses updated). Only when the problem size changes (addresses added | ||
446 | * or deleted) a new LP solution has to be found. | ||
447 | * | ||
448 | * Intended usage | ||
449 | * The mlp solver solves the bandwidth assignment problem only on demand when | ||
450 | * an address suggestion is requested. When an address is requested mlp the | ||
451 | * solves the mlp problem and if the active address or the bandwidth assigned | ||
452 | * changes it calls the callback to addresses. The mlp solver gets notified | ||
453 | * about new addresses (adding sessions), removed addresses (address | ||
454 | * deletions) and address updates. To benefit from the mlp properties | ||
455 | * mentioned in section 5 the solver rembers if since the last solution | ||
456 | * addresses were added or deleted (problem size changed, problem has to be | ||
457 | * rebuild and solved from sratch) or if addresses were updated and the | ||
458 | * existing solution can be reused. | ||
459 | * | ||
460 | * 5.1 Input data | ||
461 | * | ||
462 | * The quotas for each network segment are passed by addresses. MLP can be | ||
463 | * adapted using configuration settings and uses the following parameters: | ||
464 | * * MLP_MAX_DURATION: | ||
465 | * Maximum duration for a MLP solution procees (default: 3 sec.) | ||
466 | * * MLP_MAX_ITERATIONS: | ||
467 | * Maximum number of iterations for a MLP solution process (default: | ||
468 | * 1024) | ||
469 | * * MLP_MIN_CONNECTIONS: | ||
470 | * Minimum number of desired connections (default: 4) | ||
471 | * * MLP_MIN_BANDWIDTH: | ||
472 | * Minimum amount of bandwidth assigned to an address (default: 1024) | ||
473 | * * MLP_COEFFICIENT_D: | ||
474 | * Diversity coefficient (default: 1.0) | ||
475 | * * MLP_COEFFICIENT_R: | ||
476 | * Relativity coefficient (default: 1.0) | ||
477 | * * MLP_COEFFICIENT_U: | ||
478 | * Utilization coefficient (default: 1.0) | ||
479 | * * MLP_COEFFICIENT_D: | ||
480 | * Diversity coefficient (default: 1.0) | ||
481 | * * MLP_COEFFICIENT_QUALITY_DELAY: | ||
482 | * Quality delay coefficient (default: 1.0) | ||
483 | * * MLP_COEFFICIENT_QUALITY_DISTANCE: | ||
484 | * Quality distance coefficient (default: 1.0) | ||
485 | * * MLP_COEFFICIENT_QUALITY_DISTANCE: | ||
486 | * Quality distance coefficient (default: 1.0) | ||
487 | * * MLP_COEFFICIENT_QUALITY_DISTANCE: | ||
488 | * Quality distance coefficient (default: 1.0) | ||
489 | * * MLP_COEFFICIENT_QUALITY_DISTANCE: | ||
490 | * Quality distance coefficient (default: 1.0) | ||
491 | * | ||
492 | * 5.2 Data structures used | ||
493 | * | ||
494 | * mlp has for each known peer a struct ATS_Peer containing information about | ||
495 | * a specific peer. The address field solver_information contains information | ||
496 | * about the mlp properties of this address. | ||
497 | * | ||
498 | * 5.3 Initializing | ||
499 | * | ||
500 | * During initialization mlp initializes the GLPK libray used to solve the | ||
501 | * MLP problem: it initializes the glpk environment and creates an initial LP | ||
502 | * problem. Next it loads the configuration values from the configuration or | ||
503 | * uses the default values configured in -addresses_mlp.h. The quotas used | ||
504 | * are given by addresses but may have to be adjusted. mlp uses a upper limit | ||
505 | * for the bandwidth assigned called BIG M and a minimum amount of bandwidth | ||
506 | * an address gets assigned as well as a minium desired number of | ||
507 | * connections. If the configured quota is bigger than BIG M, it is reduced | ||
508 | * to BIG M. If the configured quota is smaller than MLP_MIN_CONNECTIONS | ||
509 | * *MLP_MIN_BANDWIDTH it is increased to this value. | ||
510 | * | ||
511 | * 5.4 Shutdown | ||
512 | |||
513 | */ | ||
514 | |||
515 | #define LOG(kind, ...) GNUNET_log_from (kind, "ats-mlp", __VA_ARGS__) | ||
516 | |||
517 | /** | ||
518 | * Print debug output for mlp problem creation | ||
519 | */ | ||
520 | #define DEBUG_MLP_PROBLEM_CREATION GNUNET_NO | ||
521 | |||
522 | |||
523 | /** | ||
524 | * Intercept GLPK terminal output | ||
525 | * @param info the mlp handle | ||
526 | * @param s the string to print | ||
527 | * @return 0: glpk prints output on terminal, 0 != surpress output | ||
528 | */ | ||
529 | static int | ||
530 | mlp_term_hook (void *info, const char *s) | ||
531 | { | ||
532 | struct GAS_MLP_Handle *mlp = info; | ||
533 | |||
534 | if (mlp->opt_dbg_glpk_verbose) | ||
535 | LOG (GNUNET_ERROR_TYPE_ERROR, "%s", s); | ||
536 | return 1; | ||
537 | } | ||
538 | |||
539 | |||
540 | /** | ||
541 | * Reset peers for next problem creation | ||
542 | * | ||
543 | * @param cls not used | ||
544 | * @param key the key | ||
545 | * @param value ATS_Peer | ||
546 | * @return #GNUNET_OK | ||
547 | */ | ||
548 | static int | ||
549 | reset_peers (void *cls, | ||
550 | const struct GNUNET_PeerIdentity *key, | ||
551 | void *value) | ||
552 | { | ||
553 | struct ATS_Peer *peer = value; | ||
554 | |||
555 | peer->processed = GNUNET_NO; | ||
556 | return GNUNET_OK; | ||
557 | } | ||
558 | |||
559 | /** | ||
560 | * Delete the MLP problem and free the constrain matrix | ||
561 | * | ||
562 | * @param mlp the MLP handle | ||
563 | */ | ||
564 | static void | ||
565 | mlp_delete_problem (struct GAS_MLP_Handle *mlp) | ||
566 | { | ||
567 | int c; | ||
568 | |||
569 | if (mlp == NULL) | ||
570 | return; | ||
571 | if (mlp->p.prob != NULL) | ||
572 | { | ||
573 | glp_delete_prob (mlp->p.prob); | ||
574 | mlp->p.prob = NULL; | ||
575 | } | ||
576 | |||
577 | /* delete row index */ | ||
578 | if (mlp->p.ia != NULL) | ||
579 | { | ||
580 | GNUNET_free (mlp->p.ia); | ||
581 | mlp->p.ia = NULL; | ||
582 | } | ||
583 | |||
584 | /* delete column index */ | ||
585 | if (mlp->p.ja != NULL) | ||
586 | { | ||
587 | GNUNET_free (mlp->p.ja); | ||
588 | mlp->p.ja = NULL; | ||
589 | } | ||
590 | |||
591 | /* delete coefficients */ | ||
592 | if (mlp->p.ar != NULL) | ||
593 | { | ||
594 | GNUNET_free (mlp->p.ar); | ||
595 | mlp->p.ar = NULL; | ||
596 | } | ||
597 | mlp->p.ci = 0; | ||
598 | mlp->p.prob = NULL; | ||
599 | |||
600 | mlp->p.c_d = MLP_UNDEFINED; | ||
601 | mlp->p.c_r = MLP_UNDEFINED; | ||
602 | mlp->p.r_c2 = MLP_UNDEFINED; | ||
603 | mlp->p.r_c4 = MLP_UNDEFINED; | ||
604 | mlp->p.r_c6 = MLP_UNDEFINED; | ||
605 | mlp->p.r_c9 = MLP_UNDEFINED; | ||
606 | for (c = 0; c < RQ_QUALITY_METRIC_COUNT; c++) | ||
607 | mlp->p.r_q[c] = MLP_UNDEFINED; | ||
608 | for (c = 0; c < GNUNET_NT_COUNT; c++) | ||
609 | mlp->p.r_quota[c] = MLP_UNDEFINED; | ||
610 | mlp->p.ci = MLP_UNDEFINED; | ||
611 | |||
612 | |||
613 | GNUNET_CONTAINER_multipeermap_iterate (mlp->requested_peers, | ||
614 | &reset_peers, NULL); | ||
615 | } | ||
616 | |||
617 | |||
618 | /** | ||
619 | * Translate glpk status error codes to text | ||
620 | * @param retcode return code | ||
621 | * @return string with result | ||
622 | */ | ||
623 | static const char * | ||
624 | mlp_status_to_string (int retcode) | ||
625 | { | ||
626 | switch (retcode) | ||
627 | { | ||
628 | case GLP_UNDEF: | ||
629 | return "solution is undefined"; | ||
630 | |||
631 | case GLP_FEAS: | ||
632 | return "solution is feasible"; | ||
633 | |||
634 | case GLP_INFEAS: | ||
635 | return "solution is infeasible"; | ||
636 | |||
637 | case GLP_NOFEAS: | ||
638 | return "no feasible solution exists"; | ||
639 | |||
640 | case GLP_OPT: | ||
641 | return "solution is optimal"; | ||
642 | |||
643 | case GLP_UNBND: | ||
644 | return "solution is unbounded"; | ||
645 | |||
646 | default: | ||
647 | GNUNET_break (0); | ||
648 | return "unknown error"; | ||
649 | } | ||
650 | } | ||
651 | |||
652 | |||
653 | /** | ||
654 | * Translate glpk solver error codes to text | ||
655 | * @param retcode return code | ||
656 | * @return string with result | ||
657 | */ | ||
658 | static const char * | ||
659 | mlp_solve_to_string (int retcode) | ||
660 | { | ||
661 | switch (retcode) | ||
662 | { | ||
663 | case 0: | ||
664 | return "ok"; | ||
665 | |||
666 | case GLP_EBADB: | ||
667 | return "invalid basis"; | ||
668 | |||
669 | case GLP_ESING: | ||
670 | return "singular matrix"; | ||
671 | |||
672 | case GLP_ECOND: | ||
673 | return "ill-conditioned matrix"; | ||
674 | |||
675 | case GLP_EBOUND: | ||
676 | return "invalid bounds"; | ||
677 | |||
678 | case GLP_EFAIL: | ||
679 | return "solver failed"; | ||
680 | |||
681 | case GLP_EOBJLL: | ||
682 | return "objective lower limit reached"; | ||
683 | |||
684 | case GLP_EOBJUL: | ||
685 | return "objective upper limit reached"; | ||
686 | |||
687 | case GLP_EITLIM: | ||
688 | return "iteration limit exceeded"; | ||
689 | |||
690 | case GLP_ETMLIM: | ||
691 | return "time limit exceeded"; | ||
692 | |||
693 | case GLP_ENOPFS: | ||
694 | return "no primal feasible solution"; | ||
695 | |||
696 | case GLP_ENODFS: | ||
697 | return "no dual feasible solution"; | ||
698 | |||
699 | case GLP_EROOT: | ||
700 | return "root LP optimum not provided"; | ||
701 | |||
702 | case GLP_ESTOP: | ||
703 | return "search terminated by application"; | ||
704 | |||
705 | case GLP_EMIPGAP: | ||
706 | return "relative mip gap tolerance reached"; | ||
707 | |||
708 | case GLP_ENOFEAS: | ||
709 | return "no dual feasible solution"; | ||
710 | |||
711 | case GLP_ENOCVG: | ||
712 | return "no convergence"; | ||
713 | |||
714 | case GLP_EINSTAB: | ||
715 | return "numerical instability"; | ||
716 | |||
717 | case GLP_EDATA: | ||
718 | return "invalid data"; | ||
719 | |||
720 | case GLP_ERANGE: | ||
721 | return "result out of range"; | ||
722 | |||
723 | default: | ||
724 | GNUNET_break (0); | ||
725 | return "unknown error"; | ||
726 | } | ||
727 | } | ||
728 | |||
729 | |||
730 | struct CountContext | ||
731 | { | ||
732 | const struct GNUNET_CONTAINER_MultiPeerMap *map; | ||
733 | int result; | ||
734 | }; | ||
735 | |||
736 | static int | ||
737 | mlp_create_problem_count_addresses_it (void *cls, | ||
738 | const struct GNUNET_PeerIdentity *key, | ||
739 | void *value) | ||
740 | { | ||
741 | struct CountContext *cctx = cls; | ||
742 | |||
743 | /* Check if we have to add this peer due to a pending request */ | ||
744 | if (GNUNET_YES == GNUNET_CONTAINER_multipeermap_contains (cctx->map, key)) | ||
745 | cctx->result++; | ||
746 | return GNUNET_OK; | ||
747 | } | ||
748 | |||
749 | |||
750 | static int | ||
751 | mlp_create_problem_count_addresses (const struct | ||
752 | GNUNET_CONTAINER_MultiPeerMap * | ||
753 | requested_peers, | ||
754 | const struct | ||
755 | GNUNET_CONTAINER_MultiPeerMap *addresses) | ||
756 | { | ||
757 | struct CountContext cctx; | ||
758 | |||
759 | cctx.map = requested_peers; | ||
760 | cctx.result = 0; | ||
761 | GNUNET_CONTAINER_multipeermap_iterate (addresses, | ||
762 | &mlp_create_problem_count_addresses_it, | ||
763 | &cctx); | ||
764 | return cctx.result; | ||
765 | } | ||
766 | |||
767 | |||
768 | static int | ||
769 | mlp_create_problem_count_peers_it (void *cls, | ||
770 | const struct GNUNET_PeerIdentity *key, | ||
771 | void *value) | ||
772 | { | ||
773 | struct CountContext *cctx = cls; | ||
774 | |||
775 | /* Check if we have to addresses for the requested peer */ | ||
776 | if (GNUNET_YES == GNUNET_CONTAINER_multipeermap_contains (cctx->map, key)) | ||
777 | cctx->result++; | ||
778 | return GNUNET_OK; | ||
779 | } | ||
780 | |||
781 | |||
782 | static int | ||
783 | mlp_create_problem_count_peers (const struct | ||
784 | GNUNET_CONTAINER_MultiPeerMap *requested_peers, | ||
785 | const struct | ||
786 | GNUNET_CONTAINER_MultiPeerMap *addresses) | ||
787 | { | ||
788 | struct CountContext cctx; | ||
789 | |||
790 | cctx.map = addresses; | ||
791 | cctx.result = 0; | ||
792 | GNUNET_CONTAINER_multipeermap_iterate (requested_peers, | ||
793 | &mlp_create_problem_count_peers_it, | ||
794 | &cctx); | ||
795 | return cctx.result; | ||
796 | } | ||
797 | |||
798 | |||
799 | /** | ||
800 | * Updates an existing value in the matrix | ||
801 | * | ||
802 | * Extract the row, updates the value and updates the row in the problem | ||
803 | * | ||
804 | * @param p the mlp problem | ||
805 | * @param row the row to create the value in | ||
806 | * @param col the column to create the value in | ||
807 | * @param val the value to set | ||
808 | * @param line calling line for debbuging | ||
809 | * @return GNUNET_YES value changed, GNUNET_NO value did not change, GNUNET_SYSERR | ||
810 | * on error | ||
811 | */ | ||
812 | static int | ||
813 | mlp_create_problem_update_value (struct MLP_Problem *p, | ||
814 | int row, int col, double val, | ||
815 | int line) | ||
816 | { | ||
817 | int c_cols; | ||
818 | int c_elems; | ||
819 | int c1; | ||
820 | int res; | ||
821 | int found; | ||
822 | double *val_array; | ||
823 | int *ind_array; | ||
824 | |||
825 | GNUNET_assert (NULL != p->prob); | ||
826 | |||
827 | /* Get number of columns and prepare data structure */ | ||
828 | c_cols = glp_get_num_cols (p->prob); | ||
829 | if (0 >= c_cols) | ||
830 | return GNUNET_SYSERR; | ||
831 | |||
832 | val_array = GNUNET_malloc ((c_cols + 1) * sizeof(double)); | ||
833 | GNUNET_assert (NULL != val_array); | ||
834 | ind_array = GNUNET_malloc ((c_cols + 1) * sizeof(int)); | ||
835 | GNUNET_assert (NULL != ind_array); | ||
836 | /* Extract the row */ | ||
837 | |||
838 | /* Update the value */ | ||
839 | c_elems = glp_get_mat_row (p->prob, row, ind_array, val_array); | ||
840 | found = GNUNET_NO; | ||
841 | for (c1 = 1; c1 < (c_elems + 1); c1++) | ||
842 | { | ||
843 | if (ind_array[c1] == col) | ||
844 | { | ||
845 | found = GNUNET_YES; | ||
846 | break; | ||
847 | } | ||
848 | } | ||
849 | if (GNUNET_NO == found) | ||
850 | { | ||
851 | ind_array[c_elems + 1] = col; | ||
852 | val_array[c_elems + 1] = val; | ||
853 | LOG (GNUNET_ERROR_TYPE_DEBUG, "[P] Setting value in [%s : %s] to `%.2f'\n", | ||
854 | glp_get_row_name (p->prob, row), glp_get_col_name (p->prob, col), | ||
855 | val); | ||
856 | glp_set_mat_row (p->prob, row, c_elems + 1, ind_array, val_array); | ||
857 | GNUNET_free (ind_array); | ||
858 | GNUNET_free (val_array); | ||
859 | return GNUNET_YES; | ||
860 | } | ||
861 | else | ||
862 | { | ||
863 | /* Update value */ | ||
864 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
865 | "[P] Updating value in [%s : %s] from `%.2f' to `%.2f'\n", | ||
866 | glp_get_row_name (p->prob, row), glp_get_col_name (p->prob, col), | ||
867 | val_array[c1], val); | ||
868 | if (val != val_array[c1]) | ||
869 | res = GNUNET_YES; | ||
870 | else | ||
871 | res = GNUNET_NO; | ||
872 | val_array[c1] = val; | ||
873 | /* Update the row in the matrix */ | ||
874 | glp_set_mat_row (p->prob, row, c_elems, ind_array, val_array); | ||
875 | } | ||
876 | |||
877 | GNUNET_free (ind_array); | ||
878 | GNUNET_free (val_array); | ||
879 | return res; | ||
880 | } | ||
881 | |||
882 | /** | ||
883 | * Creates a new value in the matrix | ||
884 | * | ||
885 | * Sets the row and column index in the problem array and increments the | ||
886 | * position field | ||
887 | * | ||
888 | * @param p the mlp problem | ||
889 | * @param row the row to create the value in | ||
890 | * @param col the column to create the value in | ||
891 | * @param val the value to set | ||
892 | * @param line calling line for debbuging | ||
893 | */ | ||
894 | static void | ||
895 | mlp_create_problem_set_value (struct MLP_Problem *p, | ||
896 | int row, int col, double val, | ||
897 | int line) | ||
898 | { | ||
899 | if ((p->ci) >= p->num_elements) | ||
900 | { | ||
901 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
902 | "[P]: line %u: Request for index %u bigger than array size of %u\n", | ||
903 | line, p->ci + 1, p->num_elements); | ||
904 | GNUNET_break (0); | ||
905 | return; | ||
906 | } | ||
907 | if ((0 == row) || (0 == col)) | ||
908 | { | ||
909 | GNUNET_break (0); | ||
910 | LOG (GNUNET_ERROR_TYPE_ERROR, | ||
911 | "[P]: Invalid call from line %u: row = %u, col = %u\n", | ||
912 | line, row, col); | ||
913 | } | ||
914 | p->ia[p->ci] = row; | ||
915 | p->ja[p->ci] = col; | ||
916 | p->ar[p->ci] = val; | ||
917 | #if DEBUG_MLP_PROBLEM_CREATION | ||
918 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
919 | "[P]: line %u: Set value [%u,%u] in index %u == %.2f\n", | ||
920 | line, p->ia[p->ci], p->ja[p->ci], p->ci, p->ar[p->ci]); | ||
921 | #endif | ||
922 | p->ci++; | ||
923 | } | ||
924 | |||
925 | static int | ||
926 | mlp_create_problem_create_column (struct MLP_Problem *p, char *name, | ||
927 | unsigned int type, unsigned int bound, double | ||
928 | lb, double ub, | ||
929 | double coef) | ||
930 | { | ||
931 | int col = glp_add_cols (p->prob, 1); | ||
932 | |||
933 | glp_set_col_name (p->prob, col, name); | ||
934 | glp_set_col_bnds (p->prob, col, bound, lb, ub); | ||
935 | glp_set_col_kind (p->prob, col, type); | ||
936 | glp_set_obj_coef (p->prob, col, coef); | ||
937 | #if DEBUG_MLP_PROBLEM_CREATION | ||
938 | LOG (GNUNET_ERROR_TYPE_DEBUG, "[P]: Added column [%u] `%s': %.2f\n", | ||
939 | col, name, coef); | ||
940 | #endif | ||
941 | return col; | ||
942 | } | ||
943 | |||
944 | static int | ||
945 | mlp_create_problem_create_constraint (struct MLP_Problem *p, char *name, | ||
946 | unsigned int bound, double lb, double ub) | ||
947 | { | ||
948 | char *op; | ||
949 | int row = glp_add_rows (p->prob, 1); | ||
950 | |||
951 | /* set row name */ | ||
952 | glp_set_row_name (p->prob, row, name); | ||
953 | /* set row bounds: <= 0 */ | ||
954 | glp_set_row_bnds (p->prob, row, bound, lb, ub); | ||
955 | switch (bound) | ||
956 | { | ||
957 | case GLP_UP: | ||
958 | GNUNET_asprintf (&op, "-inf <= x <= %.2f", ub); | ||
959 | break; | ||
960 | |||
961 | case GLP_DB: | ||
962 | GNUNET_asprintf (&op, "%.2f <= x <= %.2f", lb, ub); | ||
963 | break; | ||
964 | |||
965 | case GLP_FX: | ||
966 | GNUNET_asprintf (&op, "%.2f == x == %.2f", lb, ub); | ||
967 | break; | ||
968 | |||
969 | case GLP_LO: | ||
970 | GNUNET_asprintf (&op, "%.2f <= x <= inf", lb); | ||
971 | break; | ||
972 | |||
973 | default: | ||
974 | GNUNET_asprintf (&op, "ERROR"); | ||
975 | break; | ||
976 | } | ||
977 | #if DEBUG_MLP_PROBLEM_CREATION | ||
978 | LOG (GNUNET_ERROR_TYPE_DEBUG, "[P]: Added row [%u] `%s': %s\n", | ||
979 | row, name, op); | ||
980 | #endif | ||
981 | GNUNET_free (op); | ||
982 | return row; | ||
983 | } | ||
984 | |||
985 | /** | ||
986 | * Create the | ||
987 | * - address columns b and n | ||
988 | * - address dependent constraint rows c1, c3 | ||
989 | * - peer dependent rows c2 and c9 | ||
990 | * - Set address dependent entries in problem matrix as well | ||
991 | */ | ||
992 | static int | ||
993 | mlp_create_problem_add_address_information (void *cls, | ||
994 | const struct | ||
995 | GNUNET_PeerIdentity *key, | ||
996 | void *value) | ||
997 | { | ||
998 | struct GAS_MLP_Handle *mlp = cls; | ||
999 | struct MLP_Problem *p = &mlp->p; | ||
1000 | struct ATS_Address *address = value; | ||
1001 | struct ATS_Peer *peer; | ||
1002 | struct MLP_information *mlpi; | ||
1003 | char *name; | ||
1004 | double cur_bigm; | ||
1005 | uint32_t addr_net; | ||
1006 | uint32_t addr_net_index; | ||
1007 | unsigned long long max_quota; | ||
1008 | int c; | ||
1009 | |||
1010 | /* Check if we have to add this peer due to a pending request */ | ||
1011 | if (GNUNET_NO == GNUNET_CONTAINER_multipeermap_contains (mlp->requested_peers, | ||
1012 | key)) | ||
1013 | return GNUNET_OK; | ||
1014 | |||
1015 | mlpi = address->solver_information; | ||
1016 | if (NULL == mlpi) | ||
1017 | { | ||
1018 | fprintf (stderr, "%s %p\n", GNUNET_i2s (&address->peer), address); | ||
1019 | GNUNET_break (0); | ||
1020 | return GNUNET_OK; | ||
1021 | } | ||
1022 | |||
1023 | addr_net = address->properties.scope; | ||
1024 | for (addr_net_index = 0; addr_net_index < GNUNET_NT_COUNT; addr_net_index++) | ||
1025 | { | ||
1026 | if (mlp->pv.quota_index[addr_net_index] == addr_net) | ||
1027 | break; | ||
1028 | } | ||
1029 | |||
1030 | if (addr_net_index >= GNUNET_NT_COUNT) | ||
1031 | { | ||
1032 | GNUNET_break (0); | ||
1033 | return GNUNET_OK; | ||
1034 | } | ||
1035 | |||
1036 | max_quota = 0; | ||
1037 | for (c = 0; c < GNUNET_NT_COUNT; c++) | ||
1038 | { | ||
1039 | if (mlp->pv.quota_out[c] > max_quota) | ||
1040 | max_quota = mlp->pv.quota_out[c]; | ||
1041 | if (mlp->pv.quota_in[c] > max_quota) | ||
1042 | max_quota = mlp->pv.quota_in[c]; | ||
1043 | } | ||
1044 | if (max_quota > mlp->pv.BIG_M) | ||
1045 | cur_bigm = (double) mlp->pv.BIG_M; | ||
1046 | else | ||
1047 | cur_bigm = max_quota; | ||
1048 | |||
1049 | |||
1050 | /* Get peer */ | ||
1051 | peer = GNUNET_CONTAINER_multipeermap_get (mlp->requested_peers, key); | ||
1052 | GNUNET_assert (NULL != peer); | ||
1053 | if (peer->processed == GNUNET_NO) | ||
1054 | { | ||
1055 | /* Add peer dependent constraints */ | ||
1056 | /* Add c2) One address active per peer */ | ||
1057 | GNUNET_asprintf (&name, "c2_%s", GNUNET_i2s (&address->peer)); | ||
1058 | peer->r_c2 = mlp_create_problem_create_constraint (p, name, GLP_FX, 1.0, | ||
1059 | 1.0); | ||
1060 | GNUNET_free (name); | ||
1061 | if (GNUNET_NO == mlp->opt_dbg_feasibility_only) | ||
1062 | { | ||
1063 | if (GNUNET_YES == mlp->opt_dbg_optimize_relativity) | ||
1064 | { | ||
1065 | /* Add c9) Relativity */ | ||
1066 | GNUNET_asprintf (&name, "c9_%s", GNUNET_i2s (&address->peer)); | ||
1067 | peer->r_c9 = mlp_create_problem_create_constraint (p, name, GLP_LO, 0.0, | ||
1068 | 0.0); | ||
1069 | GNUNET_free (name); | ||
1070 | /* c9) set coefficient */ | ||
1071 | mlp_create_problem_set_value (p, peer->r_c9, p->c_r, -peer->f, | ||
1072 | __LINE__); | ||
1073 | } | ||
1074 | } | ||
1075 | peer->processed = GNUNET_YES; | ||
1076 | } | ||
1077 | |||
1078 | /* Reset addresses' solver information */ | ||
1079 | mlpi->c_b = 0; | ||
1080 | mlpi->c_n = 0; | ||
1081 | mlpi->n = 0; | ||
1082 | mlpi->r_c1 = 0; | ||
1083 | mlpi->r_c3 = 0; | ||
1084 | |||
1085 | /* Add bandwidth column */ | ||
1086 | GNUNET_asprintf (&name, "b_%s_%s_%p", GNUNET_i2s (&address->peer), | ||
1087 | address->plugin, address); | ||
1088 | if (GNUNET_NO == mlp->opt_dbg_feasibility_only) | ||
1089 | { | ||
1090 | mlpi->c_b = mlp_create_problem_create_column (p, name, GLP_CV, GLP_LO, 0.0, | ||
1091 | 0.0, 0.0); | ||
1092 | } | ||
1093 | else | ||
1094 | { | ||
1095 | /* Maximize for bandwidth assignment in feasibility testing */ | ||
1096 | mlpi->c_b = mlp_create_problem_create_column (p, name, GLP_CV, GLP_LO, 0.0, | ||
1097 | 0.0, 1.0); | ||
1098 | } | ||
1099 | GNUNET_free (name); | ||
1100 | |||
1101 | /* Add address active column */ | ||
1102 | GNUNET_asprintf (&name, "n_%s_%s_%p", GNUNET_i2s (&address->peer), | ||
1103 | address->plugin, address); | ||
1104 | mlpi->c_n = mlp_create_problem_create_column (p, name, GLP_IV, GLP_DB, 0.0, | ||
1105 | 1.0, 0.0); | ||
1106 | GNUNET_free (name); | ||
1107 | |||
1108 | /* Add address dependent constraints */ | ||
1109 | /* Add c1) bandwidth capping: b_t + (-M) * n_t <= 0 */ | ||
1110 | GNUNET_asprintf (&name, "c1_%s_%s_%p", GNUNET_i2s (&address->peer), | ||
1111 | address->plugin, address); | ||
1112 | mlpi->r_c1 = mlp_create_problem_create_constraint (p, name, GLP_UP, 0.0, 0.0); | ||
1113 | GNUNET_free (name); | ||
1114 | /* c1) set b = 1 coefficient */ | ||
1115 | mlp_create_problem_set_value (p, mlpi->r_c1, mlpi->c_b, 1, __LINE__); | ||
1116 | /* c1) set n = - min (M, quota) coefficient */ | ||
1117 | cur_bigm = (double) mlp->pv.quota_out[addr_net_index]; | ||
1118 | if (cur_bigm > mlp->pv.BIG_M) | ||
1119 | cur_bigm = (double) mlp->pv.BIG_M; | ||
1120 | mlp_create_problem_set_value (p, mlpi->r_c1, mlpi->c_n, -cur_bigm, __LINE__); | ||
1121 | |||
1122 | /* Add constraint c 3) minimum bandwidth | ||
1123 | * b_t + (-n_t * b_min) >= 0 | ||
1124 | * */ | ||
1125 | GNUNET_asprintf (&name, "c3_%s_%s_%p", GNUNET_i2s (&address->peer), | ||
1126 | address->plugin, address); | ||
1127 | mlpi->r_c3 = mlp_create_problem_create_constraint (p, name, GLP_LO, 0.0, 0.0); | ||
1128 | GNUNET_free (name); | ||
1129 | |||
1130 | /* c3) set b = 1 coefficient */ | ||
1131 | mlp_create_problem_set_value (p, mlpi->r_c3, mlpi->c_b, 1, __LINE__); | ||
1132 | /* c3) set n = -b_min coefficient */ | ||
1133 | mlp_create_problem_set_value (p, mlpi->r_c3, mlpi->c_n, | ||
1134 | -((double ) mlp->pv.b_min), __LINE__); | ||
1135 | |||
1136 | |||
1137 | /* Set coefficient entries in invariant rows */ | ||
1138 | |||
1139 | /* Feasbility */ | ||
1140 | |||
1141 | /* c 4) minimum connections */ | ||
1142 | mlp_create_problem_set_value (p, p->r_c4, mlpi->c_n, 1, __LINE__); | ||
1143 | /* c 2) 1 address peer peer */ | ||
1144 | mlp_create_problem_set_value (p, peer->r_c2, mlpi->c_n, 1, __LINE__); | ||
1145 | /* c 10) obey network specific quotas | ||
1146 | * (1)*b_1 + ... + (1)*b_m <= quota_n | ||
1147 | */ | ||
1148 | mlp_create_problem_set_value (p, p->r_quota[addr_net_index], mlpi->c_b, 1, | ||
1149 | __LINE__); | ||
1150 | |||
1151 | /* Optimality */ | ||
1152 | if (GNUNET_NO == mlp->opt_dbg_feasibility_only) | ||
1153 | { | ||
1154 | /* c 6) maximize diversity */ | ||
1155 | mlp_create_problem_set_value (p, p->r_c6, mlpi->c_n, 1, __LINE__); | ||
1156 | /* c 9) relativity */ | ||
1157 | if (GNUNET_YES == mlp->opt_dbg_optimize_relativity) | ||
1158 | mlp_create_problem_set_value (p, peer->r_c9, mlpi->c_b, 1, __LINE__); | ||
1159 | /* c 8) utility */ | ||
1160 | if (GNUNET_YES == mlp->opt_dbg_optimize_utility) | ||
1161 | mlp_create_problem_set_value (p, p->r_c8, mlpi->c_b, 1, __LINE__); | ||
1162 | /* c 7) Optimize quality */ | ||
1163 | /* For all quality metrics, set quality of this address */ | ||
1164 | if (GNUNET_YES == mlp->opt_dbg_optimize_quality) | ||
1165 | { | ||
1166 | mlp_create_problem_set_value (p, | ||
1167 | p->r_q[RQ_QUALITY_METRIC_DELAY], | ||
1168 | mlpi->c_b, | ||
1169 | address->norm_delay.norm, | ||
1170 | __LINE__); | ||
1171 | mlp_create_problem_set_value (p, | ||
1172 | p->r_q[RQ_QUALITY_METRIC_DISTANCE], | ||
1173 | mlpi->c_b, | ||
1174 | address->norm_distance.norm, | ||
1175 | __LINE__); | ||
1176 | } | ||
1177 | } | ||
1178 | |||
1179 | return GNUNET_OK; | ||
1180 | } | ||
1181 | |||
1182 | |||
1183 | /** | ||
1184 | * Create the invariant columns c4, c6, c10, c8, c7 | ||
1185 | */ | ||
1186 | static void | ||
1187 | mlp_create_problem_add_invariant_rows (struct GAS_MLP_Handle *mlp, struct | ||
1188 | MLP_Problem *p) | ||
1189 | { | ||
1190 | int c; | ||
1191 | |||
1192 | /* Feasibility */ | ||
1193 | |||
1194 | /* Row for c4) minimum connection */ | ||
1195 | /* Number of minimum connections is min(|Peers|, n_min) */ | ||
1196 | p->r_c4 = mlp_create_problem_create_constraint (p, "c4", GLP_LO, | ||
1197 | (mlp->pv.n_min > | ||
1198 | p->num_peers) ? | ||
1199 | p->num_peers : mlp->pv.n_min, | ||
1200 | 0.0); | ||
1201 | |||
1202 | /* Rows for c 10) Enforce network quotas */ | ||
1203 | for (c = 0; c < GNUNET_NT_COUNT; c++) | ||
1204 | { | ||
1205 | char *text; | ||
1206 | GNUNET_asprintf (&text, "c10_quota_ats_%s", | ||
1207 | GNUNET_NT_to_string (mlp->pv.quota_index[c])); | ||
1208 | p->r_quota[c] = mlp_create_problem_create_constraint (p, text, GLP_DB, 0.0, | ||
1209 | mlp->pv.quota_out[c]); | ||
1210 | GNUNET_free (text); | ||
1211 | } | ||
1212 | |||
1213 | /* Optimality */ | ||
1214 | if (GNUNET_NO == mlp->opt_dbg_feasibility_only) | ||
1215 | { | ||
1216 | char *name; | ||
1217 | /* Add row for c6) Maximize for diversity */ | ||
1218 | if (GNUNET_YES == mlp->opt_dbg_optimize_diversity) | ||
1219 | { | ||
1220 | p->r_c6 = mlp_create_problem_create_constraint (p, "c6", GLP_FX, 0.0, | ||
1221 | 0.0); | ||
1222 | /* Set c6 ) Setting -D */ | ||
1223 | mlp_create_problem_set_value (p, p->r_c6, p->c_d, -1, __LINE__); | ||
1224 | } | ||
1225 | |||
1226 | /* Adding rows for c 8) Maximize utility */ | ||
1227 | if (GNUNET_YES == mlp->opt_dbg_optimize_utility) | ||
1228 | { | ||
1229 | p->r_c8 = mlp_create_problem_create_constraint (p, "c8", GLP_FX, 0.0, | ||
1230 | 0.0); | ||
1231 | /* -u */ | ||
1232 | mlp_create_problem_set_value (p, p->r_c8, p->c_u, -1, __LINE__); | ||
1233 | } | ||
1234 | |||
1235 | /* For all quality metrics: | ||
1236 | * c 7) Maximize quality, austerity */ | ||
1237 | if (GNUNET_YES == mlp->opt_dbg_optimize_quality) | ||
1238 | { | ||
1239 | for (c = 0; c < mlp->pv.m_q; c++) | ||
1240 | { | ||
1241 | GNUNET_asprintf (&name, | ||
1242 | "c7_q%i_%s", c, | ||
1243 | print_quality_type (c)); | ||
1244 | p->r_q[c] = mlp_create_problem_create_constraint (p, name, GLP_FX, 0.0, | ||
1245 | 0.0); | ||
1246 | GNUNET_free (name); | ||
1247 | mlp_create_problem_set_value (p, | ||
1248 | p->r_q[c], | ||
1249 | p->c_q[c], -1, __LINE__); | ||
1250 | } | ||
1251 | } | ||
1252 | } | ||
1253 | } | ||
1254 | |||
1255 | |||
1256 | /** | ||
1257 | * Create the invariant columns d, u, r, q0 ... qm | ||
1258 | */ | ||
1259 | static void | ||
1260 | mlp_create_problem_add_invariant_columns (struct GAS_MLP_Handle *mlp, struct | ||
1261 | MLP_Problem *p) | ||
1262 | { | ||
1263 | if (GNUNET_NO == mlp->opt_dbg_feasibility_only) | ||
1264 | { | ||
1265 | char *name; | ||
1266 | int c; | ||
1267 | |||
1268 | /* Diversity d column */ | ||
1269 | if (GNUNET_YES == mlp->opt_dbg_optimize_diversity) | ||
1270 | p->c_d = mlp_create_problem_create_column (p, "d", GLP_CV, GLP_LO, 0.0, | ||
1271 | 0.0, mlp->pv.co_D); | ||
1272 | |||
1273 | /* Utilization u column */ | ||
1274 | if (GNUNET_YES == mlp->opt_dbg_optimize_utility) | ||
1275 | p->c_u = mlp_create_problem_create_column (p, "u", GLP_CV, GLP_LO, 0.0, | ||
1276 | 0.0, mlp->pv.co_U); | ||
1277 | |||
1278 | /* Relativity r column */ | ||
1279 | if (GNUNET_YES == mlp->opt_dbg_optimize_relativity) | ||
1280 | p->c_r = mlp_create_problem_create_column (p, "r", GLP_CV, GLP_LO, 0.0, | ||
1281 | 0.0, mlp->pv.co_R); | ||
1282 | |||
1283 | /* Quality metric columns */ | ||
1284 | if (GNUNET_YES == mlp->opt_dbg_optimize_quality) | ||
1285 | { | ||
1286 | for (c = 0; c < mlp->pv.m_q; c++) | ||
1287 | { | ||
1288 | GNUNET_asprintf (&name, "q_%u", c); | ||
1289 | p->c_q[c] = mlp_create_problem_create_column (p, name, GLP_CV, GLP_LO, | ||
1290 | 0.0, 0.0, | ||
1291 | mlp->pv.co_Q[c]); | ||
1292 | GNUNET_free (name); | ||
1293 | } | ||
1294 | } | ||
1295 | } | ||
1296 | } | ||
1297 | |||
1298 | |||
1299 | /** | ||
1300 | * Create the MLP problem | ||
1301 | * | ||
1302 | * @param mlp the MLP handle | ||
1303 | * @return #GNUNET_OK or #GNUNET_SYSERR | ||
1304 | */ | ||
1305 | static int | ||
1306 | mlp_create_problem (struct GAS_MLP_Handle *mlp) | ||
1307 | { | ||
1308 | struct MLP_Problem *p = &mlp->p; | ||
1309 | int res = GNUNET_OK; | ||
1310 | |||
1311 | GNUNET_assert (p->prob == NULL); | ||
1312 | GNUNET_assert (p->ia == NULL); | ||
1313 | GNUNET_assert (p->ja == NULL); | ||
1314 | GNUNET_assert (p->ar == NULL); | ||
1315 | /* Reset MLP problem struct */ | ||
1316 | |||
1317 | /* create the glpk problem */ | ||
1318 | p->prob = glp_create_prob (); | ||
1319 | GNUNET_assert (NULL != p->prob); | ||
1320 | p->num_peers = mlp_create_problem_count_peers (mlp->requested_peers, | ||
1321 | mlp->env->addresses); | ||
1322 | p->num_addresses = mlp_create_problem_count_addresses (mlp->requested_peers, | ||
1323 | mlp->env->addresses); | ||
1324 | |||
1325 | /* Create problem matrix: 10 * #addresses + #q * #addresses + #q, + #peer + 2 + 1 */ | ||
1326 | p->num_elements = (10 * p->num_addresses + mlp->pv.m_q * p->num_addresses | ||
1327 | + mlp->pv.m_q + p->num_peers + 2 + 1); | ||
1328 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1329 | "Rebuilding problem for %u peer(s) and %u addresse(s) and %u quality metrics == %u elements\n", | ||
1330 | p->num_peers, | ||
1331 | p->num_addresses, | ||
1332 | mlp->pv.m_q, | ||
1333 | p->num_elements); | ||
1334 | |||
1335 | /* Set a problem name */ | ||
1336 | glp_set_prob_name (p->prob, "GNUnet ATS bandwidth distribution"); | ||
1337 | /* Set optimization direction to maximize */ | ||
1338 | glp_set_obj_dir (p->prob, GLP_MAX); | ||
1339 | |||
1340 | /* Create problem matrix */ | ||
1341 | /* last +1 caused by glpk index starting with one: [1..elements]*/ | ||
1342 | p->ci = 1; | ||
1343 | /* row index */ | ||
1344 | p->ia = GNUNET_malloc (p->num_elements * sizeof(int)); | ||
1345 | /* column index */ | ||
1346 | p->ja = GNUNET_malloc (p->num_elements * sizeof(int)); | ||
1347 | /* coefficient */ | ||
1348 | p->ar = GNUNET_malloc (p->num_elements * sizeof(double)); | ||
1349 | |||
1350 | if ((NULL == p->ia) || (NULL == p->ja) || (NULL == p->ar)) | ||
1351 | { | ||
1352 | LOG (GNUNET_ERROR_TYPE_ERROR, _ ( | ||
1353 | "Problem size too large, cannot allocate memory!\n")); | ||
1354 | return GNUNET_SYSERR; | ||
1355 | } | ||
1356 | |||
1357 | /* Adding invariant columns */ | ||
1358 | mlp_create_problem_add_invariant_columns (mlp, p); | ||
1359 | |||
1360 | /* Adding address independent constraint rows */ | ||
1361 | mlp_create_problem_add_invariant_rows (mlp, p); | ||
1362 | |||
1363 | /* Adding address dependent columns constraint rows */ | ||
1364 | GNUNET_CONTAINER_multipeermap_iterate (mlp->env->addresses, | ||
1365 | & | ||
1366 | mlp_create_problem_add_address_information, | ||
1367 | mlp); | ||
1368 | |||
1369 | /* Load the matrix */ | ||
1370 | LOG (GNUNET_ERROR_TYPE_DEBUG, "Loading matrix\n"); | ||
1371 | glp_load_matrix (p->prob, (p->ci) - 1, p->ia, p->ja, p->ar); | ||
1372 | if (GNUNET_YES == mlp->opt_dbg_autoscale_problem) | ||
1373 | { | ||
1374 | glp_scale_prob (p->prob, GLP_SF_AUTO); | ||
1375 | } | ||
1376 | |||
1377 | return res; | ||
1378 | } | ||
1379 | |||
1380 | |||
1381 | /** | ||
1382 | * Solves the LP problem | ||
1383 | * | ||
1384 | * @param mlp the MLP Handle | ||
1385 | * @return #GNUNET_OK if could be solved, #GNUNET_SYSERR on failure | ||
1386 | */ | ||
1387 | static int | ||
1388 | mlp_solve_lp_problem (struct GAS_MLP_Handle *mlp) | ||
1389 | { | ||
1390 | int res = 0; | ||
1391 | int res_status = 0; | ||
1392 | |||
1393 | res = glp_simplex (mlp->p.prob, &mlp->control_param_lp); | ||
1394 | if (0 == res) | ||
1395 | LOG (GNUNET_ERROR_TYPE_DEBUG, "Solving LP problem: %s\n", | ||
1396 | mlp_solve_to_string (res)); | ||
1397 | else | ||
1398 | LOG (GNUNET_ERROR_TYPE_DEBUG, "Solving LP problem failed: %s\n", | ||
1399 | mlp_solve_to_string (res)); | ||
1400 | |||
1401 | /* Analyze problem status */ | ||
1402 | res_status = glp_get_status (mlp->p.prob); | ||
1403 | switch (res_status) | ||
1404 | { | ||
1405 | case GLP_OPT: /* solution is optimal */ | ||
1406 | LOG (GNUNET_ERROR_TYPE_INFO, | ||
1407 | "Solving LP problem: %s, %s\n", | ||
1408 | mlp_solve_to_string (res), | ||
1409 | mlp_status_to_string (res_status)); | ||
1410 | return GNUNET_OK; | ||
1411 | |||
1412 | default: | ||
1413 | LOG (GNUNET_ERROR_TYPE_ERROR, | ||
1414 | "Solving LP problem failed: %s %s\n", | ||
1415 | mlp_solve_to_string (res), | ||
1416 | mlp_status_to_string (res_status)); | ||
1417 | return GNUNET_SYSERR; | ||
1418 | } | ||
1419 | } | ||
1420 | |||
1421 | |||
1422 | /** | ||
1423 | * Propagates the results when MLP problem was solved | ||
1424 | * | ||
1425 | * @param cls the MLP handle | ||
1426 | * @param key the peer identity | ||
1427 | * @param value the address | ||
1428 | * @return #GNUNET_OK to continue | ||
1429 | */ | ||
1430 | static int | ||
1431 | mlp_propagate_results (void *cls, | ||
1432 | const struct GNUNET_PeerIdentity *key, | ||
1433 | void *value) | ||
1434 | { | ||
1435 | struct GAS_MLP_Handle *mlp = cls; | ||
1436 | struct ATS_Address *address; | ||
1437 | struct MLP_information *mlpi; | ||
1438 | double mlp_bw_in = MLP_NaN; | ||
1439 | double mlp_bw_out = MLP_NaN; | ||
1440 | double mlp_use = MLP_NaN; | ||
1441 | |||
1442 | /* Check if we have to add this peer due to a pending request */ | ||
1443 | if (GNUNET_NO == GNUNET_CONTAINER_multipeermap_contains (mlp->requested_peers, | ||
1444 | key)) | ||
1445 | { | ||
1446 | return GNUNET_OK; | ||
1447 | } | ||
1448 | address = value; | ||
1449 | GNUNET_assert (address->solver_information != NULL); | ||
1450 | mlpi = address->solver_information; | ||
1451 | |||
1452 | mlp_bw_in = glp_mip_col_val (mlp->p.prob, mlpi->c_b);/* FIXME */ | ||
1453 | if (mlp_bw_in > (double) UINT32_MAX) | ||
1454 | { | ||
1455 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1456 | "Overflow in assigned bandwidth, reducing ...\n"); | ||
1457 | mlp_bw_in = (double) UINT32_MAX; | ||
1458 | } | ||
1459 | mlp_bw_out = glp_mip_col_val (mlp->p.prob, mlpi->c_b); | ||
1460 | if (mlp_bw_out > (double) UINT32_MAX) | ||
1461 | { | ||
1462 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1463 | "Overflow in assigned bandwidth, reducing ...\n"); | ||
1464 | mlp_bw_out = (double) UINT32_MAX; | ||
1465 | } | ||
1466 | mlp_use = glp_mip_col_val (mlp->p.prob, mlpi->c_n); | ||
1467 | |||
1468 | /* | ||
1469 | * Debug: solution | ||
1470 | * LOG (GNUNET_ERROR_TYPE_INFO, "MLP result address: `%s' `%s' length %u session %u, mlp use %.3f\n", | ||
1471 | * GNUNET_i2s(&address->peer), address->plugin, | ||
1472 | * address->addr_len, address->session_id); | ||
1473 | */ | ||
1474 | |||
1475 | if (GLP_YES == mlp_use) | ||
1476 | { | ||
1477 | /* This address was selected by the solver to be used */ | ||
1478 | mlpi->n = GNUNET_YES; | ||
1479 | if (GNUNET_NO == address->active) | ||
1480 | { | ||
1481 | /* Address was not used before, enabling address */ | ||
1482 | LOG (GNUNET_ERROR_TYPE_DEBUG, "%s %.2f : enabling address\n", | ||
1483 | (1 == mlp_use) ? "[x]" : "[ ]", mlp_bw_out); | ||
1484 | address->active = GNUNET_YES; | ||
1485 | address->assigned_bw_in = mlp_bw_in; | ||
1486 | mlpi->b_in = mlp_bw_in; | ||
1487 | address->assigned_bw_out = mlp_bw_out; | ||
1488 | mlpi->b_out = mlp_bw_out; | ||
1489 | if ((NULL == mlp->exclude_peer) || (0 != GNUNET_memcmp (&address->peer, | ||
1490 | mlp->exclude_peer))) | ||
1491 | mlp->env->bandwidth_changed_cb (mlp->env->cls, address); | ||
1492 | return GNUNET_OK; | ||
1493 | } | ||
1494 | else if (GNUNET_YES == address->active) | ||
1495 | { | ||
1496 | /* Address was used before, check for bandwidth change */ | ||
1497 | if ((mlp_bw_out != address->assigned_bw_out) || | ||
1498 | (mlp_bw_in != address->assigned_bw_in)) | ||
1499 | { | ||
1500 | LOG (GNUNET_ERROR_TYPE_DEBUG, "%s %.2f : bandwidth changed\n", | ||
1501 | (1 == mlp_use) ? "[x]" : "[ ]", mlp_bw_out); | ||
1502 | address->assigned_bw_in = mlp_bw_in; | ||
1503 | mlpi->b_in = mlp_bw_in; | ||
1504 | address->assigned_bw_out = mlp_bw_out; | ||
1505 | mlpi->b_out = mlp_bw_out; | ||
1506 | if ((NULL == mlp->exclude_peer) || (0 != GNUNET_memcmp (&address->peer, | ||
1507 | mlp-> | ||
1508 | exclude_peer))) | ||
1509 | mlp->env->bandwidth_changed_cb (mlp->env->cls, address); | ||
1510 | return GNUNET_OK; | ||
1511 | } | ||
1512 | } | ||
1513 | else | ||
1514 | GNUNET_break (0); | ||
1515 | } | ||
1516 | else if (GLP_NO == mlp_use) | ||
1517 | { | ||
1518 | /* This address was selected by the solver to be not used */ | ||
1519 | mlpi->n = GNUNET_NO; | ||
1520 | if (GNUNET_NO == address->active) | ||
1521 | { | ||
1522 | /* Address was not used before, nothing to do */ | ||
1523 | LOG (GNUNET_ERROR_TYPE_DEBUG, "%s %.2f : no change\n", | ||
1524 | (1 == mlp_use) ? "[x]" : "[ ]", mlp_bw_out); | ||
1525 | return GNUNET_OK; | ||
1526 | } | ||
1527 | else if (GNUNET_YES == address->active) | ||
1528 | { | ||
1529 | /* Address was used before, disabling address */ | ||
1530 | LOG (GNUNET_ERROR_TYPE_DEBUG, "%s %.2f : disabling address\n", | ||
1531 | (1 == mlp_use) ? "[x]" : "[ ]", mlp_bw_out); | ||
1532 | address->active = GNUNET_NO; | ||
1533 | /* Set bandwidth to 0 */ | ||
1534 | address->assigned_bw_in = 0; | ||
1535 | mlpi->b_in = 0; | ||
1536 | address->assigned_bw_out = 0; | ||
1537 | mlpi->b_out = 0; | ||
1538 | return GNUNET_OK; | ||
1539 | } | ||
1540 | else | ||
1541 | GNUNET_break (0); | ||
1542 | } | ||
1543 | else | ||
1544 | GNUNET_break (0); | ||
1545 | |||
1546 | return GNUNET_OK; | ||
1547 | } | ||
1548 | |||
1549 | |||
1550 | static void | ||
1551 | notify (struct GAS_MLP_Handle *mlp, | ||
1552 | enum GAS_Solver_Operation op, | ||
1553 | enum GAS_Solver_Status stat, | ||
1554 | enum GAS_Solver_Additional_Information add) | ||
1555 | { | ||
1556 | mlp->env->info_cb (mlp->env->cls, | ||
1557 | op, | ||
1558 | stat, | ||
1559 | add); | ||
1560 | } | ||
1561 | |||
1562 | |||
1563 | static void | ||
1564 | mlp_branch_and_cut_cb (glp_tree *tree, void *info) | ||
1565 | { | ||
1566 | struct GAS_MLP_Handle *mlp = info; | ||
1567 | double mlp_obj = 0; | ||
1568 | |||
1569 | switch (glp_ios_reason (tree)) | ||
1570 | { | ||
1571 | case GLP_ISELECT: | ||
1572 | /* Do nothing here */ | ||
1573 | break; | ||
1574 | |||
1575 | case GLP_IPREPRO: | ||
1576 | /* Do nothing here */ | ||
1577 | break; | ||
1578 | |||
1579 | case GLP_IROWGEN: | ||
1580 | /* Do nothing here */ | ||
1581 | break; | ||
1582 | |||
1583 | case GLP_IHEUR: | ||
1584 | /* Do nothing here */ | ||
1585 | break; | ||
1586 | |||
1587 | case GLP_ICUTGEN: | ||
1588 | /* Do nothing here */ | ||
1589 | break; | ||
1590 | |||
1591 | case GLP_IBRANCH: | ||
1592 | /* Do nothing here */ | ||
1593 | break; | ||
1594 | |||
1595 | case GLP_IBINGO: | ||
1596 | /* A better solution was found */ | ||
1597 | mlp->ps.mlp_gap = glp_ios_mip_gap (tree); | ||
1598 | mlp_obj = glp_mip_obj_val (mlp->p.prob); | ||
1599 | mlp->ps.lp_mlp_gap = (abs (mlp_obj - mlp->ps.lp_objective_value)) / (abs ( | ||
1600 | mlp_obj) | ||
1601 | + | ||
1602 | DBL_EPSILON); | ||
1603 | |||
1604 | LOG (GNUNET_ERROR_TYPE_INFO, | ||
1605 | "Found better integer solution, current gaps: %.3f <= %.3f, %.3f <= %.3f\n", | ||
1606 | mlp->ps.mlp_gap, mlp->pv.mip_gap, | ||
1607 | mlp->ps.lp_mlp_gap, mlp->pv.lp_mip_gap); | ||
1608 | |||
1609 | if (mlp->ps.mlp_gap <= mlp->pv.mip_gap) | ||
1610 | { | ||
1611 | LOG (GNUNET_ERROR_TYPE_INFO, | ||
1612 | "Current LP/MLP gap of %.3f smaller than tolerated gap of %.3f, terminating search\n", | ||
1613 | mlp->ps.lp_mlp_gap, mlp->pv.lp_mip_gap); | ||
1614 | glp_ios_terminate (tree); | ||
1615 | } | ||
1616 | |||
1617 | if (mlp->ps.lp_mlp_gap <= mlp->pv.lp_mip_gap) | ||
1618 | { | ||
1619 | LOG (GNUNET_ERROR_TYPE_INFO, | ||
1620 | "Current LP/MLP gap of %.3f smaller than tolerated gap of %.3f, terminating search\n", | ||
1621 | mlp->ps.lp_mlp_gap, mlp->pv.lp_mip_gap); | ||
1622 | glp_ios_terminate (tree); | ||
1623 | } | ||
1624 | |||
1625 | break; | ||
1626 | |||
1627 | default: | ||
1628 | break; | ||
1629 | } | ||
1630 | // GNUNET_break (0); | ||
1631 | } | ||
1632 | |||
1633 | |||
1634 | /** | ||
1635 | * Solves the MLP problem | ||
1636 | * | ||
1637 | * @param solver the MLP Handle | ||
1638 | * @return #GNUNET_OK if could be solved, #GNUNET_SYSERR on failure | ||
1639 | */ | ||
1640 | static int | ||
1641 | GAS_mlp_solve_problem (void *solver) | ||
1642 | { | ||
1643 | struct GAS_MLP_Handle *mlp = solver; | ||
1644 | char *filename; | ||
1645 | int res_lp = 0; | ||
1646 | int mip_res = 0; | ||
1647 | int mip_status = 0; | ||
1648 | |||
1649 | struct GNUNET_TIME_Absolute start_total; | ||
1650 | struct GNUNET_TIME_Absolute start_cur_op; | ||
1651 | struct GNUNET_TIME_Relative dur_total; | ||
1652 | struct GNUNET_TIME_Relative dur_setup; | ||
1653 | struct GNUNET_TIME_Relative dur_lp; | ||
1654 | struct GNUNET_TIME_Relative dur_mlp; | ||
1655 | |||
1656 | GNUNET_assert (NULL != solver); | ||
1657 | dur_lp = GNUNET_TIME_UNIT_ZERO; | ||
1658 | |||
1659 | if (GNUNET_YES == mlp->stat_bulk_lock) | ||
1660 | { | ||
1661 | mlp->stat_bulk_requests++; | ||
1662 | return GNUNET_NO; | ||
1663 | } | ||
1664 | notify (mlp, GAS_OP_SOLVE_START, GAS_STAT_SUCCESS, | ||
1665 | (GNUNET_YES == mlp->stat_mlp_prob_changed) ? GAS_INFO_FULL : | ||
1666 | GAS_INFO_UPDATED); | ||
1667 | start_total = GNUNET_TIME_absolute_get (); | ||
1668 | |||
1669 | if (0 == GNUNET_CONTAINER_multipeermap_size (mlp->requested_peers)) | ||
1670 | { | ||
1671 | notify (mlp, GAS_OP_SOLVE_STOP, GAS_STAT_SUCCESS, GAS_INFO_NONE); | ||
1672 | return GNUNET_OK; /* No pending requests */ | ||
1673 | } | ||
1674 | if (0 == GNUNET_CONTAINER_multipeermap_size (mlp->env->addresses)) | ||
1675 | { | ||
1676 | notify (mlp, GAS_OP_SOLVE_STOP, GAS_STAT_SUCCESS, GAS_INFO_NONE); | ||
1677 | return GNUNET_OK; /* No addresses available */ | ||
1678 | } | ||
1679 | |||
1680 | if ((GNUNET_NO == mlp->stat_mlp_prob_changed) | ||
1681 | && (GNUNET_NO == mlp->stat_mlp_prob_updated)) | ||
1682 | { | ||
1683 | LOG (GNUNET_ERROR_TYPE_DEBUG, "No changes to problem\n"); | ||
1684 | notify (mlp, GAS_OP_SOLVE_STOP, GAS_STAT_SUCCESS, GAS_INFO_NONE); | ||
1685 | return GNUNET_OK; | ||
1686 | } | ||
1687 | if (GNUNET_YES == mlp->stat_mlp_prob_changed) | ||
1688 | { | ||
1689 | LOG (GNUNET_ERROR_TYPE_DEBUG, "Problem size changed, rebuilding\n"); | ||
1690 | notify (mlp, GAS_OP_SOLVE_SETUP_START, GAS_STAT_SUCCESS, GAS_INFO_FULL); | ||
1691 | mlp_delete_problem (mlp); | ||
1692 | if (GNUNET_SYSERR == mlp_create_problem (mlp)) | ||
1693 | { | ||
1694 | notify (mlp, GAS_OP_SOLVE_SETUP_STOP, GAS_STAT_FAIL, GAS_INFO_FULL); | ||
1695 | return GNUNET_SYSERR; | ||
1696 | } | ||
1697 | notify (mlp, GAS_OP_SOLVE_SETUP_STOP, GAS_STAT_SUCCESS, GAS_INFO_FULL); | ||
1698 | if (GNUNET_NO == mlp->opt_dbg_intopt_presolver) | ||
1699 | { | ||
1700 | mlp->control_param_lp.presolve = GLP_YES; /* LP presolver, we need lp solution */ | ||
1701 | mlp->control_param_mlp.presolve = GNUNET_NO; /* No presolver, we have LP solution */ | ||
1702 | } | ||
1703 | else | ||
1704 | { | ||
1705 | mlp->control_param_lp.presolve = GNUNET_NO; /* LP presolver, we need lp solution */ | ||
1706 | mlp->control_param_mlp.presolve = GLP_YES; /* No presolver, we have LP solution */ | ||
1707 | dur_lp = GNUNET_TIME_UNIT_ZERO; | ||
1708 | } | ||
1709 | } | ||
1710 | else | ||
1711 | { | ||
1712 | LOG (GNUNET_ERROR_TYPE_DEBUG, "Problem was updated, resolving\n"); | ||
1713 | } | ||
1714 | |||
1715 | /* Reset solution info */ | ||
1716 | mlp->ps.lp_objective_value = 0.0; | ||
1717 | mlp->ps.mlp_gap = 1.0; | ||
1718 | mlp->ps.mlp_objective_value = 0.0; | ||
1719 | mlp->ps.lp_mlp_gap = 0.0; | ||
1720 | |||
1721 | dur_setup = GNUNET_TIME_absolute_get_duration (start_total); | ||
1722 | |||
1723 | /* Run LP solver */ | ||
1724 | if (GNUNET_NO == mlp->opt_dbg_intopt_presolver) | ||
1725 | { | ||
1726 | notify (mlp, GAS_OP_SOLVE_MLP_LP_START, GAS_STAT_SUCCESS, | ||
1727 | (GNUNET_YES == mlp->stat_mlp_prob_changed) ? GAS_INFO_FULL : | ||
1728 | GAS_INFO_UPDATED); | ||
1729 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1730 | "Running LP solver %s\n", | ||
1731 | (GLP_YES == mlp->control_param_lp.presolve) ? "with presolver" : | ||
1732 | "without presolver"); | ||
1733 | start_cur_op = GNUNET_TIME_absolute_get (); | ||
1734 | |||
1735 | /* Solve LP */ | ||
1736 | /* Only for debugging: | ||
1737 | * Always use LP presolver: | ||
1738 | * mlp->control_param_lp.presolve = GLP_YES; */ | ||
1739 | res_lp = mlp_solve_lp_problem (mlp); | ||
1740 | if (GNUNET_OK == res_lp) | ||
1741 | { | ||
1742 | mlp->ps.lp_objective_value = glp_get_obj_val (mlp->p.prob); | ||
1743 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1744 | "LP solution was: %.3f\n", | ||
1745 | mlp->ps.lp_objective_value); | ||
1746 | } | ||
1747 | |||
1748 | dur_lp = GNUNET_TIME_absolute_get_duration (start_cur_op); | ||
1749 | notify (mlp, GAS_OP_SOLVE_MLP_LP_STOP, | ||
1750 | (GNUNET_OK == res_lp) ? GAS_STAT_SUCCESS : GAS_STAT_FAIL, | ||
1751 | (GNUNET_YES == mlp->stat_mlp_prob_changed) ? GAS_INFO_FULL : | ||
1752 | GAS_INFO_UPDATED); | ||
1753 | } | ||
1754 | |||
1755 | if (GNUNET_YES == mlp->opt_dbg_intopt_presolver) | ||
1756 | res_lp = GNUNET_OK; | ||
1757 | |||
1758 | /* Run MLP solver */ | ||
1759 | if ((GNUNET_OK == res_lp) || (GNUNET_YES == mlp->opt_dbg_intopt_presolver)) | ||
1760 | { | ||
1761 | LOG (GNUNET_ERROR_TYPE_DEBUG, "Running MLP solver \n"); | ||
1762 | notify (mlp, GAS_OP_SOLVE_MLP_MLP_START, GAS_STAT_SUCCESS, | ||
1763 | (GNUNET_YES == mlp->stat_mlp_prob_changed) ? GAS_INFO_FULL : | ||
1764 | GAS_INFO_UPDATED); | ||
1765 | start_cur_op = GNUNET_TIME_absolute_get (); | ||
1766 | |||
1767 | /* Solve MIP */ | ||
1768 | |||
1769 | /* Only for debugging, always use LP presolver */ | ||
1770 | if (GNUNET_YES == mlp->opt_dbg_intopt_presolver) | ||
1771 | mlp->control_param_mlp.presolve = GNUNET_YES; | ||
1772 | |||
1773 | mip_res = glp_intopt (mlp->p.prob, &mlp->control_param_mlp); | ||
1774 | switch (mip_res) | ||
1775 | { | ||
1776 | case 0: | ||
1777 | /* Successful */ | ||
1778 | LOG (GNUNET_ERROR_TYPE_INFO, | ||
1779 | "Solving MLP problem: %s\n", | ||
1780 | mlp_solve_to_string (mip_res)); | ||
1781 | break; | ||
1782 | |||
1783 | case GLP_ETMLIM: /* Time limit reached */ | ||
1784 | case GLP_EMIPGAP: /* MIP gap tolerance limit reached */ | ||
1785 | case GLP_ESTOP: /* Solver was instructed to stop*/ | ||
1786 | /* Semi-successful */ | ||
1787 | LOG (GNUNET_ERROR_TYPE_INFO, | ||
1788 | "Solving MLP problem solution was interupted: %s\n", | ||
1789 | mlp_solve_to_string (mip_res)); | ||
1790 | break; | ||
1791 | |||
1792 | case GLP_EBOUND: | ||
1793 | case GLP_EROOT: | ||
1794 | case GLP_ENOPFS: | ||
1795 | case GLP_ENODFS: | ||
1796 | case GLP_EFAIL: | ||
1797 | default: | ||
1798 | /* Fail */ | ||
1799 | LOG (GNUNET_ERROR_TYPE_INFO, | ||
1800 | "Solving MLP problem failed: %s\n", | ||
1801 | mlp_solve_to_string (mip_res)); | ||
1802 | break; | ||
1803 | } | ||
1804 | |||
1805 | /* Analyze problem status */ | ||
1806 | mip_status = glp_mip_status (mlp->p.prob); | ||
1807 | switch (mip_status) | ||
1808 | { | ||
1809 | case GLP_OPT: /* solution is optimal */ | ||
1810 | LOG (GNUNET_ERROR_TYPE_WARNING, | ||
1811 | "Solution of MLP problem is optimal: %s, %s\n", | ||
1812 | mlp_solve_to_string (mip_res), | ||
1813 | mlp_status_to_string (mip_status)); | ||
1814 | mip_res = GNUNET_OK; | ||
1815 | break; | ||
1816 | |||
1817 | case GLP_FEAS: /* solution is feasible but not proven optimal */ | ||
1818 | |||
1819 | if ((mlp->ps.mlp_gap <= mlp->pv.mip_gap) || | ||
1820 | (mlp->ps.lp_mlp_gap <= mlp->pv.lp_mip_gap)) | ||
1821 | { | ||
1822 | LOG (GNUNET_ERROR_TYPE_INFO, | ||
1823 | "Solution of MLP problem is feasible and solution within gap constraints: %s, %s\n", | ||
1824 | mlp_solve_to_string (mip_res), | ||
1825 | mlp_status_to_string (mip_status)); | ||
1826 | mip_res = GNUNET_OK; | ||
1827 | } | ||
1828 | else | ||
1829 | { | ||
1830 | LOG (GNUNET_ERROR_TYPE_WARNING, | ||
1831 | "Solution of MLP problem is feasible but solution not within gap constraints: %s, %s\n", | ||
1832 | mlp_solve_to_string (mip_res), | ||
1833 | mlp_status_to_string (mip_status)); | ||
1834 | mip_res = GNUNET_SYSERR; | ||
1835 | } | ||
1836 | break; | ||
1837 | |||
1838 | case GLP_UNDEF: /* Solution undefined */ | ||
1839 | case GLP_NOFEAS: /* No feasible solution */ | ||
1840 | default: | ||
1841 | LOG (GNUNET_ERROR_TYPE_ERROR, | ||
1842 | "Solving MLP problem failed: %s %s\n", | ||
1843 | mlp_solve_to_string (mip_res), | ||
1844 | mlp_status_to_string (mip_status)); | ||
1845 | mip_res = GNUNET_SYSERR; | ||
1846 | break; | ||
1847 | } | ||
1848 | |||
1849 | dur_mlp = GNUNET_TIME_absolute_get_duration (start_cur_op); | ||
1850 | dur_total = GNUNET_TIME_absolute_get_duration (start_total); | ||
1851 | |||
1852 | notify (mlp, GAS_OP_SOLVE_MLP_MLP_STOP, | ||
1853 | (GNUNET_OK == mip_res) ? GAS_STAT_SUCCESS : GAS_STAT_FAIL, | ||
1854 | (GNUNET_YES == mlp->stat_mlp_prob_changed) ? GAS_INFO_FULL : | ||
1855 | GAS_INFO_UPDATED); | ||
1856 | } | ||
1857 | else | ||
1858 | { | ||
1859 | /* Do not execute mip solver since lp solution is invalid */ | ||
1860 | dur_mlp = GNUNET_TIME_UNIT_ZERO; | ||
1861 | dur_total = GNUNET_TIME_absolute_get_duration (start_total); | ||
1862 | |||
1863 | notify (mlp, GAS_OP_SOLVE_MLP_MLP_STOP, GAS_STAT_FAIL, | ||
1864 | (GNUNET_YES == mlp->stat_mlp_prob_changed) ? GAS_INFO_FULL : | ||
1865 | GAS_INFO_UPDATED); | ||
1866 | mip_res = GNUNET_SYSERR; | ||
1867 | } | ||
1868 | |||
1869 | /* Notify about end */ | ||
1870 | notify (mlp, GAS_OP_SOLVE_STOP, | ||
1871 | ((GNUNET_OK == mip_res) && (GNUNET_OK == mip_res)) ? | ||
1872 | GAS_STAT_SUCCESS : GAS_STAT_FAIL, | ||
1873 | (GNUNET_YES == mlp->stat_mlp_prob_changed) ? GAS_INFO_FULL : | ||
1874 | GAS_INFO_UPDATED); | ||
1875 | |||
1876 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1877 | "Execution time for %s solve: (total/setup/lp/mlp) : %llu %llu %llu %llu\n", | ||
1878 | (GNUNET_YES == mlp->stat_mlp_prob_changed) ? "full" : "updated", | ||
1879 | (unsigned long long) dur_total.rel_value_us, | ||
1880 | (unsigned long long) dur_setup.rel_value_us, | ||
1881 | (unsigned long long) dur_lp.rel_value_us, | ||
1882 | (unsigned long long) dur_mlp.rel_value_us); | ||
1883 | |||
1884 | /* Save stats */ | ||
1885 | mlp->ps.lp_res = res_lp; | ||
1886 | mlp->ps.mip_res = mip_res; | ||
1887 | mlp->ps.lp_presolv = mlp->control_param_lp.presolve; | ||
1888 | mlp->ps.mip_presolv = mlp->control_param_mlp.presolve; | ||
1889 | mlp->ps.p_cols = glp_get_num_cols (mlp->p.prob); | ||
1890 | mlp->ps.p_rows = glp_get_num_rows (mlp->p.prob); | ||
1891 | mlp->ps.p_elements = mlp->p.num_elements; | ||
1892 | |||
1893 | /* Propagate result*/ | ||
1894 | notify (mlp, GAS_OP_SOLVE_UPDATE_NOTIFICATION_START, | ||
1895 | (GNUNET_OK == res_lp) && (GNUNET_OK == mip_res) ? GAS_STAT_SUCCESS : | ||
1896 | GAS_STAT_FAIL, | ||
1897 | GAS_INFO_NONE); | ||
1898 | if ((GNUNET_OK == res_lp) && (GNUNET_OK == mip_res)) | ||
1899 | { | ||
1900 | GNUNET_CONTAINER_multipeermap_iterate (mlp->env->addresses, | ||
1901 | &mlp_propagate_results, mlp); | ||
1902 | } | ||
1903 | notify (mlp, GAS_OP_SOLVE_UPDATE_NOTIFICATION_STOP, | ||
1904 | (GNUNET_OK == res_lp) && (GNUNET_OK == mip_res) ? GAS_STAT_SUCCESS : | ||
1905 | GAS_STAT_FAIL, | ||
1906 | GAS_INFO_NONE); | ||
1907 | |||
1908 | struct GNUNET_TIME_Absolute time = GNUNET_TIME_absolute_get (); | ||
1909 | if ((GNUNET_YES == mlp->opt_dump_problem_all) || | ||
1910 | (mlp->opt_dump_problem_on_fail && ((GNUNET_OK != res_lp) || (GNUNET_OK != | ||
1911 | mip_res)))) | ||
1912 | { | ||
1913 | /* Write problem to disk */ | ||
1914 | switch (mlp->opt_log_format) | ||
1915 | { | ||
1916 | case MLP_CPLEX: | ||
1917 | GNUNET_asprintf (&filename, "problem_p_%u_a%u_%llu.cplex", | ||
1918 | mlp->p.num_peers, | ||
1919 | mlp->p.num_addresses, time.abs_value_us); | ||
1920 | glp_write_lp (mlp->p.prob, NULL, filename); | ||
1921 | break; | ||
1922 | |||
1923 | case MLP_GLPK: | ||
1924 | GNUNET_asprintf (&filename, "problem_p_%u_a%u_%llu.glpk", | ||
1925 | mlp->p.num_peers, | ||
1926 | mlp->p.num_addresses, time.abs_value_us); | ||
1927 | glp_write_prob (mlp->p.prob, 0, filename); | ||
1928 | break; | ||
1929 | |||
1930 | case MLP_MPS: | ||
1931 | GNUNET_asprintf (&filename, "problem_p_%u_a%u_%llu.mps", mlp->p.num_peers, | ||
1932 | mlp->p.num_addresses, time.abs_value_us); | ||
1933 | glp_write_mps (mlp->p.prob, GLP_MPS_FILE, NULL, filename); | ||
1934 | break; | ||
1935 | |||
1936 | default: | ||
1937 | break; | ||
1938 | } | ||
1939 | LOG (GNUNET_ERROR_TYPE_ERROR, "Dumped problem to file: `%s' \n", filename); | ||
1940 | GNUNET_free (filename); | ||
1941 | } | ||
1942 | if ((mlp->opt_dump_solution_all) || | ||
1943 | (mlp->opt_dump_solution_on_fail && ((GNUNET_OK != res_lp) || (GNUNET_OK != | ||
1944 | mip_res)))) | ||
1945 | { | ||
1946 | /* Write solution to disk */ | ||
1947 | GNUNET_asprintf (&filename, "problem_p_%u_a%u_%llu.sol", mlp->p.num_peers, | ||
1948 | mlp->p.num_addresses, time.abs_value_us); | ||
1949 | glp_print_mip (mlp->p.prob, filename); | ||
1950 | LOG (GNUNET_ERROR_TYPE_ERROR, "Dumped solution to file: `%s' \n", filename); | ||
1951 | GNUNET_free (filename); | ||
1952 | } | ||
1953 | |||
1954 | /* Reset change and update marker */ | ||
1955 | mlp->control_param_lp.presolve = GLP_NO; | ||
1956 | mlp->stat_mlp_prob_updated = GNUNET_NO; | ||
1957 | mlp->stat_mlp_prob_changed = GNUNET_NO; | ||
1958 | |||
1959 | if ((GNUNET_OK == res_lp) && (GNUNET_OK == mip_res)) | ||
1960 | return GNUNET_OK; | ||
1961 | else | ||
1962 | return GNUNET_SYSERR; | ||
1963 | } | ||
1964 | |||
1965 | /** | ||
1966 | * Add a single address to the solve | ||
1967 | * | ||
1968 | * @param solver the solver Handle | ||
1969 | * @param address the address to add | ||
1970 | * @param network network type of this address | ||
1971 | */ | ||
1972 | static void | ||
1973 | GAS_mlp_address_add (void *solver, | ||
1974 | struct ATS_Address *address, | ||
1975 | uint32_t network) | ||
1976 | { | ||
1977 | struct GAS_MLP_Handle *mlp = solver; | ||
1978 | |||
1979 | if (GNUNET_NT_COUNT <= network) | ||
1980 | { | ||
1981 | GNUNET_break (0); | ||
1982 | return; | ||
1983 | } | ||
1984 | |||
1985 | if (NULL == address->solver_information) | ||
1986 | { | ||
1987 | address->solver_information = GNUNET_new (struct MLP_information); | ||
1988 | } | ||
1989 | else | ||
1990 | LOG (GNUNET_ERROR_TYPE_ERROR, | ||
1991 | _ ("Adding address for peer `%s' multiple times\n"), | ||
1992 | GNUNET_i2s (&address->peer)); | ||
1993 | |||
1994 | /* Is this peer included in the problem? */ | ||
1995 | if (NULL == | ||
1996 | GNUNET_CONTAINER_multipeermap_get (mlp->requested_peers, | ||
1997 | &address->peer)) | ||
1998 | { | ||
1999 | /* FIXME: should this be an error? */ | ||
2000 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
2001 | "Adding address for peer `%s' without address request\n", | ||
2002 | GNUNET_i2s (&address->peer)); | ||
2003 | return; | ||
2004 | } | ||
2005 | |||
2006 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
2007 | "Adding address for peer `%s' with address request \n", | ||
2008 | GNUNET_i2s (&address->peer)); | ||
2009 | /* Problem size changed: new address for peer with pending request */ | ||
2010 | mlp->stat_mlp_prob_changed = GNUNET_YES; | ||
2011 | if (GNUNET_YES == mlp->opt_mlp_auto_solve) | ||
2012 | GAS_mlp_solve_problem (solver); | ||
2013 | } | ||
2014 | |||
2015 | |||
2016 | /** | ||
2017 | * Transport properties for this address have changed | ||
2018 | * | ||
2019 | * @param solver solver handle | ||
2020 | * @param address the address | ||
2021 | */ | ||
2022 | static void | ||
2023 | GAS_mlp_address_property_changed (void *solver, | ||
2024 | struct ATS_Address *address) | ||
2025 | { | ||
2026 | struct MLP_information *mlpi = address->solver_information; | ||
2027 | struct GAS_MLP_Handle *mlp = solver; | ||
2028 | |||
2029 | if (NULL == mlp->p.prob) | ||
2030 | return; /* There is no MLP problem to update yet */ | ||
2031 | |||
2032 | if (NULL == mlpi) | ||
2033 | { | ||
2034 | LOG (GNUNET_ERROR_TYPE_INFO, | ||
2035 | _ ("Updating address property for peer `%s' %p not added before\n"), | ||
2036 | GNUNET_i2s (&address->peer), | ||
2037 | address); | ||
2038 | GNUNET_break (0); | ||
2039 | return; | ||
2040 | } | ||
2041 | if (NULL == | ||
2042 | GNUNET_CONTAINER_multipeermap_get (mlp->requested_peers, | ||
2043 | &address->peer)) | ||
2044 | { | ||
2045 | /* Peer is not requested, so no need to update problem */ | ||
2046 | return; | ||
2047 | } | ||
2048 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
2049 | "Updating properties for peer `%s'\n", | ||
2050 | GNUNET_i2s (&address->peer)); | ||
2051 | |||
2052 | if (GNUNET_YES == mlp->opt_dbg_feasibility_only) | ||
2053 | return; | ||
2054 | |||
2055 | /* Update c7) [r_q[index]][c_b] = f_q * q_averaged[type_index] */ | ||
2056 | if ((GNUNET_YES == | ||
2057 | mlp_create_problem_update_value (&mlp->p, | ||
2058 | mlp->p.r_q[RQ_QUALITY_METRIC_DELAY], | ||
2059 | mlpi->c_b, | ||
2060 | address->norm_delay.norm, | ||
2061 | __LINE__)) || | ||
2062 | (GNUNET_YES == | ||
2063 | mlp_create_problem_update_value (&mlp->p, | ||
2064 | mlp->p.r_q[RQ_QUALITY_METRIC_DISTANCE], | ||
2065 | mlpi->c_b, | ||
2066 | address->norm_distance.norm, | ||
2067 | __LINE__))) | ||
2068 | { | ||
2069 | mlp->stat_mlp_prob_updated = GNUNET_YES; | ||
2070 | if (GNUNET_YES == mlp->opt_mlp_auto_solve) | ||
2071 | GAS_mlp_solve_problem (solver); | ||
2072 | } | ||
2073 | } | ||
2074 | |||
2075 | |||
2076 | /** | ||
2077 | * Find the active address in the set of addresses of a peer | ||
2078 | * @param cls destination | ||
2079 | * @param key peer id | ||
2080 | * @param value address | ||
2081 | * @return #GNUNET_OK | ||
2082 | */ | ||
2083 | static int | ||
2084 | mlp_get_preferred_address_it (void *cls, | ||
2085 | const struct GNUNET_PeerIdentity *key, | ||
2086 | void *value) | ||
2087 | { | ||
2088 | static int counter = 0; | ||
2089 | struct ATS_Address **aa = cls; | ||
2090 | struct ATS_Address *addr = value; | ||
2091 | struct MLP_information *mlpi = addr->solver_information; | ||
2092 | |||
2093 | if (mlpi == NULL) | ||
2094 | return GNUNET_YES; | ||
2095 | |||
2096 | /* | ||
2097 | * Debug output | ||
2098 | * GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
2099 | * "MLP [%u] Peer `%s' %s length %u session %u active %s mlp active %s\n", | ||
2100 | * counter, GNUNET_i2s (&addr->peer), addr->plugin, addr->addr_len, addr->session_id, | ||
2101 | * (GNUNET_YES == addr->active) ? "active" : "inactive", | ||
2102 | * (GNUNET_YES == mlpi->n) ? "active" : "inactive"); | ||
2103 | */ | ||
2104 | |||
2105 | if (GNUNET_YES == mlpi->n) | ||
2106 | { | ||
2107 | (*aa) = addr; | ||
2108 | (*aa)->assigned_bw_in = mlpi->b_in; | ||
2109 | (*aa)->assigned_bw_out = mlpi->b_out; | ||
2110 | return GNUNET_NO; | ||
2111 | } | ||
2112 | counter++; | ||
2113 | return GNUNET_YES; | ||
2114 | } | ||
2115 | |||
2116 | |||
2117 | static double | ||
2118 | get_peer_pref_value (struct GAS_MLP_Handle *mlp, | ||
2119 | const struct GNUNET_PeerIdentity *peer) | ||
2120 | { | ||
2121 | double res; | ||
2122 | const double *preferences; | ||
2123 | int c; | ||
2124 | |||
2125 | preferences = mlp->env->get_preferences (mlp->env->cls, peer); | ||
2126 | res = 0.0; | ||
2127 | for (c = 0; c < GNUNET_ATS_PREFERENCE_END; c++) | ||
2128 | { | ||
2129 | /* fprintf (stderr, "VALUE[%u] %s %.3f \n", | ||
2130 | * c, GNUNET_i2s (&cur->addr->peer), t[c]); */ | ||
2131 | res += preferences[c]; | ||
2132 | } | ||
2133 | |||
2134 | res /= GNUNET_ATS_PREFERENCE_END; | ||
2135 | res += 1.0; | ||
2136 | |||
2137 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
2138 | "Peer preference for peer `%s' == %.2f\n", | ||
2139 | GNUNET_i2s (peer), res); | ||
2140 | |||
2141 | return res; | ||
2142 | } | ||
2143 | |||
2144 | |||
2145 | /** | ||
2146 | * Get the preferred address for a specific peer | ||
2147 | * | ||
2148 | * @param solver the MLP Handle | ||
2149 | * @param peer the peer | ||
2150 | */ | ||
2151 | static void | ||
2152 | GAS_mlp_get_preferred_address (void *solver, | ||
2153 | const struct GNUNET_PeerIdentity *peer) | ||
2154 | { | ||
2155 | struct GAS_MLP_Handle *mlp = solver; | ||
2156 | struct ATS_Peer *p; | ||
2157 | struct ATS_Address *res; | ||
2158 | |||
2159 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
2160 | "Getting preferred address for `%s'\n", | ||
2161 | GNUNET_i2s (peer)); | ||
2162 | |||
2163 | /* Is this peer included in the problem? */ | ||
2164 | if (NULL == | ||
2165 | GNUNET_CONTAINER_multipeermap_get (mlp->requested_peers, | ||
2166 | peer)) | ||
2167 | { | ||
2168 | LOG (GNUNET_ERROR_TYPE_INFO, | ||
2169 | "Adding peer `%s' to list of requested_peers with requests\n", | ||
2170 | GNUNET_i2s (peer)); | ||
2171 | |||
2172 | p = GNUNET_new (struct ATS_Peer); | ||
2173 | p->id = (*peer); | ||
2174 | p->f = get_peer_pref_value (mlp, peer); | ||
2175 | GNUNET_CONTAINER_multipeermap_put (mlp->requested_peers, | ||
2176 | peer, p, | ||
2177 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST); | ||
2178 | |||
2179 | /* Added new peer, we have to rebuild problem before solving */ | ||
2180 | mlp->stat_mlp_prob_changed = GNUNET_YES; | ||
2181 | |||
2182 | if ((GNUNET_YES == mlp->opt_mlp_auto_solve) && | ||
2183 | (GNUNET_YES == GNUNET_CONTAINER_multipeermap_contains ( | ||
2184 | mlp->env->addresses, | ||
2185 | peer))) | ||
2186 | { | ||
2187 | mlp->exclude_peer = peer; | ||
2188 | GAS_mlp_solve_problem (mlp); | ||
2189 | mlp->exclude_peer = NULL; | ||
2190 | } | ||
2191 | } | ||
2192 | /* Get prefered address */ | ||
2193 | res = NULL; | ||
2194 | GNUNET_CONTAINER_multipeermap_get_multiple (mlp->env->addresses, peer, | ||
2195 | &mlp_get_preferred_address_it, | ||
2196 | &res); | ||
2197 | if (NULL != res) | ||
2198 | mlp->env->bandwidth_changed_cb (mlp->env->cls, | ||
2199 | res); | ||
2200 | } | ||
2201 | |||
2202 | |||
2203 | /** | ||
2204 | * Deletes a single address in the MLP problem | ||
2205 | * | ||
2206 | * The MLP problem has to be recreated and the problem has to be resolved | ||
2207 | * | ||
2208 | * @param solver the MLP Handle | ||
2209 | * @param address the address to delete | ||
2210 | */ | ||
2211 | static void | ||
2212 | GAS_mlp_address_delete (void *solver, | ||
2213 | struct ATS_Address *address) | ||
2214 | { | ||
2215 | struct GAS_MLP_Handle *mlp = solver; | ||
2216 | struct MLP_information *mlpi; | ||
2217 | struct ATS_Address *res; | ||
2218 | int was_active; | ||
2219 | |||
2220 | mlpi = address->solver_information; | ||
2221 | if (NULL != mlpi) | ||
2222 | { | ||
2223 | /* Remove full address */ | ||
2224 | GNUNET_free (mlpi); | ||
2225 | address->solver_information = NULL; | ||
2226 | } | ||
2227 | was_active = address->active; | ||
2228 | address->active = GNUNET_NO; | ||
2229 | address->assigned_bw_in = 0; | ||
2230 | address->assigned_bw_out = 0; | ||
2231 | |||
2232 | /* Is this peer included in the problem? */ | ||
2233 | if (NULL == | ||
2234 | GNUNET_CONTAINER_multipeermap_get (mlp->requested_peers, | ||
2235 | &address->peer)) | ||
2236 | { | ||
2237 | LOG (GNUNET_ERROR_TYPE_INFO, | ||
2238 | "Deleting address for peer `%s' without address request \n", | ||
2239 | GNUNET_i2s (&address->peer)); | ||
2240 | return; | ||
2241 | } | ||
2242 | LOG (GNUNET_ERROR_TYPE_INFO, | ||
2243 | "Deleting address for peer `%s' with address request \n", | ||
2244 | GNUNET_i2s (&address->peer)); | ||
2245 | |||
2246 | /* Problem size changed: new address for peer with pending request */ | ||
2247 | mlp->stat_mlp_prob_changed = GNUNET_YES; | ||
2248 | if (GNUNET_YES == mlp->opt_mlp_auto_solve) | ||
2249 | { | ||
2250 | GAS_mlp_solve_problem (solver); | ||
2251 | } | ||
2252 | if (GNUNET_YES == was_active) | ||
2253 | { | ||
2254 | GAS_mlp_get_preferred_address (solver, &address->peer); | ||
2255 | res = NULL; | ||
2256 | GNUNET_CONTAINER_multipeermap_get_multiple (mlp->env->addresses, | ||
2257 | &address->peer, | ||
2258 | &mlp_get_preferred_address_it, | ||
2259 | &res); | ||
2260 | if (NULL == res) | ||
2261 | { | ||
2262 | /* No alternative address, disconnecting peer */ | ||
2263 | mlp->env->bandwidth_changed_cb (mlp->env->cls, address); | ||
2264 | } | ||
2265 | } | ||
2266 | } | ||
2267 | |||
2268 | |||
2269 | /** | ||
2270 | * Start a bulk operation | ||
2271 | * | ||
2272 | * @param solver the solver | ||
2273 | */ | ||
2274 | static void | ||
2275 | GAS_mlp_bulk_start (void *solver) | ||
2276 | { | ||
2277 | struct GAS_MLP_Handle *s = solver; | ||
2278 | |||
2279 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
2280 | "Locking solver for bulk operation ...\n"); | ||
2281 | GNUNET_assert (NULL != solver); | ||
2282 | s->stat_bulk_lock++; | ||
2283 | } | ||
2284 | |||
2285 | |||
2286 | static void | ||
2287 | GAS_mlp_bulk_stop (void *solver) | ||
2288 | { | ||
2289 | struct GAS_MLP_Handle *s = solver; | ||
2290 | |||
2291 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
2292 | "Unlocking solver from bulk operation ...\n"); | ||
2293 | GNUNET_assert (NULL != solver); | ||
2294 | |||
2295 | if (s->stat_bulk_lock < 1) | ||
2296 | { | ||
2297 | GNUNET_break (0); | ||
2298 | return; | ||
2299 | } | ||
2300 | s->stat_bulk_lock--; | ||
2301 | |||
2302 | if (0 < s->stat_bulk_requests) | ||
2303 | { | ||
2304 | GAS_mlp_solve_problem (solver); | ||
2305 | s->stat_bulk_requests = 0; | ||
2306 | } | ||
2307 | } | ||
2308 | |||
2309 | |||
2310 | |||
2311 | /** | ||
2312 | * Stop notifying about address and bandwidth changes for this peer | ||
2313 | * | ||
2314 | * @param solver the MLP handle | ||
2315 | * @param peer the peer | ||
2316 | */ | ||
2317 | static void | ||
2318 | GAS_mlp_stop_get_preferred_address (void *solver, | ||
2319 | const struct GNUNET_PeerIdentity *peer) | ||
2320 | { | ||
2321 | struct GAS_MLP_Handle *mlp = solver; | ||
2322 | struct ATS_Peer *p = NULL; | ||
2323 | |||
2324 | GNUNET_assert (NULL != solver); | ||
2325 | GNUNET_assert (NULL != peer); | ||
2326 | if (NULL != (p = GNUNET_CONTAINER_multipeermap_get (mlp->requested_peers, | ||
2327 | peer))) | ||
2328 | { | ||
2329 | GNUNET_assert (GNUNET_YES == | ||
2330 | GNUNET_CONTAINER_multipeermap_remove (mlp->requested_peers, | ||
2331 | peer, p)); | ||
2332 | GNUNET_free (p); | ||
2333 | |||
2334 | mlp->stat_mlp_prob_changed = GNUNET_YES; | ||
2335 | if (GNUNET_YES == mlp->opt_mlp_auto_solve) | ||
2336 | { | ||
2337 | GAS_mlp_solve_problem (solver); | ||
2338 | } | ||
2339 | } | ||
2340 | } | ||
2341 | |||
2342 | |||
2343 | /** | ||
2344 | * Changes the preferences for a peer in the MLP problem | ||
2345 | * | ||
2346 | * @param solver the MLP Handle | ||
2347 | * @param peer the peer | ||
2348 | * @param kind the kind to change the preference | ||
2349 | * @param pref_rel the relative score | ||
2350 | */ | ||
2351 | static void | ||
2352 | GAS_mlp_address_change_preference (void *solver, | ||
2353 | const struct GNUNET_PeerIdentity *peer, | ||
2354 | enum GNUNET_ATS_PreferenceKind kind, | ||
2355 | double pref_rel) | ||
2356 | { | ||
2357 | struct GAS_MLP_Handle *mlp = solver; | ||
2358 | struct ATS_Peer *p; | ||
2359 | |||
2360 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
2361 | "Changing preference for address for peer `%s' to %.2f\n", | ||
2362 | GNUNET_i2s (peer), | ||
2363 | pref_rel); | ||
2364 | |||
2365 | GNUNET_STATISTICS_update (mlp->env->stats, | ||
2366 | "# LP address preference changes", 1, GNUNET_NO); | ||
2367 | /* Update the constraints with changed preferences */ | ||
2368 | |||
2369 | |||
2370 | |||
2371 | /* Update relativity constraint c9 */ | ||
2372 | if (NULL == (p = GNUNET_CONTAINER_multipeermap_get (mlp->requested_peers, | ||
2373 | peer))) | ||
2374 | { | ||
2375 | LOG (GNUNET_ERROR_TYPE_INFO, | ||
2376 | "Updating preference for unknown peer `%s'\n", | ||
2377 | GNUNET_i2s (peer)); | ||
2378 | return; | ||
2379 | } | ||
2380 | |||
2381 | if (GNUNET_NO == mlp->opt_dbg_feasibility_only) | ||
2382 | { | ||
2383 | p->f = get_peer_pref_value (mlp, peer); | ||
2384 | mlp_create_problem_update_value (&mlp->p, | ||
2385 | p->r_c9, | ||
2386 | mlp->p.c_r, | ||
2387 | -p->f, | ||
2388 | __LINE__); | ||
2389 | |||
2390 | /* Problem size changed: new address for peer with pending request */ | ||
2391 | mlp->stat_mlp_prob_updated = GNUNET_YES; | ||
2392 | if (GNUNET_YES == mlp->opt_mlp_auto_solve) | ||
2393 | GAS_mlp_solve_problem (solver); | ||
2394 | } | ||
2395 | } | ||
2396 | |||
2397 | |||
2398 | /** | ||
2399 | * Get application feedback for a peer | ||
2400 | * | ||
2401 | * @param solver the solver handle | ||
2402 | * @param application the application | ||
2403 | * @param peer the peer to change the preference for | ||
2404 | * @param scope the time interval for this feedback: [now - scope .. now] | ||
2405 | * @param kind the kind to change the preference | ||
2406 | * @param score the score | ||
2407 | */ | ||
2408 | static void | ||
2409 | GAS_mlp_address_preference_feedback (void *solver, | ||
2410 | struct GNUNET_SERVICE_Client *application, | ||
2411 | const struct GNUNET_PeerIdentity *peer, | ||
2412 | const struct GNUNET_TIME_Relative scope, | ||
2413 | enum GNUNET_ATS_PreferenceKind kind, | ||
2414 | double score) | ||
2415 | { | ||
2416 | struct GAS_PROPORTIONAL_Handle *s = solver; | ||
2417 | |||
2418 | GNUNET_assert (NULL != solver); | ||
2419 | GNUNET_assert (NULL != peer); | ||
2420 | GNUNET_assert (NULL != s); | ||
2421 | } | ||
2422 | |||
2423 | |||
2424 | static int | ||
2425 | mlp_free_peers (void *cls, | ||
2426 | const struct GNUNET_PeerIdentity *key, void *value) | ||
2427 | { | ||
2428 | struct GNUNET_CONTAINER_MultiPeerMap *map = cls; | ||
2429 | struct ATS_Peer *p = value; | ||
2430 | |||
2431 | GNUNET_assert (GNUNET_YES == | ||
2432 | GNUNET_CONTAINER_multipeermap_remove (map, key, value)); | ||
2433 | GNUNET_free (p); | ||
2434 | |||
2435 | return GNUNET_OK; | ||
2436 | } | ||
2437 | |||
2438 | |||
2439 | /** | ||
2440 | * Shutdown the MLP problem solving component | ||
2441 | * | ||
2442 | * @param cls the solver handle | ||
2443 | * @return NULL | ||
2444 | */ | ||
2445 | void * | ||
2446 | libgnunet_plugin_ats_mlp_done (void *cls) | ||
2447 | { | ||
2448 | struct GNUNET_ATS_SolverFunctions *sf = cls; | ||
2449 | struct GAS_MLP_Handle *mlp = sf->cls; | ||
2450 | |||
2451 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
2452 | "Shutting down mlp solver\n"); | ||
2453 | mlp_delete_problem (mlp); | ||
2454 | GNUNET_CONTAINER_multipeermap_iterate (mlp->requested_peers, | ||
2455 | &mlp_free_peers, | ||
2456 | mlp->requested_peers); | ||
2457 | GNUNET_CONTAINER_multipeermap_destroy (mlp->requested_peers); | ||
2458 | mlp->requested_peers = NULL; | ||
2459 | |||
2460 | /* Clean up GLPK environment */ | ||
2461 | glp_free_env (); | ||
2462 | GNUNET_free (mlp); | ||
2463 | |||
2464 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
2465 | "Shutdown down of mlp solver complete\n"); | ||
2466 | return NULL; | ||
2467 | } | ||
2468 | |||
2469 | |||
2470 | void * | ||
2471 | libgnunet_plugin_ats_mlp_init (void *cls) | ||
2472 | { | ||
2473 | static struct GNUNET_ATS_SolverFunctions sf; | ||
2474 | struct GNUNET_ATS_PluginEnvironment *env = cls; | ||
2475 | struct GAS_MLP_Handle *mlp = GNUNET_new (struct GAS_MLP_Handle); | ||
2476 | float f_tmp; | ||
2477 | unsigned long long tmp; | ||
2478 | unsigned int b_min; | ||
2479 | unsigned int n_min; | ||
2480 | int c; | ||
2481 | char *outputformat; | ||
2482 | |||
2483 | struct GNUNET_TIME_Relative max_duration; | ||
2484 | long long unsigned int max_iterations; | ||
2485 | |||
2486 | /* Init GLPK environment */ | ||
2487 | int res = glp_init_env (); | ||
2488 | |||
2489 | switch (res) | ||
2490 | { | ||
2491 | case 0: | ||
2492 | LOG (GNUNET_ERROR_TYPE_DEBUG, "GLPK: `%s'\n", | ||
2493 | "initialization successful"); | ||
2494 | break; | ||
2495 | |||
2496 | case 1: | ||
2497 | LOG (GNUNET_ERROR_TYPE_DEBUG, "GLPK: `%s'\n", | ||
2498 | "environment is already initialized"); | ||
2499 | break; | ||
2500 | |||
2501 | case 2: | ||
2502 | LOG (GNUNET_ERROR_TYPE_ERROR, "Could not init GLPK: `%s'\n", | ||
2503 | "initialization failed (insufficient memory)"); | ||
2504 | GNUNET_free (mlp); | ||
2505 | return NULL; | ||
2506 | break; | ||
2507 | |||
2508 | case 3: | ||
2509 | LOG (GNUNET_ERROR_TYPE_ERROR, "Could not init GLPK: `%s'\n", | ||
2510 | "initialization failed (unsupported programming model)"); | ||
2511 | GNUNET_free (mlp); | ||
2512 | return NULL; | ||
2513 | break; | ||
2514 | |||
2515 | default: | ||
2516 | break; | ||
2517 | } | ||
2518 | |||
2519 | mlp->opt_dump_problem_all = GNUNET_CONFIGURATION_get_value_yesno (env->cfg, | ||
2520 | "ats", | ||
2521 | "MLP_DUMP_PROBLEM_ALL"); | ||
2522 | if (GNUNET_SYSERR == mlp->opt_dump_problem_all) | ||
2523 | mlp->opt_dump_problem_all = GNUNET_NO; | ||
2524 | |||
2525 | mlp->opt_dump_solution_all = GNUNET_CONFIGURATION_get_value_yesno (env->cfg, | ||
2526 | "ats", | ||
2527 | "MLP_DUMP_SOLUTION_ALL"); | ||
2528 | if (GNUNET_SYSERR == mlp->opt_dump_solution_all) | ||
2529 | mlp->opt_dump_solution_all = GNUNET_NO; | ||
2530 | |||
2531 | mlp->opt_dump_problem_on_fail = GNUNET_CONFIGURATION_get_value_yesno ( | ||
2532 | env->cfg, | ||
2533 | "ats", | ||
2534 | "MLP_DUMP_PROBLEM_ON_FAIL"); | ||
2535 | if (GNUNET_SYSERR == mlp->opt_dump_problem_on_fail) | ||
2536 | mlp->opt_dump_problem_on_fail = GNUNET_NO; | ||
2537 | |||
2538 | mlp->opt_dump_solution_on_fail = GNUNET_CONFIGURATION_get_value_yesno ( | ||
2539 | env->cfg, | ||
2540 | "ats", | ||
2541 | "MLP_DUMP_SOLUTION_ON_FAIL"); | ||
2542 | if (GNUNET_SYSERR == mlp->opt_dump_solution_on_fail) | ||
2543 | mlp->opt_dump_solution_on_fail = GNUNET_NO; | ||
2544 | |||
2545 | mlp->opt_dbg_glpk_verbose = GNUNET_CONFIGURATION_get_value_yesno (env->cfg, | ||
2546 | "ats", | ||
2547 | "MLP_DBG_GLPK_VERBOSE"); | ||
2548 | if (GNUNET_SYSERR == mlp->opt_dbg_glpk_verbose) | ||
2549 | mlp->opt_dbg_glpk_verbose = GNUNET_NO; | ||
2550 | |||
2551 | mlp->opt_dbg_feasibility_only = GNUNET_CONFIGURATION_get_value_yesno ( | ||
2552 | env->cfg, | ||
2553 | "ats", | ||
2554 | "MLP_DBG_FEASIBILITY_ONLY"); | ||
2555 | if (GNUNET_SYSERR == mlp->opt_dbg_feasibility_only) | ||
2556 | mlp->opt_dbg_feasibility_only = GNUNET_NO; | ||
2557 | if (GNUNET_YES == mlp->opt_dbg_feasibility_only) | ||
2558 | LOG (GNUNET_ERROR_TYPE_WARNING, | ||
2559 | "MLP solver is configured to check feasibility only!\n"); | ||
2560 | |||
2561 | mlp->opt_dbg_autoscale_problem = GNUNET_CONFIGURATION_get_value_yesno ( | ||
2562 | env->cfg, | ||
2563 | "ats", | ||
2564 | "MLP_DBG_AUTOSCALE_PROBLEM"); | ||
2565 | if (GNUNET_SYSERR == mlp->opt_dbg_autoscale_problem) | ||
2566 | mlp->opt_dbg_autoscale_problem = GNUNET_NO; | ||
2567 | if (GNUNET_YES == mlp->opt_dbg_autoscale_problem) | ||
2568 | LOG (GNUNET_ERROR_TYPE_WARNING, | ||
2569 | "MLP solver is configured automatically scale the problem!\n"); | ||
2570 | |||
2571 | mlp->opt_dbg_intopt_presolver = GNUNET_CONFIGURATION_get_value_yesno ( | ||
2572 | env->cfg, | ||
2573 | "ats", | ||
2574 | "MLP_DBG_INTOPT_PRESOLVE"); | ||
2575 | if (GNUNET_SYSERR == mlp->opt_dbg_intopt_presolver) | ||
2576 | mlp->opt_dbg_intopt_presolver = GNUNET_NO; | ||
2577 | if (GNUNET_YES == mlp->opt_dbg_intopt_presolver) | ||
2578 | LOG (GNUNET_ERROR_TYPE_WARNING, | ||
2579 | "MLP solver is configured use the mlp presolver\n"); | ||
2580 | |||
2581 | mlp->opt_dbg_optimize_diversity = GNUNET_CONFIGURATION_get_value_yesno ( | ||
2582 | env->cfg, | ||
2583 | "ats", | ||
2584 | "MLP_DBG_OPTIMIZE_DIVERSITY"); | ||
2585 | if (GNUNET_SYSERR == mlp->opt_dbg_optimize_diversity) | ||
2586 | mlp->opt_dbg_optimize_diversity = GNUNET_YES; | ||
2587 | if (GNUNET_NO == mlp->opt_dbg_optimize_diversity) | ||
2588 | LOG (GNUNET_ERROR_TYPE_WARNING, | ||
2589 | "MLP solver is not optimizing for diversity\n"); | ||
2590 | |||
2591 | mlp->opt_dbg_optimize_relativity = GNUNET_CONFIGURATION_get_value_yesno ( | ||
2592 | env->cfg, | ||
2593 | "ats", | ||
2594 | "MLP_DBG_OPTIMIZE_RELATIVITY"); | ||
2595 | if (GNUNET_SYSERR == mlp->opt_dbg_optimize_relativity) | ||
2596 | mlp->opt_dbg_optimize_relativity = GNUNET_YES; | ||
2597 | if (GNUNET_NO == mlp->opt_dbg_optimize_relativity) | ||
2598 | LOG (GNUNET_ERROR_TYPE_WARNING, | ||
2599 | "MLP solver is not optimizing for relativity\n"); | ||
2600 | |||
2601 | mlp->opt_dbg_optimize_quality = GNUNET_CONFIGURATION_get_value_yesno ( | ||
2602 | env->cfg, | ||
2603 | "ats", | ||
2604 | "MLP_DBG_OPTIMIZE_QUALITY"); | ||
2605 | if (GNUNET_SYSERR == mlp->opt_dbg_optimize_quality) | ||
2606 | mlp->opt_dbg_optimize_quality = GNUNET_YES; | ||
2607 | if (GNUNET_NO == mlp->opt_dbg_optimize_quality) | ||
2608 | LOG (GNUNET_ERROR_TYPE_WARNING, | ||
2609 | "MLP solver is not optimizing for quality\n"); | ||
2610 | |||
2611 | mlp->opt_dbg_optimize_utility = GNUNET_CONFIGURATION_get_value_yesno ( | ||
2612 | env->cfg, | ||
2613 | "ats", | ||
2614 | "MLP_DBG_OPTIMIZE_UTILITY"); | ||
2615 | if (GNUNET_SYSERR == mlp->opt_dbg_optimize_utility) | ||
2616 | mlp->opt_dbg_optimize_utility = GNUNET_YES; | ||
2617 | if (GNUNET_NO == mlp->opt_dbg_optimize_utility) | ||
2618 | LOG (GNUNET_ERROR_TYPE_WARNING, | ||
2619 | "MLP solver is not optimizing for utility\n"); | ||
2620 | |||
2621 | if ((GNUNET_NO == mlp->opt_dbg_optimize_utility) && | ||
2622 | (GNUNET_NO == mlp->opt_dbg_optimize_quality) && | ||
2623 | (GNUNET_NO == mlp->opt_dbg_optimize_relativity) && | ||
2624 | (GNUNET_NO == mlp->opt_dbg_optimize_utility) && | ||
2625 | (GNUNET_NO == mlp->opt_dbg_feasibility_only)) | ||
2626 | { | ||
2627 | LOG (GNUNET_ERROR_TYPE_ERROR, | ||
2628 | _ ( | ||
2629 | "MLP solver is not optimizing for anything, changing to feasibility check\n")); | ||
2630 | mlp->opt_dbg_feasibility_only = GNUNET_YES; | ||
2631 | } | ||
2632 | |||
2633 | if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_string (env->cfg, | ||
2634 | "ats", | ||
2635 | "MLP_LOG_FORMAT", | ||
2636 | &outputformat)) | ||
2637 | mlp->opt_log_format = MLP_CPLEX; | ||
2638 | else | ||
2639 | { | ||
2640 | GNUNET_STRINGS_utf8_toupper (outputformat, outputformat); | ||
2641 | if (0 == strcmp (outputformat, "MPS")) | ||
2642 | { | ||
2643 | mlp->opt_log_format = MLP_MPS; | ||
2644 | } | ||
2645 | else if (0 == strcmp (outputformat, "CPLEX")) | ||
2646 | { | ||
2647 | mlp->opt_log_format = MLP_CPLEX; | ||
2648 | } | ||
2649 | else if (0 == strcmp (outputformat, "GLPK")) | ||
2650 | { | ||
2651 | mlp->opt_log_format = MLP_GLPK; | ||
2652 | } | ||
2653 | else | ||
2654 | { | ||
2655 | LOG (GNUNET_ERROR_TYPE_WARNING, | ||
2656 | "Invalid log format `%s' in configuration, using CPLEX!\n", | ||
2657 | outputformat); | ||
2658 | mlp->opt_log_format = MLP_CPLEX; | ||
2659 | } | ||
2660 | GNUNET_free (outputformat); | ||
2661 | } | ||
2662 | |||
2663 | mlp->pv.BIG_M = (double) BIG_M_VALUE; | ||
2664 | |||
2665 | mlp->pv.mip_gap = (double) 0.0; | ||
2666 | if (GNUNET_SYSERR != GNUNET_CONFIGURATION_get_value_float (env->cfg, "ats", | ||
2667 | "MLP_MAX_MIP_GAP", | ||
2668 | &f_tmp)) | ||
2669 | { | ||
2670 | if ((f_tmp < 0.0) || (f_tmp > 1.0)) | ||
2671 | { | ||
2672 | LOG (GNUNET_ERROR_TYPE_ERROR, _ ("Invalid %s configuration %f \n"), | ||
2673 | "MIP gap", f_tmp); | ||
2674 | } | ||
2675 | else | ||
2676 | { | ||
2677 | mlp->pv.mip_gap = f_tmp; | ||
2678 | LOG (GNUNET_ERROR_TYPE_INFO, "Using %s of %.3f\n", | ||
2679 | "MIP gap", f_tmp); | ||
2680 | } | ||
2681 | } | ||
2682 | |||
2683 | mlp->pv.lp_mip_gap = (double) 0.0; | ||
2684 | if (GNUNET_SYSERR != GNUNET_CONFIGURATION_get_value_float (env->cfg, "ats", | ||
2685 | "MLP_MAX_LP_MIP_GAP", | ||
2686 | &f_tmp)) | ||
2687 | { | ||
2688 | if ((f_tmp < 0.0) || (f_tmp > 1.0)) | ||
2689 | { | ||
2690 | LOG (GNUNET_ERROR_TYPE_ERROR, _ ("Invalid %s configuration %f \n"), | ||
2691 | "LP/MIP", f_tmp); | ||
2692 | } | ||
2693 | else | ||
2694 | { | ||
2695 | mlp->pv.lp_mip_gap = f_tmp; | ||
2696 | LOG (GNUNET_ERROR_TYPE_INFO, "Using %s gap of %.3f\n", | ||
2697 | "LP/MIP", f_tmp); | ||
2698 | } | ||
2699 | } | ||
2700 | |||
2701 | /* Get timeout for iterations */ | ||
2702 | if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_time (env->cfg, "ats", | ||
2703 | "MLP_MAX_DURATION", | ||
2704 | &max_duration)) | ||
2705 | { | ||
2706 | max_duration = MLP_MAX_EXEC_DURATION; | ||
2707 | } | ||
2708 | |||
2709 | /* Get maximum number of iterations */ | ||
2710 | if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_size (env->cfg, "ats", | ||
2711 | "MLP_MAX_ITERATIONS", | ||
2712 | &max_iterations)) | ||
2713 | { | ||
2714 | max_iterations = MLP_MAX_ITERATIONS; | ||
2715 | } | ||
2716 | |||
2717 | /* Get diversity coefficient from configuration */ | ||
2718 | mlp->pv.co_D = MLP_DEFAULT_D; | ||
2719 | if (GNUNET_SYSERR != GNUNET_CONFIGURATION_get_value_float (env->cfg, "ats", | ||
2720 | "MLP_COEFFICIENT_D", | ||
2721 | &f_tmp)) | ||
2722 | { | ||
2723 | if ((f_tmp < 0.0)) | ||
2724 | { | ||
2725 | LOG (GNUNET_ERROR_TYPE_ERROR, _ ("Invalid %s configuration %f \n"), | ||
2726 | "MLP_COEFFICIENT_D", f_tmp); | ||
2727 | } | ||
2728 | else | ||
2729 | { | ||
2730 | mlp->pv.co_D = f_tmp; | ||
2731 | LOG (GNUNET_ERROR_TYPE_INFO, "Using %s gap of %.3f\n", | ||
2732 | "MLP_COEFFICIENT_D", f_tmp); | ||
2733 | } | ||
2734 | } | ||
2735 | |||
2736 | /* Get relativity coefficient from configuration */ | ||
2737 | mlp->pv.co_R = MLP_DEFAULT_R; | ||
2738 | if (GNUNET_SYSERR != GNUNET_CONFIGURATION_get_value_float (env->cfg, "ats", | ||
2739 | "MLP_COEFFICIENT_R", | ||
2740 | &f_tmp)) | ||
2741 | { | ||
2742 | if ((f_tmp < 0.0)) | ||
2743 | { | ||
2744 | LOG (GNUNET_ERROR_TYPE_ERROR, _ ("Invalid %s configuration %f \n"), | ||
2745 | "MLP_COEFFICIENT_R", f_tmp); | ||
2746 | } | ||
2747 | else | ||
2748 | { | ||
2749 | mlp->pv.co_R = f_tmp; | ||
2750 | LOG (GNUNET_ERROR_TYPE_INFO, "Using %s gap of %.3f\n", | ||
2751 | "MLP_COEFFICIENT_R", f_tmp); | ||
2752 | } | ||
2753 | } | ||
2754 | |||
2755 | |||
2756 | /* Get utilization coefficient from configuration */ | ||
2757 | mlp->pv.co_U = MLP_DEFAULT_U; | ||
2758 | if (GNUNET_SYSERR != GNUNET_CONFIGURATION_get_value_float (env->cfg, "ats", | ||
2759 | "MLP_COEFFICIENT_U", | ||
2760 | &f_tmp)) | ||
2761 | { | ||
2762 | if ((f_tmp < 0.0)) | ||
2763 | { | ||
2764 | LOG (GNUNET_ERROR_TYPE_ERROR, _ ("Invalid %s configuration %f \n"), | ||
2765 | "MLP_COEFFICIENT_U", f_tmp); | ||
2766 | } | ||
2767 | else | ||
2768 | { | ||
2769 | mlp->pv.co_U = f_tmp; | ||
2770 | LOG (GNUNET_ERROR_TYPE_INFO, "Using %s gap of %.3f\n", | ||
2771 | "MLP_COEFFICIENT_U", f_tmp); | ||
2772 | } | ||
2773 | } | ||
2774 | |||
2775 | /* Get quality metric coefficients from configuration */ | ||
2776 | for (c = 0; c < RQ_QUALITY_METRIC_COUNT; c++) | ||
2777 | { | ||
2778 | /* initialize quality coefficients with default value 1.0 */ | ||
2779 | mlp->pv.co_Q[c] = MLP_DEFAULT_QUALITY; | ||
2780 | } | ||
2781 | |||
2782 | |||
2783 | if (GNUNET_OK == | ||
2784 | GNUNET_CONFIGURATION_get_value_size (env->cfg, "ats", | ||
2785 | "MLP_COEFFICIENT_QUALITY_DELAY", | ||
2786 | &tmp)) | ||
2787 | mlp->pv.co_Q[RQ_QUALITY_METRIC_DELAY] = (double) tmp / 100; | ||
2788 | else | ||
2789 | mlp->pv.co_Q[RQ_QUALITY_METRIC_DELAY] = MLP_DEFAULT_QUALITY; | ||
2790 | |||
2791 | if (GNUNET_OK == | ||
2792 | GNUNET_CONFIGURATION_get_value_size (env->cfg, "ats", | ||
2793 | "MLP_COEFFICIENT_QUALITY_DISTANCE", | ||
2794 | &tmp)) | ||
2795 | mlp->pv.co_Q[RQ_QUALITY_METRIC_DISTANCE] = (double) tmp / 100; | ||
2796 | else | ||
2797 | mlp->pv.co_Q[RQ_QUALITY_METRIC_DISTANCE] = MLP_DEFAULT_QUALITY; | ||
2798 | |||
2799 | /* Get minimum bandwidth per used address from configuration */ | ||
2800 | if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_size (env->cfg, "ats", | ||
2801 | "MLP_MIN_BANDWIDTH", | ||
2802 | &tmp)) | ||
2803 | b_min = tmp; | ||
2804 | else | ||
2805 | { | ||
2806 | b_min = ntohl (GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT.value__); | ||
2807 | } | ||
2808 | |||
2809 | /* Get minimum number of connections from configuration */ | ||
2810 | if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_size (env->cfg, "ats", | ||
2811 | "MLP_MIN_CONNECTIONS", | ||
2812 | &tmp)) | ||
2813 | n_min = tmp; | ||
2814 | else | ||
2815 | n_min = MLP_DEFAULT_MIN_CONNECTIONS; | ||
2816 | |||
2817 | /* Init network quotas */ | ||
2818 | for (c = 0; c < GNUNET_NT_COUNT; c++) | ||
2819 | { | ||
2820 | mlp->pv.quota_index[c] = c; | ||
2821 | mlp->pv.quota_out[c] = env->out_quota[c]; | ||
2822 | mlp->pv.quota_in[c] = env->in_quota[c]; | ||
2823 | |||
2824 | LOG (GNUNET_ERROR_TYPE_INFO, | ||
2825 | "Quota for network `%s' (in/out) %llu/%llu\n", | ||
2826 | GNUNET_NT_to_string (c), | ||
2827 | mlp->pv.quota_out[c], | ||
2828 | mlp->pv.quota_in[c]); | ||
2829 | /* Check if defined quota could make problem unsolvable */ | ||
2830 | if ((n_min * b_min) > mlp->pv.quota_out[c]) | ||
2831 | { | ||
2832 | LOG (GNUNET_ERROR_TYPE_INFO, | ||
2833 | _ ( | ||
2834 | "Adjusting inconsistent outbound quota configuration for network `%s', is %llu must be at least %llu\n"), | ||
2835 | GNUNET_NT_to_string (mlp->pv.quota_index[c]), | ||
2836 | mlp->pv.quota_out[c], | ||
2837 | (n_min * b_min)); | ||
2838 | mlp->pv.quota_out[c] = (n_min * b_min); | ||
2839 | } | ||
2840 | if ((n_min * b_min) > mlp->pv.quota_in[c]) | ||
2841 | { | ||
2842 | LOG (GNUNET_ERROR_TYPE_INFO, | ||
2843 | _ ( | ||
2844 | "Adjusting inconsistent inbound quota configuration for network `%s', is %llu must be at least %llu\n"), | ||
2845 | GNUNET_NT_to_string (mlp->pv.quota_index[c]), | ||
2846 | mlp->pv.quota_in[c], | ||
2847 | (n_min * b_min)); | ||
2848 | mlp->pv.quota_in[c] = (n_min * b_min); | ||
2849 | } | ||
2850 | /* Check if bandwidth is too big to make problem solvable */ | ||
2851 | if (mlp->pv.BIG_M < mlp->pv.quota_out[c]) | ||
2852 | { | ||
2853 | LOG (GNUNET_ERROR_TYPE_INFO, | ||
2854 | _ ( | ||
2855 | "Adjusting outbound quota configuration for network `%s'from %llu to %.0f\n"), | ||
2856 | GNUNET_NT_to_string (mlp->pv.quota_index[c]), | ||
2857 | mlp->pv.quota_out[c], | ||
2858 | mlp->pv.BIG_M); | ||
2859 | mlp->pv.quota_out[c] = mlp->pv.BIG_M; | ||
2860 | } | ||
2861 | if (mlp->pv.BIG_M < mlp->pv.quota_in[c]) | ||
2862 | { | ||
2863 | LOG (GNUNET_ERROR_TYPE_INFO, | ||
2864 | _ ( | ||
2865 | "Adjusting inbound quota configuration for network `%s' from %llu to %.0f\n"), | ||
2866 | GNUNET_NT_to_string (mlp->pv.quota_index[c]), | ||
2867 | mlp->pv.quota_in[c], | ||
2868 | mlp->pv.BIG_M); | ||
2869 | mlp->pv.quota_in[c] = mlp->pv.BIG_M; | ||
2870 | } | ||
2871 | } | ||
2872 | mlp->env = env; | ||
2873 | sf.cls = mlp; | ||
2874 | sf.s_add = &GAS_mlp_address_add; | ||
2875 | sf.s_address_update_property = &GAS_mlp_address_property_changed; | ||
2876 | sf.s_get = &GAS_mlp_get_preferred_address; | ||
2877 | sf.s_get_stop = &GAS_mlp_stop_get_preferred_address; | ||
2878 | sf.s_pref = &GAS_mlp_address_change_preference; | ||
2879 | sf.s_feedback = &GAS_mlp_address_preference_feedback; | ||
2880 | sf.s_del = &GAS_mlp_address_delete; | ||
2881 | sf.s_bulk_start = &GAS_mlp_bulk_start; | ||
2882 | sf.s_bulk_stop = &GAS_mlp_bulk_stop; | ||
2883 | |||
2884 | /* Setting MLP Input variables */ | ||
2885 | mlp->pv.b_min = b_min; | ||
2886 | mlp->pv.n_min = n_min; | ||
2887 | mlp->pv.m_q = RQ_QUALITY_METRIC_COUNT; | ||
2888 | mlp->stat_mlp_prob_changed = GNUNET_NO; | ||
2889 | mlp->stat_mlp_prob_updated = GNUNET_NO; | ||
2890 | mlp->opt_mlp_auto_solve = GNUNET_YES; | ||
2891 | mlp->requested_peers = GNUNET_CONTAINER_multipeermap_create (10, GNUNET_NO); | ||
2892 | mlp->stat_bulk_requests = 0; | ||
2893 | mlp->stat_bulk_lock = 0; | ||
2894 | |||
2895 | /* Setup GLPK */ | ||
2896 | /* Redirect GLPK output to GNUnet logging */ | ||
2897 | glp_term_hook (&mlp_term_hook, (void *) mlp); | ||
2898 | |||
2899 | /* Init LP solving parameters */ | ||
2900 | glp_init_smcp (&mlp->control_param_lp); | ||
2901 | mlp->control_param_lp.msg_lev = GLP_MSG_OFF; | ||
2902 | if (GNUNET_YES == mlp->opt_dbg_glpk_verbose) | ||
2903 | mlp->control_param_lp.msg_lev = GLP_MSG_ALL; | ||
2904 | |||
2905 | mlp->control_param_lp.it_lim = max_iterations; | ||
2906 | mlp->control_param_lp.tm_lim = max_duration.rel_value_us / 1000LL; | ||
2907 | |||
2908 | /* Init MLP solving parameters */ | ||
2909 | glp_init_iocp (&mlp->control_param_mlp); | ||
2910 | /* Setting callback function */ | ||
2911 | mlp->control_param_mlp.cb_func = &mlp_branch_and_cut_cb; | ||
2912 | mlp->control_param_mlp.cb_info = mlp; | ||
2913 | mlp->control_param_mlp.msg_lev = GLP_MSG_OFF; | ||
2914 | mlp->control_param_mlp.mip_gap = mlp->pv.mip_gap; | ||
2915 | if (GNUNET_YES == mlp->opt_dbg_glpk_verbose) | ||
2916 | mlp->control_param_mlp.msg_lev = GLP_MSG_ALL; | ||
2917 | mlp->control_param_mlp.tm_lim = max_duration.rel_value_us / 1000LL; | ||
2918 | |||
2919 | LOG (GNUNET_ERROR_TYPE_DEBUG, "solver ready\n"); | ||
2920 | |||
2921 | return &sf; | ||
2922 | } | ||
2923 | |||
2924 | /* end of plugin_ats_mlp.c */ | ||