Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
Merge branch 'oldstyle_element_set'
authorFabien Chaix <chaix@ics.forth.gr>
Wed, 24 Feb 2016 12:05:57 +0000 (14:05 +0200)
committerFabien Chaix <chaix@ics.forth.gr>
Wed, 24 Feb 2016 12:05:57 +0000 (14:05 +0200)
Fixed corner cases with concurrency and concurrency_share>1
Fixed a bug in lmm_on_disabled_var()
Added more flexibility to maxmin_bench to stress better SURF maxmin

1  2 
src/include/surf/maxmin.h
src/surf/maxmin.cpp
src/surf/maxmin_private.hpp
src/surf/network_cm02.cpp
teshsuite/surf/maxmin_bench/maxmin_bench.c

Simple merge
@@@ -133,20 -150,18 +150,31 @@@ static XBT_INLINE void lmm_variable_rem
    for (i = 0; i < var->cnsts_number; i++) {
      elem = &var->cnsts[i];
      if(var->weight>0)
-       lmm_decrease_concurrency(elem->constraint);
 -      lmm_decrease_concurrency(elem);
 -    xbt_swag_remove(elem, &(elem->constraint->element_set));
++    lmm_decrease_concurrency(elem);
 +    xbt_swag_remove(elem, &(elem->constraint->enabled_element_set));
 +    xbt_swag_remove(elem, &(elem->constraint->disabled_element_set));
      xbt_swag_remove(elem, &(elem->constraint->active_element_set));
 -    nelements=xbt_swag_size(&(elem->constraint->element_set));
 +    nelements=xbt_swag_size(&(elem->constraint->enabled_element_set)) +
 +              xbt_swag_size(&(elem->constraint->disabled_element_set));
      if (!nelements)
        make_constraint_inactive(sys, elem->constraint);
--  //Check if we can enable new variables going through the constraints where var was.
      else
        lmm_on_disabled_var(sys,elem->constraint);
    }
--
++  
++  //Check if we can enable new variables going through the constraints where var was.
++  //Do it after removing all elements, so he first disabled variables get priority over those with smaller
++  //requirement
++  for (i = 0; i < var->cnsts_number; i++) {
++    elem = &var->cnsts[i];
++    if(xbt_swag_size(&(elem->constraint->disabled_element_set)))
++      lmm_on_disabled_var(sys,elem->constraint);  
++  }
++  
    var->cnsts_number = 0;
++
++  lmm_check_concurrency(sys);
++    
    XBT_OUT();
  }
  
