Commit 8137d742 authored by Mike Hibler's avatar Mike Hibler
Browse files

Merge remote branch 'central/master'

parents 61b01ae5 ca1b1604
......@@ -64,14 +64,12 @@ CXXFLAGS += -O3
CXXFLAGS += -DMELT -DEPSILON_TERMINATE -DCHILL -DNEIGHBOR_LENGTH \
-DLOCAL_DERIVATIVE -DALLOW_NEGATIVE_DELTA
# Bug/scoring fixes
CXXFLAGS += -DINTERSWITCH_LENGTH -DPNODE_SWITCH_LOAD -DFIX_SHARED_INTERFACES
CXXFLAGS += -DINTERSWITCH_LENGTH
# Various tweaks to the simulated annealing behavior
CXXFLAGS += -DFIND_PNODE_SEARCH -DNO_REVERT
# Keeps information about which pclasses are potential mappings for vnodes on a
# per-vnode basis, not a per-type basis
CXXFLAGS += -DPER_VNODE_TT
# Should be on by default, but not well tested enough
#CXXFLAGS += -DSMART_UNMAP
# Make sure that all emulated links that are assigned to a plink have the same
# endpoints
CXXFLAGS += -DFIX_PLINK_ENDPOINTS
......
/*
* EMULAB-COPYRIGHT
* Copyright (c) 2003-2009 University of Utah and the Flux Group.
* Copyright (c) 2003-2010 University of Utah and the Flux Group.
* All rights reserved.
*/
......@@ -20,9 +20,6 @@ static const char rcsid[] = "$Id: anneal.cc,v 1.46 2009-05-20 18:06:07 tarunp Ex
* Internal variables
*/
// These variables store the best solution.
//node_map absassignment; // assignment field of vnode
//assigned_map absassigned; // assigned field of vnode
//type_map abstypes; // type field of vnode
solution best_solution;
// Map of virtual node name to its vertex descriptor.
......@@ -97,106 +94,6 @@ inline bool accept(double change, double temperature) {
return 0;
}
#ifdef SMART_UNMAP
/*
* XXX - I pulled this code out of the anneal loop, and it needs to be fixed
* up (and get some arguments and a return type) before it will compile
*/
void smart_unmap() {
// XXX: Should probably randomize this
// XXX: Add support for not using PER_VNODE_TT
// XXX: Not very robust
freednode = true;
tt_entry tt = vnode_type_table[vn->name];
int size = tt.first;
pclass_vector *acceptable_types = tt.second;
// Find a node to kick out
bool foundnode = false;
int offi = RANDOM();
int index;
for (int i = 0; i < size; i++) {
index = (i + offi) % size;
if ((*acceptable_types)[index]->used_members.find(vn->type) ==
(*acceptable_types)[index]->used_members.end()) {
continue;
}
if ((*acceptable_types)[index]->used_members[vn->type]->size() == 0) {
continue;
}
foundnode = true;
break;
}
if (foundnode) {
assert((*acceptable_types)[index]->used_members[vn->type]->size());
tb_pclass::tb_pnodeset::iterator it =
(*acceptable_types)[index]->used_members[vn->type]->begin();
int j = RANDOM() %
(*acceptable_types)[index]->used_members[vn->type]->size();
while (j > 0) {
it++;
j--;
}
tb_vnode_set::iterator it2 = (*it)->assigned_nodes.begin();
int k = RANDOM() % (*it)->assigned_nodes.size();
while (k > 0) {
it2++;
k--;
}
tb_vnode *kickout = *it2;
assert(kickout->assigned);
vvertex toremove = vname2vertex[kickout->name];
newpnode = *it;
remove_node(toremove);
unassigned_nodes.push(vvertex_int_pair(toremove,
RANDOM()));
} else {
cerr << "Failed to find a replacement!" << endl;
}
#endif /* SMART_UNMAP */
#ifdef SMART_UNMAP
/*
* Part II of the smart_unmap code - again, needs to be fixed before it
* will compile.
*/
void smart_unmap_part2() {
#ifdef PER_VNODE_TT
tt_entry tt = vnode_type_table[vn->name];
#else
tt_entry tt = type_table[vn->type];
#endif
pclass_vector *acceptable_types = tt.second;
while (1) {
bool keepgoing = false;
if (get(vvertex_pmap,virtual_nodes[toremove])->fixed) {
keepgoing = true;
} else if (! get(vvertex_pmap,virtual_nodes[toremove])->assigned) {
keepgoing = true;
} else {
pvertex pv = get(vvertex_pmap,virtual_nodes[toremove])->assignment;
tb_pnode *pn = get(pvertex_pmap,pv);
int j;
for (j = 0; j < acceptable_types->size(); j++) {
if ((*acceptable_types)[j] == pn->my_class) {
break;
}
}
if (j == acceptable_types->size()) {
keepgoing = true;
}
}
if (!keepgoing) {
break;
}
}
#endif
// We put the temperature outside the function so that external stuff, like
// status_report in assign.cc, can see it.
double temp;
......@@ -208,15 +105,24 @@ void anneal(bool scoring_selftest, bool check_fixed_nodes,
{
cout << "Annealing." << endl;
double newscore = 0;
double bestscore = 0;
/*
* The score and number of violations at the start of the inner annealing
* loop
*/
double prev_score = 0;
int prev_violated = 0;
/*
*
*/
double new_score = 0;
double scorediff;
// The number of iterations that took place.
iters = 0;
iters_to_best = 0;
int accepts = 0;
double scorediff;
int nnodes = num_vertices(VG);
//int npnodes = num_vertices(PG);
......@@ -229,16 +135,13 @@ void anneal(bool scoring_selftest, bool check_fixed_nodes,
int naccepts = 20*(nnodes + PHYSICAL(npnodes));
pvertex oldpos;
bool oldassigned;
int bestviolated;
int num_fixed=0;
double meltedtemp;
temp = init_temp;
double deltatemp, deltaavg;
// Priority queue of unassigned virtual nodes. Basically a fancy way
// of randomly choosing a unassigned virtual node. When nodes become
// unassigned they are placed in the queue with a random priority.
vvertex_int_priority_queue unassigned_nodes;
// List of unassigned virtual nodes
slist<vvertex> unassigned_nodes;
#ifdef VERBOSE
cout << "Initialized to cycles="<<cycles<<" mintrans="
......@@ -381,16 +284,16 @@ void anneal(bool scoring_selftest, bool check_fixed_nodes,
/*
* Find out the starting temperature
*/
bestscore = get_score();
bestviolated = violated;
prev_score = get_score();
prev_violated = violated;
#ifdef VERBOSE
cout << "Problem started with score "<<bestscore<<" and "<< violated
cout << "Problem started with score "<<prev_score<<" and "<< violated
<< " violations." << endl;
#endif
absbest = bestscore;
absbestviolated = bestviolated;
best_score = prev_score;
best_violated = prev_violated;
/*
* Make a list of all nodes that are still unassigned
......@@ -400,14 +303,11 @@ void anneal(bool scoring_selftest, bool check_fixed_nodes,
for (;vit!=veit;++vit) {
tb_vnode *vn = get(vvertex_pmap,*vit);
if (vn->assigned) {
// XXX
// absassignment[*vit] = vn->assignment;
// abstypes[*vit] = vn->type;
best_solution.set_assignment(*vit,vn->assignment);
best_solution.set_vtype_assignment(*vit,vn->type);
} else {
best_solution.clear_assignment(*vit);
unassigned_nodes.push(vvertex_int_pair(*vit,RANDOM()));
unassigned_nodes.push_front(*vit);
}
}
......@@ -533,10 +433,10 @@ void anneal(bool scoring_selftest, bool check_fixed_nodes,
#endif
#ifdef VERBOSE
cout << "Temperature: " << temp << " AbsBest: " << absbest <<
" (" << absbestviolated << ")" << endl;
cout << "Temperature: " << temp << " Best: " << best_score <<
" (" << best_violated << ")" << endl;
#endif
/*
* Initialize this temperature step
*/
......@@ -544,9 +444,9 @@ void anneal(bool scoring_selftest, bool check_fixed_nodes,
accepts = 0;
nincreases = ndecreases = 0;
avgincrease = 0.0;
avgscore = bestscore;
avgscore = prev_score;
#ifdef CHILL
scores[0] = bestscore;
scores[0] = prev_score;
#endif
// Adjust the number of transitions we're going to do based on the number
......@@ -572,6 +472,9 @@ void anneal(bool scoring_selftest, bool check_fixed_nodes,
|| (!melting && (trans < mintrans && accepts < naccepts))) {
#endif
RDEBUG(cout << "ANNEALING: Loop starts with score " << get_score() <<
" violations " << violated << endl;)
#ifdef STATS
cout << "STATS temp:" << temp << " score:" << get_score() <<
" violated:" << violated << " trans:" << trans <<
......@@ -589,9 +492,18 @@ void anneal(bool scoring_selftest, bool check_fixed_nodes,
* If not, find some other random vnode, which we'll unmap then remap
*/
if (! unassigned_nodes.empty()) {
vv = unassigned_nodes.top().first;
// Pick a random node from the list of unassigned nodes
int choice = RANDOM() % unassigned_nodes.size();
slist<vvertex>::iterator uit = unassigned_nodes.begin();
for (int i = 0; i < choice; i++) { uit++; }
assert(uit != unassigned_nodes.end());
vv = *uit;
assert(!get(vvertex_pmap,vv)->assigned);
unassigned_nodes.pop();
unassigned_nodes.erase(uit);
RDEBUG(cout << "Using unassigned node " << choice << ": " <<
get(vvertex_pmap,vv)->name << " (" <<
unassigned_nodes.size() << " in queue)" << endl;)
} else {
int start = RANDOM()%nnodes;
int choice = start;
......@@ -617,6 +529,11 @@ void anneal(bool scoring_selftest, bool check_fixed_nodes,
*/
oldassigned = vn->assigned;
oldpos = vn->assignment;
if (oldassigned) {
RDEBUG(cout << " was assigned to " <<
get(pvertex_pmap,oldpos)->name << endl;)
}
/*
* Problem: If we free the chosen vnode now, we might just try remapping
......@@ -652,6 +569,7 @@ void anneal(bool scoring_selftest, bool check_fixed_nodes,
tb_pnode *newpnode = NULL;
if ((use_connected_pnode_find != 0)
&& ((RANDOM() % 1000) < (use_connected_pnode_find * 1000))) {
RDEBUG(cout << " using find_pnode_connected" << endl;)
newpnode = find_pnode_connected(vv,vn);
}
......@@ -660,6 +578,7 @@ void anneal(bool scoring_selftest, bool check_fixed_nodes,
* fall back on the regular algorithm to find a pnode
*/
if (newpnode == NULL) {
RDEBUG(cout << " using find_pnode" << endl;)
newpnode = find_pnode(vn);
}
......@@ -678,9 +597,8 @@ void anneal(bool scoring_selftest, bool check_fixed_nodes,
* vnode so that we can make progress - otherwise, we could get stuck
*/
if (newpnode == NULL) {
#ifndef SMART_UNMAP
// Push this node back onto the unassigned map
unassigned_nodes.push(vvertex_int_pair(vv,RANDOM()));
unassigned_nodes.push_front(vv);
int start = RANDOM()%nnodes;
int toremove = start;
while (get(vvertex_pmap,virtual_nodes[toremove])->fixed ||
......@@ -688,33 +606,31 @@ void anneal(bool scoring_selftest, bool check_fixed_nodes,
toremove = (toremove +1) % nnodes;
if (toremove == start) {
toremove = -1;
RDEBUG(cout << "Not removing a node" << endl;)
break;
}
}
if (toremove >= 0) {
RDEBUG(cout << "removing: freeing up nodes" << endl;)
remove_node(virtual_nodes[toremove]);
unassigned_nodes.push(vvertex_int_pair(virtual_nodes[toremove], RANDOM()));
}
}
if (toremove >= 0) {
RDEBUG(cout << "removing: freeing up node " <<
get(vvertex_pmap,virtual_nodes[toremove])->name << endl;)
remove_node(virtual_nodes[toremove]);
unassigned_nodes.push_front(virtual_nodes[toremove]);
}
/*
* Start again with another vnode - which will probably be the same one,
* since we just marked it as unmapped. But now, there will be at least one
* free pnode
*/
continue;
#else /* SMART_UNMAP */
// XXX: This code is broken for now, which is okay, because we weren't
// using it
smart_unmap();
smart_unmap_part2();
#endif
/*
* Start again with another vnode - which will probably be the same one,
* since we just marked it as unmapped. But now, there will be at least one
* free pnode
*/
RDEBUG(cout << "Failed to find a possible mapping; try again..." << endl;)
continue;
}
/*
* Okay, we've got pnode to map this vnode to - let's do it
*/
if (newpnode != NULL) {
RDEBUG(cout << "MOVE: " << vn->name << " to " << newpnode->name << " " << endl;)
newpos = pnode2vertex[newpnode];
if (scoring_selftest) {
// Run a little test here - see if the score we get by adding
......@@ -730,7 +646,7 @@ void anneal(bool scoring_selftest, bool check_fixed_nodes,
}
if ((oldscore != get_score()) || (oldviolated != violated)) {
cerr << "Scoring problem adding a mapping - oldscore was " <<
oldscore << " newscore is " << newscore << " tempscore was "
oldscore << " current score is " << get_score() << " tempscore was "
<< tempscore << endl;
cerr << "oldviolated was " << oldviolated << " newviolated is "
<< violated << " tempviolated was " << tempviolated << endl;
......@@ -747,13 +663,11 @@ void anneal(bool scoring_selftest, bool check_fixed_nodes,
* unassigned, and we go back and try with another
*/
if (add_node(vv,newpos,false,false,false) != 0) {
unassigned_nodes.push(vvertex_int_pair(vv,RANDOM()));
unassigned_nodes.push_front(vv);
RDEBUG(cout << "failed" << endl;)
continue;
}
} else { // pnode != NULL
#ifdef SMART_UNMAP
unassigned_nodes.push(vvertex_int_pair(vv,RANDOM()));
#endif
if (freednode) {
continue;
}
......@@ -762,11 +676,11 @@ void anneal(bool scoring_selftest, bool check_fixed_nodes,
/*
* Okay, now that we've mapped some new node, let's check the scoring
*/
newscore = get_score();
assert(newscore >= 0);
new_score = get_score();
assert(new_score >= 0);
// Negative means bad
scorediff = bestscore - newscore;
scorediff = prev_score - new_score;
// This looks funny, because < 0 means worse, which means an increase in
// score
if (scorediff < 0) {
......@@ -790,14 +704,14 @@ void anneal(bool scoring_selftest, bool check_fixed_nodes,
#ifdef NO_VIOLATIONS
// Here, we don't consider violations at all, just whether the regular
// simulated annealing accept conditions
if (newscore < bestscore) {
if (new_score < prev_score) {
accepttrans = true;
RDEBUG(cout << "accept: better (" << newscore << "," << bestscore
RDEBUG(cout << "accept: better (" << new_score << "," << prev_score
<< ")" << endl;)
} else if (accept(scorediff,temp)) {
accepttrans = true;
RDEBUG(cout << "accept: metropolis (" << newscore << ","
<< bestscore << "," << expf(scorediff/(temp*sensitivity))
RDEBUG(cout << "accept: metropolis (" << new_score << ","
<< prev_score << "," << expf(scorediff/(temp*sensitivity))
<< ")" << endl;)
}
#else
......@@ -818,21 +732,24 @@ void anneal(bool scoring_selftest, bool check_fixed_nodes,
* progress. This prevents the cooling schedule from converging for
* much, much longer than it should really take.
*/
if ((violated == bestviolated) && (newscore < bestscore)) {
RDEBUG(cout << "CRITERIA: v=" << violated << " bv=" <<
prev_violated << " ns=" << new_score << " ps=" <<
prev_score << " sd=" << scorediff << " t=" << temp << endl;)
if ((violated == prev_violated) && (new_score < prev_score)) {
accepttrans = true;
RDEBUG(cout << "accept: better (" << newscore << "," << bestscore
RDEBUG(cout << "accept: better (" << new_score << "," << prev_score
<< ")" << endl;)
} else if (violated < bestviolated) {
} else if (violated < prev_violated) {
accepttrans = true;
RDEBUG(cout << "accept: better (violations) (" << newscore << ","
<< bestscore << "," << violated << "," << bestviolated
RDEBUG(cout << "accept: better (violations) (" << new_score << ","
<< prev_score << "," << violated << "," << prev_violated
<< ")" << endl;
cout << "Violations: (new) " << violated << endl;
cout << vinfo;)
} else if (accept(scorediff,temp)) {
accepttrans = true;
RDEBUG(cout << "accept: metropolis (" << newscore << ","
<< bestscore << "," << expf(scorediff/(temp*sensitivity))
RDEBUG(cout << "accept: metropolis (" << new_score << ","
<< prev_score << "," << scorediff << "," << temp
<< ")" << endl;)
}
#else // no SPECIAL_VIOLATION_TREATMENT
......@@ -847,8 +764,8 @@ void anneal(bool scoring_selftest, bool check_fixed_nodes,
* adding a violation results in a _lower_ score than a solution with
* fewer violations.
*/
double adjusted_new_score = newscore + violated * VIOLATION_SCORE;
double adjusted_old_score = bestscore + bestviolated * VIOLATION_SCORE;
double adjusted_new_score = new_score + violated * VIOLATION_SCORE;
double adjusted_old_score = prev_score + prev_violated * VIOLATION_SCORE;
if (adjusted_new_score < adjusted_old_score) {
accepttrans = true;
......@@ -865,21 +782,22 @@ void anneal(bool scoring_selftest, bool check_fixed_nodes,
* Okay, we've decided to accep this transition - do some bookkeeping
*/
if (accepttrans) {
bestscore = newscore;
bestviolated = violated;
// Accept change
prev_score = new_score;
prev_violated = violated;
#ifdef GNUPLOT_OUTPUT
fprintf(tempout,"%f\n",temp);
fprintf(scoresout,"%f\n",newscore);
fprintf(scoresout,"%f\n",new_score);
fprintf(deltaout,"%f\n",-scorediff);
#endif // GNUPLOT_OUTPUT
avgscore += newscore;
avgscore += new_score;
accepts++;
#ifdef CHILL
if (!melting) {
scores[accepts] = newscore;
scores[accepts] = new_score;
}
#endif // CHILL
......@@ -888,11 +806,11 @@ void anneal(bool scoring_selftest, bool check_fixed_nodes,
* further bookkeeping - copy it into the structures for our best solution
*/
#ifdef NO_VIOLATIONS
if (newscore < absbest) {
if (new_score < best_score) {
#else // NO_VIOLATIONS
if ((violated < absbestviolated) ||
((violated == absbestviolated) &&
(newscore < absbest))) {
if ((violated < best_violated) ||
((violated == best_violated) &&
(new_score < best_score))) {
#endif // NO_VIOLATIONS
#ifdef SCORE_DEBUG
......@@ -907,9 +825,6 @@ void anneal(bool scoring_selftest, bool check_fixed_nodes,
} else {
best_solution.clear_assignment(*vit);
}
//absassignment[*vit] = get(vvertex_pmap,*vit)->assignment;
//absassigned[*vit] = get(vvertex_pmap,*vit)->assigned;
//abstypes[*vit] = get(vvertex_pmap,*vit)->type;
}
vedge_iterator edge_it, edge_it_end;
......@@ -923,21 +838,22 @@ void anneal(bool scoring_selftest, bool check_fixed_nodes,
}
}
absbest = newscore;
absbestviolated = violated;
best_score = new_score;
best_violated = violated;
iters_to_best = iters;
#ifdef SCORE_DEBUG
cerr << "New best recorded" << endl;
#endif
}
// Accept change
} else { // !acceptrans
// Reject change, go back to the state we were in before
RDEBUG(cout << "removing: rejected change" << endl;)
remove_node(vv);
if (oldassigned) {
add_node(vv,oldpos,false,false,false);
}
} else {
unassigned_nodes.push_front(vv);
}
}
/*
......@@ -1127,7 +1043,7 @@ NOTQUITEDONE:
(deltaavg > 0) && ((temp / initialavg) * (deltaavg/ deltatemp) < epsilon)) {
#endif
#ifdef FINISH_HILLCLIMB
if (!finishedonce && ((absbestviolated <= violated) && (absbest < bestscore))) {
if (!finishedonce && ((best_violated <= violated) && (best_score < prev_score))) {
// We don't actually stop, we just go do a hill-climb (basically) at the best
// one we previously found
finishedonce = true;
......@@ -1196,11 +1112,11 @@ NOTQUITEDONE:
* it either in violations or in score.
*/
#ifndef NO_REVERT
if (REVERT_VIOLATIONS && (absbestviolated < violated)) {
if (REVERT_VIOLATIONS && (best_violated < violated)) {
cout << "Reverting: REVERT_VIOLATIONS" << endl;
revert = true;
}
if (absbest < bestscore) {
if (best_score < prev_score) {
cout << "Reverting: best score" << endl;
revert = true;
}
......@@ -1301,6 +1217,7 @@ NOTQUITEDONE:
* Okay, now that we've jumped through enough hoops, we can actually
* do the scoring
*/
mark_vlink_assigned(vlink);
score_link_info(*vedge_it, src_pnode, dst_pnode, src_vnode, dst_vnode);
} else {
/*
......@@ -1309,9 +1226,9 @@ NOTQUITEDONE:
* mapped, then we have to make sure the score reflects that.
*/
if (!dst_vnode->assigned || !src_vnode->assigned) {
vlink->link_info.type_used = tb_link_info::LINK_UNMAPPED;
} else {
mark_vlink_unassigned(vlink);
if (!vlink->no_connection) {
mark_vlink_unassigned(vlink);
}
}
}
}
......
/*
* EMULAB-COPYRIGHT
* Copyright (c) 2003-2006 University of Utah and the Flux Group.
* Copyright (c) 2003-2010 University of Utah and the Flux Group.
* All rights reserved.
*/
......@@ -84,8 +84,8 @@ extern float temp_rate;
extern pclass_types type_table;
extern pclass_list pclasses;
extern pnode_pvertex_map pnode2vertex;
extern double absbest;
extern int absbestviolated, iters, iters_to_best;
extern double best_score;
extern int best_violated, iters, iters_to_best;
extern bool allow_overload;
#ifdef PER_VNODE_TT
......
/*
* EMULAB-COPYRIGHT
* Copyright (c) 2008 University of Utah and the Flux Group.
* Copyright (c) 2008-2010 University of Utah and the Flux Group.
* All rights reserved.
*/
......
/*
* EMULAB-COPYRIGHT
* Copyright (c) 2008 University of Utah and the Flux Group.
* Copyright (c) 2008-2010 University of Utah and the Flux Group.
* All rights reserved.
*/
......