+#define BIG_M_STRING "unlimited"
+
+static struct Experiment *e;
+
+static struct LoggingHandle *l;
+
+static struct SolverHandle *sh;
+
+static struct TestPeer *peer_head;
+static struct TestPeer *peer_tail;
+
+static double default_properties[GNUNET_ATS_PropertyCount];
+static double default_preferences[GNUNET_ATS_PreferenceCount];
+
+/**
+ * cmd option -e: experiment file
+ */
+static char *opt_exp_file;
+
+static char *opt_solver;
+
+/**
+ * cmd option -l: enable logging
+ */
+static int opt_log;
+
+/**
+ * cmd option -p: enable plots
+ */
+static int opt_save;
+
+/**
+ * cmd option -v: verbose logs
+ */
+static int opt_verbose;
+
+/**
+ * cmd option -p: print logs
+ */
+static int opt_print;
+
+/**
+ * cmd option -d: disable normalization
+ */
+static int opt_disable_normalization;
+
+static int res;
+
+static void
+end_now ();
+
+
+static char *
+print_generator_type (enum GeneratorType g)
+{
+ switch (g) {
+ case GNUNET_ATS_TEST_TG_CONSTANT:
+ return "CONSTANT";
+ case GNUNET_ATS_TEST_TG_LINEAR:
+ return "LINEAR";
+ case GNUNET_ATS_TEST_TG_RANDOM:
+ return "RANDOM";
+ case GNUNET_ATS_TEST_TG_SINUS:
+ return "SINUS";
+ default:
+ return "INVALID";
+ break;
+ }
+}
+
+struct AddressLookupCtx
+{
+ struct ATS_Address *res;
+ char *plugin;
+ char *addr;
+};
+
+
+int find_address_it (void *cls,
+ const struct GNUNET_PeerIdentity *key,
+ void *value)
+{
+ struct AddressLookupCtx *ctx = cls;
+ struct ATS_Address *addr = value;
+
+ if ( (0 == strcmp (ctx->plugin, addr->plugin)) &&
+ (0 == strcmp (ctx->addr, addr->addr)) )
+ {
+ ctx->res = addr;
+ return GNUNET_NO;
+ }
+ return GNUNET_YES;
+}
+
+static struct TestPeer *
+find_peer_by_id (int id)
+{
+ struct TestPeer *cur;
+ for (cur = peer_head; NULL != cur; cur = cur->next)
+ if (cur->id == id)
+ return cur;
+ return NULL;
+}
+
+static struct TestPeer *
+find_peer_by_pid (const struct GNUNET_PeerIdentity *pid)
+{
+ struct TestPeer *cur;
+ for (cur = peer_head; NULL != cur; cur = cur->next)
+ if (0 == memcmp (&cur->peer_id, pid, sizeof (struct GNUNET_PeerIdentity)))
+ return cur;
+ return NULL;
+}
+
+static struct TestAddress *
+find_address_by_id (struct TestPeer *peer, int aid)
+{
+ struct TestAddress *cur;
+ for (cur = peer->addr_head; NULL != cur; cur = cur->next)
+ if (cur->aid == aid)
+ return cur;
+ return NULL;
+}
+
+
+static struct TestAddress *
+find_address_by_ats_address (struct TestPeer *p, const struct ATS_Address *addr)
+{
+ struct TestAddress *cur;
+ for (cur = p->addr_head; NULL != cur; cur = cur->next)
+ if ((0 == strcmp(cur->ats_addr->plugin, addr->plugin)) &&
+ (cur->ats_addr->addr_len == addr->addr_len) &&
+ (0 == memcmp (cur->ats_addr->addr, addr->addr, addr->addr_len)))
+ return cur;
+ return NULL;
+}
+
+
+/**
+ * Logging
+ */
+
+void
+GNUNET_ATS_solver_logging_now (struct LoggingHandle *l)
+{
+ struct LoggingTimeStep *lts;
+ struct TestPeer *cur;
+ struct TestAddress *cur_addr;
+ struct LoggingPeer *log_p;
+ struct LoggingAddress *log_a;
+ int c;
+
+ lts = GNUNET_new (struct LoggingTimeStep);
+ GNUNET_CONTAINER_DLL_insert_tail(l->head, l->tail, lts);
+ lts->timestamp = GNUNET_TIME_absolute_get();
+ if (NULL == lts->prev)
+ lts->delta = GNUNET_TIME_UNIT_ZERO;
+ else
+ lts->delta = GNUNET_TIME_absolute_get_duration(lts->prev->timestamp);
+
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Logging %llu, delta %llu\n",
+ lts->timestamp.abs_value_us, lts->delta.rel_value_us);
+
+
+ /* Store logging data here */
+ for (cur = peer_head; NULL != cur; cur = cur->next)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Logging peer id %llu\n", cur->id);
+
+ log_p = GNUNET_new (struct LoggingPeer);
+ log_p->id = cur->id;
+ log_p->peer_id = cur->peer_id;
+ for (c = 0; c < GNUNET_ATS_PreferenceCount; c++)
+ {
+ log_p->pref_abs[c] = cur->pref_abs[c];
+ log_p->pref_norm[c] = cur->pref_norm[c];
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "\t %s = %.2f %.2f [abs/rel]\n",
+ GNUNET_ATS_print_preference_type(c),
+ log_p->pref_abs[c], log_p->pref_norm[c]);
+ }
+ GNUNET_CONTAINER_DLL_insert_tail(lts->head, lts->tail, log_p);
+
+ for (cur_addr = cur->addr_head; NULL != cur_addr; cur_addr = cur_addr->next)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Logging peer id %llu address %llu \n",
+ cur->id, cur_addr->aid);
+ log_a = GNUNET_new (struct LoggingAddress);
+ log_a->aid = cur_addr->aid;
+ log_a->active = cur_addr->ats_addr->active;
+ log_a->network = cur_addr->network;
+ log_a->used = cur_addr->ats_addr->used;
+ log_a->assigned_bw_in = cur_addr->ats_addr->assigned_bw_in;
+ log_a->assigned_bw_out = cur_addr->ats_addr->assigned_bw_out;
+ for (c = 0; c < GNUNET_ATS_PropertyCount; c++)
+ {
+ log_a->prop_abs[c] = cur_addr->prop_abs[c];
+ log_a->prop_norm[c] = cur_addr->prop_norm[c];
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "\t %s = %.2f %.2f [abs/rel]\n",
+ GNUNET_ATS_print_property_type(c),
+ log_a->prop_abs[c], log_a->prop_norm[c]);
+ }
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "\t Active = %i\n", log_a->active);
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "\t BW in = %llu\n", ntohl(log_a->assigned_bw_in.value__));
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO, "\t BW out = %llu\n", ntohl(log_a->assigned_bw_out.value__));
+
+ GNUNET_CONTAINER_DLL_insert_tail (log_p->addr_head, log_p->addr_tail, log_a);
+ }
+ }
+}
+
+static void
+logging_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ struct LoggingHandle *l = cls;
+ l->logging_task = GNUNET_SCHEDULER_NO_TASK;
+
+ GNUNET_ATS_solver_logging_now (l);
+
+ l->logging_task = GNUNET_SCHEDULER_add_delayed (l->log_freq, &logging_task, l);
+
+}
+
+struct LoggingHandle *
+GNUNET_ATS_solver_logging_start (struct GNUNET_TIME_Relative freq)
+{
+ struct LoggingHandle *l;
+ l = GNUNET_new (struct LoggingHandle);
+
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Start logging every %s\n",
+ GNUNET_STRINGS_relative_time_to_string(freq, GNUNET_NO));
+ l->log_freq = freq;
+ l->logging_task = GNUNET_SCHEDULER_add_now (&logging_task, l);
+ return l;
+}
+
+void
+GNUNET_ATS_solver_logging_stop (struct LoggingHandle *l)
+{
+ if (GNUNET_SCHEDULER_NO_TASK != l->logging_task)
+ GNUNET_SCHEDULER_cancel (l->logging_task);
+
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Stop logging\n");
+
+ l->logging_task = GNUNET_SCHEDULER_NO_TASK;
+}
+
+static struct LoggingFileHandle *
+find_logging_file_handle (struct LoggingFileHandle *lf_head,
+ struct LoggingFileHandle *lf_tail,
+ int peer_id, int address_id)
+{
+ struct LoggingFileHandle *res;
+
+ for (res = lf_head; NULL != res; res = res->next)
+ if ((res->pid == peer_id) && (res->aid == address_id))
+ return res;
+ return NULL;
+
+}
+
+void
+GNUNET_ATS_solver_logging_write_to_disk (struct LoggingHandle *l, int add_time_stamp,
+ char *output_dir)
+{
+ struct LoggingTimeStep *lts;
+ struct LoggingPeer *log_p;
+ struct LoggingAddress *log_a;
+ struct LoggingFileHandle *lf_head;
+ struct LoggingFileHandle *lf_tail;
+ struct LoggingFileHandle *cur;
+ struct LoggingFileHandle *next;
+ char * filename;
+ char * datastring;
+ char * propstring;
+ char * propstring_tmp;
+ char * prefstring;
+ char * prefstring_tmp;
+ int c;
+ int use_dir;
+
+ use_dir = GNUNET_NO;
+ if (NULL != output_dir)
+ {
+ if (GNUNET_OK != GNUNET_DISK_directory_create_for_file (output_dir))
+ {
+ fprintf (stderr, "Failed to create directory `%s'\n", output_dir);
+ return;
+ }
+ else
+ {
+ fprintf (stderr, "Created directory `%s'\n", output_dir);
+ use_dir = GNUNET_YES;
+ }
+ }
+
+ lf_head = NULL;
+ lf_tail = NULL;
+
+ for (lts = l->head; NULL != lts; lts = lts->next)
+ {
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Writing log step %llu\n",
+ (long long unsigned int) lts->timestamp.abs_value_us);
+
+ for (log_p = lts->head; NULL != log_p; log_p = log_p->next)
+ {
+ for (log_a = log_p->addr_head; NULL != log_a; log_a = log_a->next)
+ {
+
+ cur = find_logging_file_handle (lf_head, lf_tail, log_p->id,
+ log_a->aid);
+ if (NULL == cur)
+ {
+ cur = GNUNET_new (struct LoggingFileHandle);
+ cur->aid = log_a->aid;
+ cur->pid = log_p->id;
+
+ if (GNUNET_YES == add_time_stamp)
+ GNUNET_asprintf (&filename, "%s%s%s_%s_p%u_a%u_%llu.log",
+ (GNUNET_YES == use_dir) ? output_dir : "",
+ (GNUNET_YES == use_dir) ? DIR_SEPARATOR_STR : "",
+ e->log_prefix,
+ opt_solver,
+ cur->pid,
+ cur->aid,
+ l->head->timestamp.abs_value_us);
+ else
+ GNUNET_asprintf (&filename, "%s%s%s_%s_p%u_a%u.log",
+ (GNUNET_YES == use_dir) ? output_dir : "",
+ (GNUNET_YES == use_dir) ? DIR_SEPARATOR_STR : "",
+ e->log_prefix,
+ opt_solver,
+ cur->pid,
+ cur->aid);
+
+ fprintf (stderr, "Add writing log data for peer %llu address %llu to file `%s'\n",
+ cur->pid, cur->aid, filename);
+
+
+ cur->f_hd = GNUNET_DISK_file_open (filename,
+ GNUNET_DISK_OPEN_READWRITE |
+ GNUNET_DISK_OPEN_CREATE |
+ GNUNET_DISK_OPEN_TRUNCATE,
+ GNUNET_DISK_PERM_USER_READ |
+ GNUNET_DISK_PERM_USER_WRITE |
+ GNUNET_DISK_PERM_GROUP_READ |
+ GNUNET_DISK_PERM_OTHER_READ);
+ if (NULL == cur->f_hd)
+ {
+ fprintf (stderr, "Cannot open `%s' to write log data!\n", filename);
+ GNUNET_free (filename);
+ goto cleanup;
+ }
+ GNUNET_free (filename);
+ GNUNET_CONTAINER_DLL_insert (lf_head, lf_tail, cur);
+
+ GNUNET_asprintf(&datastring,"#time delta;log duration; addr net; addr_active; bw in; bw out; " \
+ "UTILIZATION_UP [abs/rel]; UTILIZATION_UP; UTILIZATION_DOWN; UTILIZATION_DOWN; " \
+ "UTILIZATION_PAYLOAD_UP; UTILIZATION_PAYLOAD_UP; UTILIZATION_PAYLOAD_DOWN; UTILIZATION_PAYLOAD_DOWN;"\
+ "DELAY; DELAY; " \
+ "DISTANCE ;DISTANCE ; COST_WAN; COST_WAN; COST_LAN; COST_LAN; " \
+ "COST_WLAN; COST_WLAN; PREF BW abs; PREF BW rel; PREF LATENCY abs; PREF LATENCY rel;\n");
+ GNUNET_DISK_file_write (cur->f_hd, datastring, strlen(datastring));
+ GNUNET_free (datastring);
+
+ }
+
+ prefstring = GNUNET_strdup("");
+ for (c = 1; c < GNUNET_ATS_PreferenceCount; c++)
+ {
+ /*
+ fprintf(stderr,"\t %s = %.2f %.2f [abs/rel]\n",
+ GNUNET_ATS_print_preference_type(c),
+ log_p->pref_abs[c], log_p->pref_norm[c]);
+ */
+ GNUNET_asprintf(&prefstring_tmp,"%s;%.3f;%.3f",
+ prefstring, log_p->pref_abs[c], log_p->pref_norm[c]);
+
+
+ GNUNET_free (prefstring);
+ prefstring = GNUNET_strdup(prefstring_tmp);
+ GNUNET_free (prefstring_tmp);
+ }
+
+
+ propstring = GNUNET_strdup("");
+ for (c = 1; c < GNUNET_ATS_PropertyCount; c++)
+ {
+ if (GNUNET_ATS_NETWORK_TYPE == c)
+ continue;
+ /*
+ fprintf(stderr, "\t %s = %.2f %.2f [abs/rel]\n",
+ GNUNET_ATS_print_property_type(c),
+ log_a->prop_abs[c], log_a->prop_norm[c]);*/
+ GNUNET_asprintf(&propstring_tmp,"%s%.3f;%.3f;",
+ propstring, log_a->prop_abs[c], log_a->prop_norm[c]);
+ GNUNET_free (propstring);
+ propstring = GNUNET_strdup(propstring_tmp);
+ GNUNET_free (propstring_tmp);
+ }
+
+ GNUNET_asprintf(&datastring,"%llu;%llu;%u;%i;%u;%u;%s;%s\n",
+ GNUNET_TIME_absolute_get_difference(l->head->timestamp, lts->timestamp).rel_value_us / 1000,
+ lts->delta,
+ log_a->network,
+ log_a->active,
+ ntohl (log_a->assigned_bw_in.value__),
+ ntohl (log_a->assigned_bw_out.value__),
+ propstring, prefstring);
+
+ GNUNET_DISK_file_write (cur->f_hd, datastring, strlen(datastring));
+ GNUNET_free (datastring);
+ GNUNET_free (prefstring);
+ GNUNET_free (propstring);
+ }
+ }
+ }
+
+cleanup:
+ next = lf_head;
+ for (cur = next; NULL != cur; cur = next)
+ {
+ next = cur->next;
+ GNUNET_CONTAINER_DLL_remove (lf_head, lf_tail, cur);
+ if (NULL != cur->f_hd)
+ GNUNET_DISK_file_close (cur->f_hd);
+ GNUNET_free (cur);
+ }
+
+}
+
+void
+GNUNET_ATS_solver_logging_eval (struct LoggingHandle *l)
+{
+ struct LoggingTimeStep *lts;
+ struct LoggingPeer *log_p;
+ struct LoggingAddress *log_a;
+ int c;
+
+ for (lts = l->head; NULL != lts; lts = lts->next)
+ {
+ fprintf (stderr, "Log step %llu %llu: \n",
+ (long long unsigned int) lts->timestamp.abs_value_us,
+ (long long unsigned int) lts->delta.rel_value_us);
+
+ for (log_p = lts->head; NULL != log_p; log_p = log_p->next)
+ {
+ fprintf (stderr,"\tLogging peer pid %llu\n", log_p->id);
+ for (c = 1; c < GNUNET_ATS_PreferenceCount; c++)
+ {
+ fprintf(stderr,"\t %s = %.2f %.2f [abs/rel]\n",
+ GNUNET_ATS_print_preference_type(c),
+ log_p->pref_abs[c], log_p->pref_norm[c]);
+ }
+
+ for (log_a = log_p->addr_head; NULL != log_a; log_a = log_a->next)
+ {
+ fprintf (stderr, "\tPeer pid %llu address %llu: %u %u %u\n",
+ log_p->id, log_a->aid, log_a->active,
+ ntohl(log_a->assigned_bw_in.value__),
+ ntohl(log_a->assigned_bw_out.value__));
+
+ for (c = 1; c < GNUNET_ATS_PropertyCount; c++)
+ {
+ if (GNUNET_ATS_NETWORK_TYPE == c)
+ continue;
+ fprintf(stderr, "\t %s = %.2f %.2f [abs/rel]\n",
+ GNUNET_ATS_print_property_type(c),
+ log_a->prop_abs[c], log_a->prop_norm[c]);
+ }
+ }
+ }
+ }
+}
+
+void
+GNUNET_ATS_solver_logging_free (struct LoggingHandle *l)
+{
+ struct LoggingTimeStep *lts_cur;
+ struct LoggingTimeStep *lts_next;
+ struct LoggingPeer *log_p_cur;
+ struct LoggingPeer *log_p_next;
+ struct LoggingAddress *log_a_cur;
+ struct LoggingAddress *log_a_next;
+
+ if (GNUNET_SCHEDULER_NO_TASK != l->logging_task)
+ GNUNET_SCHEDULER_cancel (l->logging_task);
+ l->logging_task = GNUNET_SCHEDULER_NO_TASK;
+
+ lts_next = l->head;
+ while (NULL != (lts_cur = lts_next))
+ {
+ lts_next = lts_cur->next;
+
+ log_p_next = lts_cur->head;
+ while (NULL != (log_p_cur = log_p_next))
+ {
+ log_p_next = log_p_cur->next;
+
+ log_a_next = log_p_cur->addr_head;
+ while (NULL != (log_a_cur = log_a_next))
+ {
+ log_a_next = log_a_cur->next;
+
+ GNUNET_CONTAINER_DLL_remove (log_p_cur->addr_head, log_p_cur->addr_tail, log_a_cur);
+ GNUNET_free (log_a_cur);
+ }
+
+ GNUNET_CONTAINER_DLL_remove (lts_cur->head, lts_cur->tail, log_p_cur);
+ GNUNET_free (log_p_cur);
+ }
+
+ GNUNET_CONTAINER_DLL_remove (l->head, l->tail, lts_cur);
+ GNUNET_free (lts_cur);
+ }
+
+ GNUNET_free (l);
+}
+
+/**
+ * Property Generators
+ */
+
+static struct PropertyGenerator *prop_gen_head;
+static struct PropertyGenerator *prop_gen_tail;
+
+static double
+get_property (struct PropertyGenerator *pg)
+{
+ struct GNUNET_TIME_Relative time_delta;
+ double delta_value;
+ double pref_value;
+
+ /* Calculate the current preference value */
+ switch (pg->type) {
+ case GNUNET_ATS_TEST_TG_CONSTANT:
+ pref_value = pg->base_value;
+ break;
+ case GNUNET_ATS_TEST_TG_LINEAR:
+ time_delta = GNUNET_TIME_absolute_get_duration(pg->time_start);
+ /* Calculate point of time in the current period */
+ time_delta.rel_value_us = time_delta.rel_value_us %
+ pg->duration_period.rel_value_us;
+ delta_value = ((double) time_delta.rel_value_us /
+ pg->duration_period.rel_value_us) * (pg->max_value - pg->base_value);
+ if ((pg->max_value < pg->base_value) &&
+ ((pg->max_value - pg->base_value) > pg->base_value))
+ {
+ /* This will cause an underflow */
+ GNUNET_break (0);
+ }
+ pref_value = pg->base_value + delta_value;
+ break;
+ case GNUNET_ATS_TEST_TG_RANDOM:
+ delta_value = (double) GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
+ 10000 * (pg->max_value - pg->base_value)) / 10000;
+ pref_value = pg->base_value + delta_value;
+ break;
+ case GNUNET_ATS_TEST_TG_SINUS:
+ time_delta = GNUNET_TIME_absolute_get_duration(pg->time_start);
+ /* Calculate point of time in the current period */
+ time_delta.rel_value_us = time_delta.rel_value_us %
+ pg->duration_period.rel_value_us;
+ if ((pg->max_value - pg->base_value) > pg->base_value)
+ {
+ /* This will cause an underflow for second half of sinus period,
+ * will be detected in general when experiments are loaded */
+ GNUNET_break (0);
+ }
+ delta_value = (pg->max_value - pg->base_value) *
+ sin ( (2 * M_PI) / ((double) pg->duration_period.rel_value_us) *
+ time_delta.rel_value_us);
+ pref_value = pg->base_value + delta_value;
+ break;
+ default:
+ pref_value = 0.0;
+ break;
+ }
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Current property value is %f\n",
+ pref_value);
+ return pref_value;
+}
+
+
+static void
+set_prop_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ struct PropertyGenerator *pg = cls;
+ struct TestPeer *p;
+ struct TestAddress *a;
+ double prop_value;
+ struct GNUNET_ATS_Information atsi;
+
+ pg->set_task = GNUNET_SCHEDULER_NO_TASK;
+
+ if (GNUNET_NO == GNUNET_CONTAINER_multipeermap_contains_value (sh->addresses,
+ &pg->test_peer->peer_id, pg->test_address->ats_addr))
+ {
+ GNUNET_break (0);
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Setting property generation for unknown address [%u:%u]\n",
+ pg->peer, pg->address_id);
+ return;
+ }
+ if (NULL == (p = find_peer_by_id (pg->peer)))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Setting property generation for unknown peer %u\n",
+ pg->peer);
+ }
+ if (NULL == (a = find_address_by_id (p, pg->address_id)))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Setting property generation for unknown peer %u\n",
+ pg->peer);
+ }
+
+ prop_value = get_property (pg);
+ a->prop_abs[pg->ats_property] = prop_value;
+
+ GNUNET_log(GNUNET_ERROR_TYPE_INFO,
+ "Setting property for peer [%u] address [%u] for %s to %f\n",
+ pg->peer, pg->address_id,
+ GNUNET_ATS_print_property_type (pg->ats_property), prop_value);
+
+ atsi.type = htonl (pg->ats_property);
+ atsi.value = htonl ((uint32_t) prop_value);
+
+ /* set performance here! */
+ sh->env.sf.s_bulk_start (sh->solver);
+ if (GNUNET_YES == opt_disable_normalization)
+ {
+ a->prop_abs[pg->ats_property] = prop_value;
+ a->prop_norm[pg->ats_property] = prop_value;
+ sh->env.sf.s_address_update_property (sh->solver, a->ats_addr,
+ pg->ats_property, prop_value, prop_value);
+ }
+ else
+ GAS_normalization_normalize_property (sh->addresses,
+ pg->test_address->ats_addr, &atsi, 1);
+ sh->env.sf.s_bulk_stop (sh->solver);
+
+ pg->set_task = GNUNET_SCHEDULER_add_delayed (pg->frequency,
+ &set_prop_task, pg);
+
+}
+
+/**
+ * Set ats_property to 0 to find all pgs
+ */
+
+static struct PropertyGenerator *
+find_prop_gen (unsigned int peer, unsigned int address,
+ uint32_t ats_property)
+{
+ struct PropertyGenerator *cur;
+ for (cur = prop_gen_head; NULL != cur; cur = cur->next)
+ if ((cur->peer == peer) && (cur->address_id == address))
+ {
+ if ((cur->ats_property == ats_property) || (0 == ats_property))
+ return cur;
+ }
+ return NULL;
+}
+
+void
+GNUNET_ATS_solver_generate_property_stop (struct PropertyGenerator *pg)
+{
+ GNUNET_CONTAINER_DLL_remove (prop_gen_head, prop_gen_tail, pg);
+
+ if (GNUNET_SCHEDULER_NO_TASK != pg->set_task)
+ {
+ GNUNET_SCHEDULER_cancel (pg->set_task);
+ pg->set_task = GNUNET_SCHEDULER_NO_TASK;
+ }
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Removing old up preference generator peer [%u] address [%u] `%s'\n",
+ pg->peer, pg->address_id,
+ GNUNET_ATS_print_property_type(pg->ats_property));
+
+ GNUNET_free (pg);
+}
+
+
+/**
+ * Generate between the source master and the partner and set property with a
+ * value depending on the generator.
+ *
+ * @param peer source
+ * @param address_id partner
+ * @param test_peer the peer
+ * @param test_address the address
+ * @param type type of generator
+ * @param base_value base value
+ * @param value_rate maximum value
+ * @param period duration of a period of generation (~ 1/frequency)
+ * @param frequency how long to generate property
+ * @param ats_property ATS property to generate
+ * @return the property generator
+ */
+struct PropertyGenerator *
+GNUNET_ATS_solver_generate_property_start (unsigned int peer,
+ unsigned int address_id,
+ struct TestPeer *test_peer,
+ struct TestAddress *test_address,
+ enum GeneratorType type,
+ long int base_value,
+ long int value_rate,
+ struct GNUNET_TIME_Relative period,
+ struct GNUNET_TIME_Relative frequency,
+ uint32_t ats_property)
+{
+ struct PropertyGenerator *pg;
+
+ pg = GNUNET_new (struct PropertyGenerator);
+ GNUNET_CONTAINER_DLL_insert (prop_gen_head, prop_gen_tail, pg);
+ pg->type = type;
+ pg->peer = peer;
+ pg->test_address = test_address;
+ pg->test_peer = test_peer;
+ pg->address_id = address_id;
+ pg->ats_property = ats_property;
+ pg->base_value = base_value;
+ pg->max_value = value_rate;
+ pg->duration_period = period;
+ pg->frequency = frequency;
+ pg->time_start = GNUNET_TIME_absolute_get();
+
+ switch (type) {
+ case GNUNET_ATS_TEST_TG_CONSTANT:
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Setting up %s property generator peer [%u] address [%u] `%s'"\
+ "max %u Bips\n",
+ print_generator_type(type), pg->peer, pg->address_id,
+ GNUNET_ATS_print_property_type (ats_property),
+ base_value);
+ break;
+ case GNUNET_ATS_TEST_TG_LINEAR:
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Setting up %s property generator peer [%u] address [%u] `%s' " \
+ "min %u Bips max %u Bips\n",
+ print_generator_type(type), pg->peer, pg->address_id,
+ GNUNET_ATS_print_property_type(ats_property),
+ base_value, value_rate);
+ break;
+ case GNUNET_ATS_TEST_TG_SINUS:
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Setting up %s property generator peer [%u] address [%u] `%s' "\
+ "baserate %u Bips, amplitude %u Bps\n",
+ print_generator_type(type), pg->peer, pg->address_id,
+ GNUNET_ATS_print_property_type(ats_property),
+ base_value, value_rate);
+ break;
+ case GNUNET_ATS_TEST_TG_RANDOM:
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Setting up %s property generator peer [%u] address [%u] `%s' "\
+ "min %u Bips max %u Bps\n",
+ print_generator_type(type), pg->peer, pg->address_id,
+ GNUNET_ATS_print_property_type(ats_property),
+ base_value, value_rate);
+ break;
+ default:
+ break;
+ }
+
+ pg->set_task = GNUNET_SCHEDULER_add_now (&set_prop_task, pg);
+ return pg;
+}
+
+
+
+/**
+ * Stop all preferences generators
+ */
+void
+GNUNET_ATS_solver_generate_property_stop_all ()
+{
+ struct PropertyGenerator *cur;
+ struct PropertyGenerator *next;
+ next = prop_gen_head;
+ for (cur = next; NULL != cur; cur = next)
+ {
+ next = cur->next;
+ GNUNET_ATS_solver_generate_property_stop (cur);
+ }
+}
+
+
+/**
+ * Preference Generators
+ */
+
+static struct PreferenceGenerator *pref_gen_head;
+static struct PreferenceGenerator *pref_gen_tail;
+
+static double
+get_preference (struct PreferenceGenerator *pg)
+{
+ struct GNUNET_TIME_Relative time_delta;
+ double delta_value;
+ double pref_value;
+
+ /* Calculate the current preference value */
+ switch (pg->type) {
+ case GNUNET_ATS_TEST_TG_CONSTANT:
+ pref_value = pg->base_value;
+ break;
+ case GNUNET_ATS_TEST_TG_LINEAR:
+ time_delta = GNUNET_TIME_absolute_get_duration(pg->time_start);
+ /* Calculate point of time in the current period */
+ time_delta.rel_value_us = time_delta.rel_value_us %
+ pg->duration_period.rel_value_us;
+ delta_value = ((double) time_delta.rel_value_us /
+ pg->duration_period.rel_value_us) * (pg->max_value - pg->base_value);
+ if ((pg->max_value < pg->base_value) &&
+ ((pg->max_value - pg->base_value) > pg->base_value))
+ {
+ /* This will cause an underflow */
+ GNUNET_break (0);
+ }
+ pref_value = pg->base_value + delta_value;
+ break;
+ case GNUNET_ATS_TEST_TG_RANDOM:
+ delta_value = (double) GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
+ 10000 * (pg->max_value - pg->base_value)) / 10000;
+ pref_value = pg->base_value + delta_value;
+ break;
+ case GNUNET_ATS_TEST_TG_SINUS:
+ time_delta = GNUNET_TIME_absolute_get_duration(pg->time_start);
+ /* Calculate point of time in the current period */
+ time_delta.rel_value_us = time_delta.rel_value_us %
+ pg->duration_period.rel_value_us;
+ if ((pg->max_value - pg->base_value) > pg->base_value)
+ {
+ /* This will cause an underflow for second half of sinus period,
+ * will be detected in general when experiments are loaded */
+ GNUNET_break (0);
+ }
+ delta_value = (pg->max_value - pg->base_value) *
+ sin ( (2 * M_PI) / ((double) pg->duration_period.rel_value_us) *
+ time_delta.rel_value_us);
+ pref_value = pg->base_value + delta_value;
+ break;
+ default:
+ pref_value = 0.0;
+ break;
+ }
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Current preference value is %f\n",
+ pref_value);
+ return pref_value;
+}