@@@ -351,10 -370,10 +386,10 @@@ void lmm_shrink(lmm_system_t sys, lmm_c
     */
    lmm_update_modified_set(sys, cnst);
    //Useful in case var was already removed from the constraint
 -  lmm_update_modified_set(sys, var->cnsts[0].constraint); // will look up element_set of this constraint, and then each var in the element_set, and each var->cnsts[i].
 +  lmm_update_modified_set(sys, var->cnsts[0].constraint); // will look up enabled_element_set of this constraint, and then each var in the enabled_element_set, and each var->cnsts[i].
  
 -  if(xbt_swag_remove(elem, &(elem->constraint->element_set)) && var->weight>0)
 +  if(xbt_swag_remove(elem, &(elem->constraint->enabled_element_set)))
-     lmm_decrease_concurrency(elem->constraint);
+     lmm_decrease_concurrency(elem);
  
    xbt_swag_remove(elem, &(elem->constraint->active_element_set));
    elem->constraint = NULL;
@@@ -379,11 -398,11 +414,24 @@@ void lmm_expand(lmm_system_t sys, lmm_c
  {
    lmm_element_t elem = NULL;
    double weight;
--  int i;
++  int i,current_share;
++  
    
    sys->modified = 1;
  
--  if(var->weight>0 && lmm_concurrency_slack(cnst)==0){
++  //Check if this variable already has an active element in this constraint
++  //If it does, substract it from the required slack
++  current_share=0;
++  if(var->concurrency_share>1){
++    for( i=0; i<var->cnsts_number;i++){
++      if(var->cnsts[i].constraint==cnst && xbt_swag_belongs(&var->cnsts[i],&(var->cnsts[i].constraint->enabled_element_set)))
++      current_share+=lmm_element_concurrency(&(var->cnsts[i]));
++    }
++  }
++
++  //Check if we need to disable the variable 
++  if(var->weight>0 && var->concurrency_share-current_share>lmm_concurrency_slack(cnst))
++   {
      weight=var->weight;
      lmm_disable_var(sys,var);
      for (i = 0; i < var->cnsts_number; i++)
  
    
    if (var->weight){
 -    xbt_swag_insert_at_head(elem, &(elem->constraint->element_set));
 +    xbt_swag_insert_at_head(elem, &(elem->constraint->enabled_element_set));
-     lmm_increase_concurrency(elem->constraint);
+     lmm_increase_concurrency(elem);
    }
    else
 -    xbt_swag_insert_at_tail(elem, &(elem->constraint->element_set));
 +    xbt_swag_insert_at_tail(elem, &(elem->constraint->disabled_element_set));
  
    if(!sys->selective_update_active) {
      make_constraint_active(sys, cnst);
  void lmm_expand_add(lmm_system_t sys, lmm_constraint_t cnst,
                      lmm_variable_t var, double value)
  {
--  int i;
++  int i,j;
++  double weight;
    sys->modified = 1;
--
++  
    lmm_check_concurrency(sys);
  
++  //BEWARE: In case you have multiple elements in one constraint, this will always
++  //add value to the first element.
    for (i = 0; i < var->cnsts_number; i++)
      if (var->cnsts[i].constraint == cnst)
        break;
  
    if (i < var->cnsts_number) {
++    if (var->weight)
++      lmm_decrease_concurrency(&var->cnsts[i]);
++
      if (cnst->sharing_policy)
        var->cnsts[i].value += value;
      else
        var->cnsts[i].value = MAX(var->cnsts[i].value, value);
++
++    //We need to check that increasing value of the element does not cross the concurrency limit
++    if (var->weight){
++      if(lmm_concurrency_slack(cnst)<lmm_element_concurrency(&var->cnsts[i])){
++      weight=var->weight;
++      lmm_disable_var(sys,var);
++      for (j = 0; j < var->cnsts_number; j++)
++        lmm_on_disabled_var(sys,var->cnsts[j].constraint);
++      var->staged_weight=weight;
++      xbt_assert(!var->weight);
++      }
++      lmm_increase_concurrency(&var->cnsts[i]);
++    }
++    
      lmm_update_modified_set(sys, cnst);
    } else
      lmm_expand(sys, cnst, var, value);
@@@ -924,6 -906,6 +992,8 @@@ void lmm_solve(lmm_system_t sys
      lmm_print(sys);
    }
  
++  lmm_check_concurrency(sys);
++  
    xbt_free(saturated_constraint_set->data);
    xbt_free(saturated_constraint_set);
    xbt_free(cnst_light_tab);
@@@ -957,8 -939,11 +1027,6 @@@ void lmm_update_variable_bound(lmm_syst
  
  int lmm_concurrency_slack(lmm_constraint_t cnstr){
  
-   xbt_assert(xbt_swag_size(&(cnstr->enabled_element_set))==cnstr->concurrency_current,"concurrency_current is not up to date!");
 -  int slack;
 -  int concurrency=0;
 -  void* _elem;
 -  lmm_element_t elem;
--
    //FIXME MARTIN: Replace by infinite value std::numeric_limits<int>::(max)(), or something better within Simgrid?
    if(cnstr->concurrency_limit<0)
      return 666;
@@@ -1018,14 -1015,14 +1086,16 @@@ void lmm_enable_var(lmm_system_t sys, l
    xbt_swag_insert_at_head(var, &(sys->variable_set));
    for (i = 0; i < var->cnsts_number; i++) {
      elem = &var->cnsts[i];
 -    xbt_swag_remove(elem, &(elem->constraint->element_set));
 -    xbt_swag_insert_at_head(elem, &(elem->constraint->element_set));
 +    xbt_swag_remove(elem, &(elem->constraint->disabled_element_set));
 +    xbt_swag_insert_at_head(elem, &(elem->constraint->enabled_element_set));
-     lmm_increase_concurrency(elem->constraint);
+     lmm_increase_concurrency(elem);
    }
    if (var->cnsts_number)
      lmm_update_modified_set(sys, var->cnsts[0].constraint);
  
--  lmm_check_concurrency(sys);
++  //When used within lmm_on_disabled_var, we would get an assertion fail, because transiently there can be variables that are staged and could be activated.
++  //Anyway, caller functions all call lmm_check_concurrency() in the end. 
++  //  lmm_check_concurrency(sys);
  }
  
  void lmm_disable_var(lmm_system_t sys, lmm_variable_t var){
  void lmm_on_disabled_var(lmm_system_t sys, lmm_constraint_t cnstr){
  
    lmm_element_t elem;
++  lmm_element_t nextelem;
++  int numelem;
++  
    if(cnstr->concurrency_limit<0)
      return;
--  
-   int concurrency=cnstr->concurrency_current;
-   xbt_swag_foreach(elem, &(cnstr->disabled_element_set)) {
 -  int concurrency=0;
 -  xbt_swag_foreach(elem, &(cnstr->element_set)) {
 -
 -    //active variables are checked to see if we already reached the maximum (SHOULD NOT HAPPEN BECAUSE WE SHOULD HAVE JUST DEACTIVATED ONE)
 -    if (elem->variable->weight > 0){
 -      concurrency+=lmm_element_concurrency(elem);
 -      xbt_assert(elem->variable->staged_weight==0.0,"Staged weight should have been reset");
 -    } else if (elem->variable->staged_weight>0 )
++
++  numelem=xbt_swag_size(&(cnstr->disabled_element_set));
++  if(!numelem)
++    return;
++
++  elem= (lmm_element_t) xbt_swag_getFirst(&(cnstr->disabled_element_set));
++
++  //Cannot use xbt_swag_foreach, because lmm_enable_var will modify disabled_element_set.. within the loop
++  while(numelem-- && elem ){
++
++    nextelem = (lmm_element_t) xbt_swag_getNext(elem, cnstr->disabled_element_set.offset);      
 +
 +    if (elem->variable->staged_weight>0 )
        {
-   //Found a staged variable
-   //TODOLATER: Add random timing function to model reservation protocol fuzziness? Then how to make sure that staged variables will eventually be called?
-   if(lmm_can_enable_var(elem->variable)){
-     lmm_enable_var(sys,elem->variable);
-     concurrency++;
-   }        
+       //Found a staged variable
+       //TODOLATER: Add random timing function to model reservation protocol fuzziness? Then how to make sure that staged variables will eventually be called?
+       if(lmm_can_enable_var(elem->variable)){
+         lmm_enable_var(sys,elem->variable);
 -        concurrency+=lmm_element_concurrency(elem);
 -      }             
++      }        
        }
  
--    xbt_assert(concurrency<=cnstr->concurrency_limit,"Concurrency overflow!");
--    if(concurrency==cnstr->concurrency_limit)
++    xbt_assert(cnstr->concurrency_current<=cnstr->concurrency_limit,"Concurrency overflow!");
++    if(cnstr->concurrency_current==cnstr->concurrency_limit)
        break;
++
++    elem = nextelem;
    }
  
--  lmm_check_concurrency(sys);
++  //We could get an assertion fail, because transiently there can be variables that are staged and could be activated.
++  //And we need to go through all constraints of the disabled var before getting back a coherent state.
++  //Anyway, caller functions all call lmm_check_concurrency() in the end. 
++  //  lmm_check_concurrency(sys);
  
  }
  
@@@ -1113,8 -1114,8 +1198,8 @@@ void lmm_update_variable_weight(lmm_sys
    if (enabling_var){
      var->staged_weight = weight;
      minslack=lmm_cnstrs_min_concurrency_slack(var);
--    if(minslack==0){      
--      XBT_DEBUG("Staging var (instead of enabling) because min concurrency slack %i, with weight %f", minslack, weight);
++    if(minslack<var->concurrency_share){      
++      XBT_DEBUG("Staging var (instead of enabling) because min concurrency slack %i, with weight %f and concurrency share %i", minslack, weight, var->concurrency_share);
        return;
      }
      XBT_DEBUG("Enabling var with min concurrency slack %i", minslack);
@@@ -1232,10 -1236,10 +1317,10 @@@ static void lmm_remove_all_modified_set
    //To be clean, when visited counter has wrapped around, we force these var->visited values so that variables that were in the modified a long (long long) time ago are not wrongly skipped here, which would lead to very nasty bugs (i.e. not readibily reproducible, and requiring a lot of run time before happening).  
    if (++sys->visited_counter == 1) {
      /* the counter wrapped around, reset each variable->visited */
 -      void *_var;
 +  void *_var;
      xbt_swag_foreach(_var, &sys->variable_set)
        ((lmm_variable_t)_var)->visited = 0;
--  }
++  } 
    xbt_swag_reset(&sys->modified_constraint_set);
  }
  
@@@ -1268,34 -1275,30 +1353,58 @@@ double lmm_constraint_get_usage(lmm_con
  void lmm_check_concurrency(lmm_system_t sys){
    void* _cnst;
    void* _elem;
++  void* _var;
    lmm_element_t elem;
    lmm_constraint_t cnst;
++  lmm_variable_t var;
    int concurrency;
--
++  int i,belong_to_enabled,belong_to_disabled,belong_to_active;
++  
    //These checks are very expensive, so do them only if we want to debug SURF LMM
    if (XBT_LOG_ISENABLED(surf_maxmin, xbt_log_priority_debug)) {
    
      xbt_swag_foreach(_cnst, &(sys->constraint_set)) {
        cnst = (lmm_constraint_t) _cnst;
        concurrency=0;
-      
 -      if(cnst->concurrency_limit<0)
 -      continue;
 -      xbt_swag_foreach(_elem, &(cnst->element_set)) {
 +      xbt_swag_foreach(_elem, &(cnst->enabled_element_set)) {
-   elem = (lmm_element_t)_elem;
-   xbt_assert(elem->variable->weight > 0);
-     concurrency++;
+       elem = (lmm_element_t)_elem;
 -      if (elem->variable->weight > 0) 
 -        concurrency+=lmm_element_concurrency(elem);
 -      else {
 -        //We should have staged variables only if conccurency is reached in some constraint
 -        xbt_assert(cnst->concurrency_limit<0 || elem->variable->staged_weight==0 || lmm_cnstrs_min_concurrency_slack(elem->variable) < elem->variable->concurrency_share,"should not have staged variable!");
 -          }
++      xbt_assert(elem->variable->weight > 0);
++      concurrency+=lmm_element_concurrency(elem);
 +      }
++      
 +      xbt_swag_foreach(_elem, &(cnst->disabled_element_set)) {
 +  elem = (lmm_element_t)_elem;
-   //We should have staged variables only if conccurency is reached in some constraint
++  //We should have staged variables only if concurrency is reached in some constraint
 +  xbt_assert(cnst->concurrency_limit<0 || elem->variable->staged_weight==0 || lmm_cnstrs_min_concurrency_slack(elem->variable) < elem->variable->concurrency_share,"should not have staged variable!");
        }
 +      
        xbt_assert(cnst->concurrency_limit<0 || cnst->concurrency_limit >= concurrency,"concurrency check failed!");
        xbt_assert(cnst->concurrency_current == concurrency, "concurrency_current is out-of-date!");
-       xbt_assert(cnst->concurrency_current == xbt_swag_size(&(cnst->enabled_element_set)), "concurrency_current is out-of-date (2) !");
      }
  
++
++    //Check that for each variable, all corresponding elements are in the same state (i.e. same element sets)
++    xbt_swag_foreach(_var, &(sys->variable_set)) {
++      var= (lmm_variable_t) _var;
++
++      if(!var->cnsts_number)
++      continue;
++
++      elem = &var->cnsts[0];
++      belong_to_enabled=xbt_swag_belongs(elem,&(elem->constraint->enabled_element_set));
++      belong_to_disabled=xbt_swag_belongs(elem,&(elem->constraint->disabled_element_set));
++      belong_to_active=xbt_swag_belongs(elem,&(elem->constraint->active_element_set));
++
++      for (i = 1; i < var->cnsts_number; i++) {
++      elem = &var->cnsts[i];
++      xbt_assert(belong_to_enabled==xbt_swag_belongs(elem,&(elem->constraint->enabled_element_set)),
++                 "Variable inconsistency (1): enabled_element_set");
++      xbt_assert(belong_to_disabled==xbt_swag_belongs(elem,&(elem->constraint->disabled_element_set)),
++         "Variable inconsistency (2): disabled_element_set");
++      xbt_assert(belong_to_active==xbt_swag_belongs(elem,&(elem->constraint->active_element_set)),
++                 "Variable inconsistency (3): active_element_set");
++      }
++      
++    }
    }
  }
Simple merge
@@@ -418,7 -450,7 +418,9 @@@ Action *NetworkCm02Model::communicate(N
        link = static_cast<NetworkCm02Link*>(_link);
        lmm_expand(p_maxminSystem, link->getConstraint(), action->getVariable(), .05);
      }
--    lmm_variable_concurrency_share_set(action->getVariable(),2);
++    //Change concurrency_share here, if you want that cross-traffic is included in the SURF concurrency
++    //(You would also have to change lmm_element_concurrency())
++    //lmm_variable_concurrency_share_set(action->getVariable(),2);
    }
  
    xbt_dynar_free(&route);
@@@ -28,33 -28,44 +28,47 @@@ int int_random(int max
    return (int) (((max * 1.0) * rand()) / (RAND_MAX + 1.0));
  }
  
- void test(int nb_cnst, int nb_var, int nb_elem);
- void test(int nb_cnst, int nb_var, int nb_elem)
 -void test(int nb_cnst, int nb_var, int nb_elem, int pw_base_limit, int pw_max_limit, float rate_no_limit, int max_share);
 -void test(int nb_cnst, int nb_var, int nb_elem, int pw_base_limit, int pw_max_limit, float rate_no_limit, int max_share)
++void test(int nb_cnst, int nb_var, int nb_elem, int pw_base_limit, int pw_max_limit, float rate_no_limit, int max_share, int testmode);
++void test(int nb_cnst, int nb_var, int nb_elem, int pw_base_limit, int pw_max_limit, float rate_no_limit, int max_share, int testmode)
  {
    lmm_system_t Sys = NULL;
    lmm_constraint_t *cnst = xbt_new0(lmm_constraint_t, nb_cnst);
    lmm_variable_t *var = xbt_new0(lmm_variable_t, nb_var);
    int *used = xbt_new0(int, nb_cnst);
-   int i, j, k;
+   int i, j, k,l;
++  int concurrency_share;
+   
    Sys = lmm_system_new(1);
  
    for (i = 0; i < nb_cnst; i++) {
      cnst[i] = lmm_constraint_new(Sys, NULL, float_random(10.0));
+     if(rate_no_limit>float_random(1.0))
+       //Look at what happens when there is no concurrency limit 
+       l=-1;
+     else
+       //Badly logarithmically random concurrency limit in [2^pw_base_limit+1,2^pw_base_limit+2^pw_max_limit]
+       l=(1<<pw_base_limit)+(1<<int_random(pw_max_limit));
+  
+     lmm_constraint_concurrency_limit_set(cnst[i],l );
    }
+   
    for (i = 0; i < nb_var; i++) {
      var[i] = lmm_variable_new(Sys, NULL, 1.0, -1.0, nb_elem);
 -    lmm_variable_concurrency_share_set(var[i],1+int_random(max_share));
+     //Have a few variables with a concurrency share of two (e.g. cross-traffic in some cases)
++    concurrency_share=1+int_random(max_share);
++    lmm_variable_concurrency_share_set(var[i],concurrency_share);
+       
      for (j = 0; j < nb_cnst; j++)
        used[j] = 0;
      for (j = 0; j < nb_elem; j++) {
        k = int_random(nb_cnst);
--      if (used[k]) {
++      if (used[k]>=concurrency_share) {
          j--;
          continue;
        }
--      lmm_expand(Sys, cnst[k], var[i], float_random(1.0));
--      used[k] = 1;
++      lmm_expand(Sys, cnst[k], var[i], float_random(1.5));
++      lmm_expand_add(Sys, cnst[k], var[i], float_random(1.5));
++      used[k]++;
      }
    }
  
    lmm_solve(Sys);
    date = xbt_os_time() * 1000000 - date;
  
 -  printf("Max concurrency:\n");
 -  l=0;
 -  for (i = 0; i < nb_cnst; i++) {
 -    j=lmm_constraint_concurrency_maximum_get(cnst[i]);
 -    k=lmm_constraint_concurrency_limit_get(cnst[i]);
 -    xbt_assert(k<0 || j<=k);
 -    if(j>l)
 -      l=j;
 -    printf("(%i):%i/%i ",i,j,k);
 -    lmm_constraint_concurrency_maximum_reset(cnst[i]);
 -    xbt_assert(!lmm_constraint_concurrency_maximum_get(cnst[i]));
 -    if(i%10==9)
 -       printf("\n");    
 -  }
 -  printf("\nTotal maximum concurrency is %i\n",l);
++  if(testmode){
++    printf("Max concurrency:\n");
++    l=0;
++    for (i = 0; i < nb_cnst; i++) {
++      j=lmm_constraint_concurrency_maximum_get(cnst[i]);
++      k=lmm_constraint_concurrency_limit_get(cnst[i]);
++      xbt_assert(k<0 || j<=k);
++      if(j>l)
++      l=j;
++      printf("(%i):%i/%i ",i,j,k);
++      lmm_constraint_concurrency_maximum_reset(cnst[i]);
++      xbt_assert(!lmm_constraint_concurrency_maximum_get(cnst[i]));
++      if(i%10==9)
++      printf("\n");    
++    }
++    printf("\nTotal maximum concurrency is %i\n",l);
 -  lmm_print(Sys);
++    lmm_print(Sys);
++  }
+   
    for (i = 0; i < nb_var; i++)
      lmm_variable_free(Sys, var[i]);
    lmm_system_free(Sys);
    free(cnst);
    free(var);
    free(used);
+   
  }
  
++int TestClasses [][4]=
++  //Nbcnst Nbvar Baselimit Maxlimit 
++  {{  10  ,10    ,1        ,2 }, //small
++   {  100 ,100   ,3        ,6 }, //medium
++   {  2000,2000  ,5        ,8 }, //big
++   { 20000,20000 ,7        ,10}  //huge
++  }; 
++
  int main(int argc, char **argv)
  {
--  int nb_cnst = 2000;
--  int nb_var = 2000;
-   int nb_elem = 80;
 -  int nb_elem; 
 -  int pw_base_limit=5; 
 -  int pw_max_limit=8;
++  int nb_cnst, nb_var,nb_elem,pw_base_limit,pw_max_limit,max_share;
+   float rate_no_limit=0.2;
 -  int max_share=1<<(pw_base_limit/2+1);
++  float acc_date=0,acc_date2=0;
++  int testclass,testmode,testcount;
++  int i;
++  
++  if(argc<3) {
++    printf("Syntax: <small|medium|big|huge> <count> [test]\n");
++    return -1;
++  }
++
++  //what class?
++  if(!strcmp(argv[1],"small"))
++      testclass=0;
++  else if(!strcmp(argv[1],"medium"))
++      testclass=1;
++  else if(!strcmp(argv[1],"big"))
++      testclass=2;
++  else if(!strcmp(argv[1],"huge"))
++      testclass=3;
++  else {
++    printf("Unknown class \"%s\", aborting!\n",argv[1]);
++    return -2;
++  }
++
++  //How many times?
++  testcount=atoi(argv[2]);
+   
++  //Show me everything!
++  testmode=(argc>=4 && strcmp(argv[3],"test")==0);
++
++  if(testmode)
++    xbt_log_control_set("surf/maxmin.threshold:DEBUG surf.threshold:DEBUG");
++
++  nb_cnst= TestClasses[testclass][0];
++  nb_var= TestClasses[testclass][1];
++  pw_base_limit= TestClasses[testclass][2];
++  pw_max_limit= TestClasses[testclass][3];
++  max_share=2; //1<<(pw_base_limit/2+1);
++
+   //If you want to test concurrency, you need nb_elem >> 2^pw_base_limit:
+   nb_elem= (1<<pw_base_limit)+(1<<(8*pw_max_limit/10));
+   //Otherwise, just set it to a constant value (and set rate_no_limit to 1.0):
+   //nb_elem=200
 -  
++
    xbt_init(&argc, argv);
--  date = xbt_os_time() * 1000000;
-   test(nb_cnst, nb_var, nb_elem);
 -  test(nb_cnst, nb_var, nb_elem, pw_base_limit, pw_max_limit, rate_no_limit,max_share);    
--  printf("One shot execution time for a total of %d constraints, "
-          "%d variables with %d active constraint each : %g microsecondes \n",
 -         "%d variables with %d active constraint each : %g microseconds \n",
--         nb_cnst, nb_var, nb_elem, date);
++  
++  for(i=0;i<testcount;i++){
++    test(nb_cnst, nb_var, nb_elem, pw_base_limit, pw_max_limit, rate_no_limit,max_share,testmode);
++    acc_date+=date;
++    acc_date2+=date*date;
++  }
++
++  float mean_date= acc_date/(float)testcount;  
++  float stdev_date= sqrt(acc_date2/(float)testcount-mean_date*mean_date);
++    
++  printf("%ix One shot execution time for a total of %d constraints, "
++         "%d variables with %d active constraint each, concurrency in [%i,%i] and max concurrency share %i: %g +- %g  microseconds \n",
++       testcount,nb_cnst, nb_var, nb_elem, (1<<pw_base_limit), (1<<pw_base_limit)+(1<<pw_max_limit), max_share, mean_date, stdev_date);
    return 0;
  }