Esempio n. 1
0
/**
 * This function secures calls to glpk with an error hook.
 * @param forceError force error if bit 0 = 1
 * @return ok code: 1 failure, 2 out of memory
 */
int runOptimizer(int forceError) {
    int ret = 0;
    INFO *info;
    info = (INFO*) malloc(sizeof(INFO));
    if (info == NULL) {
        return 2;
    }
    info->env = (jmp_buf *) malloc(sizeof(jmp_buf));
    if (info->env == NULL) {
        free(info);
        return 2;
    }
    info->text = "This information was passed to the hook function.";
    if (setjmp(*(info->env))) {
        printf("Post treatment of error.\n");
        ret = 1;
    } else {
        glp_error_hook(errorHook, info);
        buildModel(forceError);
    }
    glp_error_hook(NULL, NULL);
    free(info->env);
    free(info);
    return ret;
}
/**
 * Init the MLP problem solving component
 *
 * @param cfg the GNUNET_CONFIGURATION_Handle handle
 * @param stats the GNUNET_STATISTICS handle
 * @param max_duration maximum numbers of iterations for the LP/MLP Solver
 * @param max_iterations maximum time limit for the LP/MLP Solver
 * @return struct GAS_MLP_Handle * on success, NULL on fail
 */
struct GAS_MLP_Handle *
GAS_mlp_init (const struct GNUNET_CONFIGURATION_Handle *cfg,
              const struct GNUNET_STATISTICS_Handle *stats,
              struct GNUNET_TIME_Relative max_duration,
              unsigned int max_iterations)
{
  struct GAS_MLP_Handle * mlp = GNUNET_malloc (sizeof (struct GAS_MLP_Handle));

  double D;
  double R;
  double U;
  unsigned long long tmp;
  unsigned int b_min;
  unsigned int n_min;
  struct GNUNET_TIME_Relative i_exec;
  int c;
  char * quota_out_str;
  char * quota_in_str;

  /* Init GLPK environment */
  int res = glp_init_env();
  switch (res) {
    case 0:
      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "GLPK: `%s'\n",
          "initialization successful");
      break;
    case 1:
      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "GLPK: `%s'\n",
          "environment is already initialized");
      break;
    case 2:
      GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Could not init GLPK: `%s'\n",
          "initialization failed (insufficient memory)");
      GNUNET_free(mlp);
      return NULL;
      break;
    case 3:
      GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Could not init GLPK: `%s'\n",
          "initialization failed (unsupported programming model)");
      GNUNET_free(mlp);
      return NULL;
      break;
    default:
      break;
  }

  /* Create initial MLP problem */
  mlp->prob = glp_create_prob();
  GNUNET_assert (mlp->prob != NULL);

  mlp->BIG_M = (double) BIG_M_VALUE;

  /* Get diversity coefficient from configuration */
  if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_size (cfg, "ats",
                                                      "COEFFICIENT_D",
                                                      &tmp))
    D = (double) tmp / 100;
  else
    D = 1.0;

  /* Get proportionality coefficient from configuration */
  if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_size (cfg, "ats",
                                                      "COEFFICIENT_R",
                                                      &tmp))
    R = (double) tmp / 100;
  else
    R = 1.0;

  /* Get utilization coefficient from configuration */
  if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_size (cfg, "ats",
                                                      "COEFFICIENT_U",
                                                      &tmp))
    U = (double) tmp / 100;
  else
    U = 1.0;

  /* Get quality metric coefficients from configuration */
  int i_delay = -1;
  int i_distance = -1;
  int q[GNUNET_ATS_QualityPropertiesCount] = GNUNET_ATS_QualityProperties;
  for (c = 0; c < GNUNET_ATS_QualityPropertiesCount; c++)
  {
    /* initialize quality coefficients with default value 1.0 */
    mlp->co_Q[c] = 1.0;

    mlp->q[c] = q[c];
    if (q[c] == GNUNET_ATS_QUALITY_NET_DELAY)
      i_delay = c;
    if (q[c] == GNUNET_ATS_QUALITY_NET_DISTANCE)
      i_distance = c;
  }

  if ((i_delay != -1) && (GNUNET_OK == GNUNET_CONFIGURATION_get_value_size (cfg, "ats",
                                                      "COEFFICIENT_QUALITY_DELAY",
                                                      &tmp)))

    mlp->co_Q[i_delay] = (double) tmp / 100;
  else
    mlp->co_Q[i_delay] = 1.0;

  if ((i_distance != -1) && (GNUNET_OK == GNUNET_CONFIGURATION_get_value_size (cfg, "ats",
                                                      "COEFFICIENT_QUALITY_DISTANCE",
                                                      &tmp)))
    mlp->co_Q[i_distance] = (double) tmp / 100;
  else
    mlp->co_Q[i_distance] = 1.0;

  /* Get minimum bandwidth per used address from configuration */
  if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_size (cfg, "ats",
                                                      "MIN_BANDWIDTH",
                                                      &tmp))
    b_min = tmp;
  else
  {
    b_min = ntohl (GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT.value__);
  }

  /* Get minimum number of connections from configuration */
  if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_size (cfg, "ats",
                                                      "MIN_CONNECTIONS",
                                                      &tmp))
    n_min = tmp;
  else
    n_min = 4;

  /* Init network quotas */
  int quotas[GNUNET_ATS_NetworkTypeCount] = GNUNET_ATS_NetworkType;
  for (c = 0; c < GNUNET_ATS_NetworkTypeCount; c++)
  {
    mlp->quota_index[c] = quotas[c];
    static char * entry_in = NULL;
    static char * entry_out = NULL;
    unsigned long long quota_in = 0;
    unsigned long long quota_out = 0;

    switch (quotas[c]) {
      case GNUNET_ATS_NET_UNSPECIFIED:
        entry_out = "UNSPECIFIED_QUOTA_OUT";
        entry_in = "UNSPECIFIED_QUOTA_IN";
        break;
      case GNUNET_ATS_NET_LOOPBACK:
        entry_out = "LOOPBACK_QUOTA_OUT";
        entry_in = "LOOPBACK_QUOTA_IN";
        break;
      case GNUNET_ATS_NET_LAN:
        entry_out = "LAN_QUOTA_OUT";
        entry_in = "LAN_QUOTA_IN";
        break;
      case GNUNET_ATS_NET_WAN:
        entry_out = "WAN_QUOTA_OUT";
        entry_in = "WAN_QUOTA_IN";
        break;
      case GNUNET_ATS_NET_WLAN:
        entry_out = "WLAN_QUOTA_OUT";
        entry_in = "WLAN_QUOTA_IN";
        break;
      default:
        break;
    }

    if ((entry_in == NULL) || (entry_out == NULL))
      continue;

    if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string(cfg, "ats", entry_out, &quota_out_str))
    {
      if (0 == strcmp(quota_out_str, BIG_M_STRING) ||
          (GNUNET_SYSERR == GNUNET_STRINGS_fancy_size_to_bytes (quota_out_str, &quota_out)))
        quota_out = mlp->BIG_M;

      GNUNET_free (quota_out_str);
      quota_out_str = NULL;
    }
    else if (GNUNET_ATS_NET_UNSPECIFIED == quotas[c])
    {
      quota_out = mlp->BIG_M;
    }
    else
    {
      quota_out = mlp->BIG_M;
    }

    if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string(cfg, "ats", entry_in, &quota_in_str))
    {
      if (0 == strcmp(quota_in_str, BIG_M_STRING) ||
          (GNUNET_SYSERR == GNUNET_STRINGS_fancy_size_to_bytes (quota_in_str, &quota_in)))
        quota_in = mlp->BIG_M;

      GNUNET_free (quota_in_str);
      quota_in_str = NULL;
    }
    else if (GNUNET_ATS_NET_UNSPECIFIED == quotas[c])
    {
      quota_in = mlp->BIG_M;
    }
    else
    {
      quota_in = mlp->BIG_M;
    }

    /* Check if defined quota could make problem unsolvable */
    if (((n_min * b_min) > quota_out) && (GNUNET_ATS_NET_UNSPECIFIED != quotas[c]))
    {
      GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Inconsistent quota configuration value `%s': " 
		  "outbound quota (%u Bps) too small for combination of minimum connections and minimum bandwidth per peer (%u * %u Bps = %u)\n", entry_out, quota_out, n_min, b_min, n_min * b_min);

      GAS_mlp_done(mlp);
      mlp = NULL;
      return NULL;
    }

    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Found `%s' quota %llu and `%s' quota %llu\n",
                entry_out, quota_out, entry_in, quota_in);
    GNUNET_STATISTICS_update ((struct GNUNET_STATISTICS_Handle *) stats, entry_out, quota_out, GNUNET_NO);
    GNUNET_STATISTICS_update ((struct GNUNET_STATISTICS_Handle *) stats, entry_in, quota_in, GNUNET_NO);
    mlp->quota_out[c] = quota_out;
    mlp->quota_in[c] = quota_in;
  }

  /* Get minimum number of connections from configuration */
  if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_time (cfg, "ats",
                                                        "ATS_EXEC_INTERVAL",
                                                        &i_exec))
    mlp->exec_interval = i_exec;
  else
    mlp->exec_interval = GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 30);

  mlp->stats = (struct GNUNET_STATISTICS_Handle *) stats;
  mlp->max_iterations = max_iterations;
  mlp->max_exec_duration = max_duration;
  mlp->auto_solve = GNUNET_YES;

  /* Redirect GLPK output to GNUnet logging */
  glp_error_hook((void *) mlp, &mlp_term_hook);

  /* Init LP solving parameters */
  glp_init_smcp(&mlp->control_param_lp);

  mlp->control_param_lp.msg_lev = GLP_MSG_OFF;
#if VERBOSE_GLPK
  mlp->control_param_lp.msg_lev = GLP_MSG_ALL;
#endif

  mlp->control_param_lp.it_lim = max_iterations;
  mlp->control_param_lp.tm_lim = max_duration.rel_value;

  /* Init MLP solving parameters */
  glp_init_iocp(&mlp->control_param_mlp);

  mlp->control_param_mlp.msg_lev = GLP_MSG_OFF;
#if VERBOSE_GLPK
  mlp->control_param_mlp.msg_lev = GLP_MSG_ALL;
#endif
  mlp->control_param_mlp.tm_lim = max_duration.rel_value;

  mlp->last_execution = GNUNET_TIME_UNIT_FOREVER_ABS;

  mlp->co_D = D;
  mlp->co_R = R;
  mlp->co_U = U;
  mlp->b_min = b_min;
  mlp->n_min = n_min;
  mlp->m_q = GNUNET_ATS_QualityPropertiesCount;
  mlp->semaphore = GNUNET_NO;
  return mlp;
}