Commit 2e2dc874 authored by Robert Ricci's avatar Robert Ricci

Some work on cleaning up assign - in genernal, I've tried to split

some independant functionality off into new files, and reduce its
use of globals, which can be very confusing to follow.

I didn't get as far as I had hoped, but it's a good start.
parent ffe16b88
......@@ -13,7 +13,7 @@ all: assign
include $(TESTBED_SRCDIR)/GNUmakerules
OBJS=parse_top.o parse_ptop.o assign.o pclass.o vclass.o config.o score.o \
parser.o
parser.o solution.o anneal.o
LIBS+= -lm
LDFLAGS+= -pipe -O3
CXXFLAGS = -pipe -I/usr/local/include -ftemplate-depth-30
......
This diff is collapsed.
/*
* EMULAB-COPYRIGHT
* Copyright (c) 2003 University of Utah and the Flux Group.
* All rights reserved.
*/
/*
* Contains the actual functions to do simulated annealing
*/
#ifndef __ANNEAL_H
#define __ANNEAL_H
#include "port.h"
#include <boost/graph/adjacency_list.hpp>
using namespace boost;
#include <rope>
#include <queue>
#include <iostream>
#include <math.h>
#include "common.h"
#include "delay.h"
#include "physical.h"
#include "virtual.h"
#include "vclass.h"
#include "maps.h"
#include "score.h"
#include "pclass.h"
// Some defaults for #defines
#ifndef NO_REVERT
#define NO_REVERT 0
#endif
#ifndef REVERT_VIOLATIONS
#define REVERT_VIOLATIONS 1
#endif
#ifndef REVERT_LAST
#define REVERT_LAST 0
#endif
#ifdef PHYS_CHAIN_LEN
#define PHYSICAL(x) x
#else
#define PHYSICAL(x) 0
#endif
/*
* Information returned by the annealing process - note that this does not
* include the solution, which is still global for now.
*/
struct annealing_results {
int violated; /* Number of violations - XXX make vinfo non-global too */
};
/*
* Globals - XXX made non-global!
*/
/* From assign.cc */
extern pclass_types type_table;
extern pclass_list pclasses;
extern pnode_pvertex_map pnode2vertex;
extern double absbest;
extern int absbestviolated, iters, iters_to_best;
#ifdef PER_VNODE_TT
extern pclass_types vnode_type_table;
#endif
/* Decides based on the temperature if a new score should be accepted or not */
inline int accept(double change, double temperature);
/* Find a pnode that can satisfy the give vnode */
tb_pnode *find_pnode(tb_vnode *vn);
/* The big guy! */
void anneal();
#endif
This diff is collapsed.
......@@ -200,8 +200,10 @@ Overview of the Code
CC Files:
assign.cc - Contains the simulated annealing loop and all
initialization code, including main().
assign.cc - Contains all initialization code, including main().
anneal.cc - Contains the simulated annealing loop and related
functions.
score.cc - Contains init_score, add_node, remove_node and all
associated helper routines.
......@@ -218,6 +220,9 @@ the pclasses, and the code to maintain the pclasses.
vclass.cc - Contains the code to setup vclasses and calculate score
deltas when nodes are mapped and unmapped..
solution.cc - Contains the code to print out solutions and other
graphs.
Header Files:
common.h - Contains all the parameters including all the score
......
......@@ -151,10 +151,22 @@ typedef slist<crope> name_slist;
*/
typedef hash_map<crope,int> name_count_map;
/*
* A hash function for pointers
*/
template <class T> struct hashptr {
size_t operator()(T const &A) const {
return (size_t) A;
}
};
/*
* Misc. debugging stuff
*/
#ifdef ROB_DEBUG
#define RDEBUG(a) a
#else
#define RDEBUG(a)
#endif
#endif
......@@ -56,18 +56,8 @@ int parse_ptop(tb_pgraph &PG, tb_sgraph &SG, istream& i)
crope name = parsed_line[1];
bool isswitch = false;
pvertex pv = add_vertex(PG);
tb_pnode *p = new tb_pnode();
tb_pnode *p = new tb_pnode(name);
put(pvertex_pmap,pv,p);
p->name = name;
p->typed = false;
p->max_load = 0;
p->current_load = 0;
p->pnodes_used = 0;
p->total_interfaces = 0;
#ifdef TRIVIAL_LINK_BW
p->trivial_bw = 0;
p->trivial_bw_used = 0;
#endif
unsigned int i;
for (i = 2;
......@@ -199,24 +189,17 @@ int parse_ptop(tb_pgraph &PG, tb_sgraph &SG, istream& i)
for (int cur = 0;cur<num;++cur) {
pedge pe = (add_edge(srcv,dstv,PG)).first;
tb_plink *pl = new tb_plink();
tb_plink *pl = new tb_plink(name,tb_plink::PLINK_NORMAL,srcmac,dstmac);
put(pedge_pmap,pe,pl);
pl->delay_info.bandwidth = ibw;
pl->delay_info.delay = idelay;
pl->delay_info.loss = gloss;
pl->bw_used = 0;
pl->name = name;
pl->emulated = 0;
pl->nonemulated = 0;
#ifdef FIX_PLINK_ENDPOINTS
pl->fixends = fixends;
#endif
#ifdef PENALIZE_BANDWIDTH
pl->penalty = penalty;
#endif
pl->type = tb_plink::PLINK_NORMAL;
pl->srcmac = srcmac;
pl->dstmac = dstmac;
if (ISSWITCH(srcnode) && ISSWITCH(dstnode)) {
if (cur != 0) {
cout <<
......
......@@ -60,12 +60,6 @@ struct hashlinkinfo {
// mapping between links that preserves bw, and destination.
int pclass_equiv(tb_pgraph &PG, tb_pnode *a,tb_pnode *b)
{
// We disable pclasses by simply never considering any two nodes to be
// equivalent
if (!use_pclasses) {
return 0;
}
typedef hash_multiset<link_info,hashlinkinfo> link_set;
// check type information
......@@ -127,7 +121,7 @@ int pclass_equiv(tb_pgraph &PG, tb_pnode *a,tb_pnode *b)
list of all equivalence classes) and type_table (and table of
physical type to list of classes that can satisfy that type) are
set by this routine. */
int generate_pclasses(tb_pgraph &PG) {
int generate_pclasses(tb_pgraph &PG, bool pclass_for_each_pnode) {
typedef hash_map<tb_pclass*,tb_pnode*,hashptr<tb_pclass*> > pclass_pnode_map;
typedef hash_map<crope,pclass_list*> name_pclass_list_map;
......@@ -138,20 +132,26 @@ int generate_pclasses(tb_pgraph &PG) {
tie(vit,vendit) = vertices(PG);
for (;vit != vendit;++vit) {
cur = *vit;
tb_pclass *curclass;
bool found_class = 0;
tb_pnode *curP = get(pvertex_pmap,cur);
pclass_pnode_map::iterator dit;
for (dit=canonical_members.begin();dit!=canonical_members.end();
++dit) {
curclass=(*dit).first;
if (pclass_equiv(PG,curP,(*dit).second)) {
// found the right class
found_class=1;
curclass->add_member(curP);
break;
}
tb_pclass *curclass;
// If we're putting each pnode in its own pclass, don't bother to find
// existing pclasses that it matches
if (!pclass_for_each_pnode) {
pclass_pnode_map::iterator dit;
for (dit=canonical_members.begin();dit!=canonical_members.end();
++dit) {
curclass=(*dit).first;
if (pclass_equiv(PG,curP,(*dit).second)) {
// found the right class
found_class=1;
curclass->add_member(curP);
break;
}
}
}
if (found_class == 0) {
// new class
tb_pclass *n = new tb_pclass;
......
......@@ -62,7 +62,7 @@ public:
class tb_pclass {
public:
tb_pclass() : size(0), used(0), refcount(0) {;}
tb_pclass() : name(), size(0), used(0), refcount(0) {;}
typedef hash_map<crope,tb_pnodelist*> pclass_members_map;
typedef hash_set<tb_pnode*,hashptr<tb_pnode*> > tb_pnodeset;
......@@ -108,7 +108,11 @@ typedef hash_map<crope,tt_entry> pclass_types;
#define PCLASS_FDS_WEIGHT 2
/* routines defined in pclass.cc */
int generate_pclasses(tb_pgraph &PG);// sets pclasses and type_table globals
// Sets pclasses and type_table globals -
// Takes two arguments - a physical graph, and a flag indicating whether or not
// each physical node should get its own pclass (effectively disabling
// pclasses)
int generate_pclasses(tb_pgraph &PG, bool pclass_for_each_pnode);
/* The following two routines sets and remove mappings in pclass
datastructures */
......
......@@ -8,16 +8,19 @@
#define __PHYSICAL_H
#include "common.h"
// Icky, but I can't include virtual.h here
class tb_vnode;
typedef hash_set<tb_vnode*,hashptr<tb_vnode*> > tb_vnode_set;
// Class forward declarations - defined below
class tb_pclass;
class tb_pnode;
class tb_switch;
class tb_plink;
class tb_slink;
// typedefs
typedef property<vertex_data_t,tb_pnode*> PNodeProperty;
typedef property<edge_data_t,tb_plink*> PEdgeProperty;
typedef property<vertex_data_t,tb_switch*> SNodeProperty;
......@@ -57,6 +60,8 @@ typedef hash_map<svertex,switch_dist_map*>switch_dist_map_map;
typedef list<pedge> pedge_path;
typedef list<pvertex> pvertex_list;
// Globals, declared in assign.cc
extern tb_pgraph_vertex_pmap pvertex_pmap;
extern tb_pgraph_edge_pmap pedge_pmap;
extern tb_sgraph_vertex_pmap svertex_pmap;
......@@ -64,8 +69,49 @@ extern tb_sgraph_edge_pmap sedge_pmap;
class tb_pnode {
public:
tb_pnode() {;}
tb_pnode() { tb_pnode("(unnamed)"); }
tb_pnode(crope _name) : types(), features(), name(_name), typed(false),
max_load(0), current_load(0), switches(),
sgraph_switch(), switch_used_links(0),
total_interfaces(0), used_interfaces(0),
total_bandwidth(0), my_class(NULL), assigned_nodes(),
trivial_bw(0), trivial_bw_used(0) {;}
typedef hash_map<crope,int> types_map;
typedef hash_map<crope,double> features_map;
// contains max nodes for each type
types_map types;
// contains cost of each feature
features_map features;
crope name; // name of the node
bool typed; // has it been typed
crope current_type; // type the node is currently being used as
int max_load; // maxmium load for current type
int current_load; // how many vnodes are assigned to this pnode
pvertex_set switches; // what switches the node is attached to
svertex sgraph_switch; // only for switches, the corresponding
// sgraph switch.
int switch_used_links; // only for switches, how many links are
// in use. Switch is in use whenever > 0
int total_interfaces; // total number of links leaving the node
int used_interfaces; // number of links that are currently in use
int total_bandwidth; // total bandwidth of all this nodes' links
tb_pclass *my_class; // the pclass this node belongs to
tb_vnode_set assigned_nodes; // the set of vnodes currently assigned
int trivial_bw; // the maximum amount of trivial bandwidth
// available
int trivial_bw_used; // the amount of bandwidth currently used by
// trivial links
// Output operator for debugging
friend ostream &operator<<(ostream &o, const tb_pnode& node)
{
o << "tb_pnode: " << node.name << " (" << &node << ")" << endl;
......@@ -85,49 +131,11 @@ public:
o << " " << get(pvertex_pmap,*it)->name;
}
o << endl;
o << " pnodes_used="<< node.pnodes_used << " sgraph_switch=" <<
node.sgraph_switch << " my_class=" << node.my_class << endl;
o << " sgraph_switch=" << node.sgraph_switch
<< " my_class=" << node.my_class << endl;
return o;
}
typedef hash_map<crope,int> types_map;
typedef hash_map<crope,double> features_map;
// contains max nodes for each type
types_map types;
// contains cost of each feature
features_map features;
crope current_type;
bool typed; // has it been typed
int max_load; // maxmium load for current type
int current_load; // how many vnodes are assigned to this pnode
crope name;
pvertex_set switches; // what switches the node is attached to
int pnodes_used; // for switch nodes
svertex sgraph_switch; // only for switches, the corresponding
// sgraph switch.
int switch_used_links; // only for switches, how many links are
// in use. Switch is in use whenever > 0
int total_interfaces;
#ifdef PENALIZE_UNUSED_INTERFACES
int used_interfaces;
#endif
#ifdef PER_VNODE_TT
int total_bandwidth;
#endif
tb_pclass *my_class;
#ifdef SMART_UNMAP
tb_vnode_set assigned_nodes;
#endif
#ifdef TRIVIAL_LINK_BW
int trivial_bw;
int trivial_bw_used;
#endif
};
class tb_switch {
......@@ -143,7 +151,6 @@ public:
pvertex mate; // match in PG
};
#ifdef FIX_PLINK_ENDPOINTS
// Hasher for pairs
template <class T> struct pairhash {
size_t operator()(pair<T,T> const &A) const {
......@@ -154,16 +161,36 @@ template <class T> struct pairhash {
typedef pair<crope,crope> nodepair;
typedef hash_map<nodepair,int,pairhash<crope> > nodepair_count_map;
#endif
class tb_plink {
public:
#ifdef FIX_PLINK_ENDPOINTS
tb_plink():current_count(0) {;}
#else
tb_plink() {;}
#endif
typedef enum {PLINK_NORMAL,PLINK_INTERSWITCH,PLINK_LAN} plinkType;
tb_plink(crope _name, plinkType _type, crope _srcmac, crope _dstmac)
: name(_name), srcmac(_srcmac), dstmac(_dstmac), type(_type),
delay_info(), bw_used(0), emulated(0), nonemulated(0),
penalty(0.0), fixends(false), current_endpoints(), current_count(0),
vedge_counts() {;}
crope name; // the name
crope srcmac,dstmac; // source and destination MAC addresses.
plinkType type; // type of the link
tb_delay_info delay_info; // the delay characteristics of this link
int bw_used; // how much is used
int emulated; // number of emulated vlinks
int nonemulated; // number of nonemulated vlinks
float penalty; // penaly for bandwidth used
bool fixends; // if using as a emulated link, fix endpoints
nodepair current_endpoints; // pnodes at the endpoints of the vlink using
// this plink
int current_count; // number of mapped vlinks that share these
// pnode endpoints
nodepair_count_map vedge_counts; // list, and count, of all pairs of pnode
// endpoints sharing this link
friend ostream &operator<<(ostream &o, const tb_plink& link)
{
o << "tb_plink: " << link.name << " (" << &link << ")" << endl;
......@@ -186,26 +213,6 @@ public:
o << link.delay_info;
return o;
}
typedef enum {PLINK_NORMAL,PLINK_INTERSWITCH,PLINK_LAN} plinkType;
plinkType type;
tb_delay_info delay_info; // the delay characteristics of this link
int bw_used; // how much is used
crope srcmac,dstmac; // source and destination MAC addresses.
crope name; // The name
int emulated; // number of emulated vlinks
int nonemulated; // number of nonemulated vlinks
bool interswitch; // is this an interswitch link
#ifdef PENALIZE_BANDWIDTH
float penalty;
#endif
#ifdef FIX_PLINK_ENDPOINTS
bool fixends; // If using as a emulated link, fix endpoints
nodepair_count_map vedge_counts;
nodepair current_endpoints;
int current_count;
#endif
};
class tb_slink {
......@@ -223,4 +230,11 @@ public:
int parse_ptop(tb_pgraph &PG, tb_sgraph &SG, istream& i);
/*
* Globals
*/
/* The physical graph, defined in assign.cc */
extern tb_pgraph PG;
#endif
......@@ -36,7 +36,7 @@ using namespace boost;
extern switch_pred_map_map switch_preds;
extern bool use_pclasses;
extern bool disable_pclasses;
double score; // The score of the current mapping
int violated; // How many times the restrictions
......@@ -94,11 +94,6 @@ void init_score()
SDEBUG(cerr << "SCORE: Initializing" << endl);
score=0;
violated=0;
vinfo.unassigned = vinfo.pnode_load = 0;
vinfo.no_connection = vinfo.link_users = vinfo.bandwidth = 0;
#ifdef FIX_PLINK_ENDPOINTS
vinfo.incorrect_endpoints = 0;
#endif
vvertex_iterator vvertex_it,end_vvertex_it;
tie(vvertex_it,end_vvertex_it) = vertices(VG);
......@@ -118,6 +113,7 @@ void init_score()
}
pvertex_iterator pvertex_it,end_pvertex_it;
tie(pvertex_it,end_pvertex_it) = vertices(PG);
/*
for (;pvertex_it!=end_pvertex_it;++pvertex_it) {
tb_pnode *pn=get(pvertex_pmap,*pvertex_it);
pn->typed=false;
......@@ -125,6 +121,7 @@ void init_score()
pn->pnodes_used=0;
pn->switch_used_links=0;
}
*/
pedge_iterator pedge_it,end_pedge_it;
tie(pedge_it,end_pedge_it) = edges(PG);
for (;pedge_it!=end_pedge_it;++pedge_it) {
......@@ -246,7 +243,7 @@ void remove_node(vvertex vv)
#endif
// pclass
if (use_pclasses && pnode->my_class && (pnode->my_class->used == 0)) {
if ((!disable_pclasses) && pnode->my_class && (pnode->my_class->used == 0)) {
SDEBUG(cerr << " freeing pclass" << endl);
SSUB(SCORE_PCLASS);
}
......@@ -786,7 +783,7 @@ int add_node(vvertex vv,pvertex pv, bool deterministic)
vinfo.desires += fd_violated;
// pclass
if (use_pclasses && pnode->my_class && (pnode->my_class->used == 0)) {
if ((!disable_pclasses) && pnode->my_class && (pnode->my_class->used == 0)) {
SDEBUG(cerr << " new pclass" << endl);
SADD(SCORE_PCLASS);
}
......@@ -1296,23 +1293,17 @@ pvertex make_lan_node(vvertex vv)
" largest_switch_count=" << largest_switch_count << endl);
pvertex pv = add_vertex(PG);
tb_pnode *p = new tb_pnode();
tb_pnode *p = new tb_pnode(vnode->name);
put(pvertex_pmap,pv,p);
p->name += vnode->name; // Just in case - this gets reset below
p->typed = true;
p->current_type = "lan";
p->max_load = 1;
p->current_load = 0;
p->pnodes_used = 0;
p->types["lan"] = 1;
p->my_class = NULL;
// If the below is false then we have an orphined lan node which will
// If the below is false then we have an orphaned lan node which will
// quickly be destroyed when add_node fails.
if (largest_switch_count != 0) {
pedge pe = (add_edge(pv,largest_switch,PG)).first;
tb_plink *pl = new tb_plink();
put(pedge_pmap,pe,pl);
p->name = "lan-";
p->name += get(pvertex_pmap,largest_switch)->name;
......@@ -1321,24 +1312,19 @@ pvertex make_lan_node(vvertex vv)
// Build a link name that looks like the ones we used to supply in the ptop
// file
pl->name = "link-";
pl->name += p->name;
crope link_name = "link-";
link_name += p->name;
tb_plink *pl = new tb_plink(link_name, tb_plink::PLINK_LAN,
p->name, "(null)");
pl->type = tb_plink::PLINK_LAN;
pl->srcmac = p->name;
//pl->dstmac = get(pvertex_pmap,largest_switch)->name;
pl->dstmac = "(null)";
pl->bw_used = 0;
pl->emulated = pl->nonemulated = 0;
p->switches.insert(largest_switch);
put(pedge_pmap,pe,pl);
#ifdef FIX_PLINK_ENDPOINTS
pl->fixends = false;
#endif
} else {
p->name += "orphin";
p->name += "orphan";
}
return pv;
......@@ -1373,3 +1359,4 @@ void delete_lan_node(pvertex pv)
remove_vertex(pv,PG);
delete pnode;
}
......@@ -7,23 +7,67 @@
#ifndef _SCORE_H
#define _SCORE_H
typedef struct {
int unassigned;
int pnode_load;
int no_connection;
int link_users;
int bandwidth;
int desires;
int vclass;
int delay;
int incorrect_endpoints;
} violated_info;
/*
* 'optimal' score - computes a lower bound on the optimal score for this
* mapping, so that if we find this score, we know we're done and can exit
* early.
*/
#ifdef USE_OPTIMAL
#define OPTIMAL_SCORE(edges,nodes) (nodes*SCORE_PNODE + \
nodes/opt_nodes_per_sw*SCORE_SWITCH + \
edges*((SCORE_INTRASWITCH_LINK+ \
SCORE_DIRECT_LINK*2)*4+\
SCORE_INTERSWITCH_LINK)/opt_nodes_per_sw)
#else
#define OPTIMAL_SCORE(edges,nodes) 0
#endif
/*
* Details about which violations are present
*/
class violated_info {
/* Spit out the current violations (details only, not the total) */
friend ostream &operator<<(ostream &o, const violated_info &vinfo) {
o << " unassigned: " << vinfo.unassigned << endl;
o << " pnode_load: " << vinfo.pnode_load << endl;
o << " no_connect: " << vinfo.no_connection << endl;
o << " link_users: " << vinfo.link_users << endl;
o << " bandwidth: " << vinfo.bandwidth << endl;
o << " desires: " << vinfo.desires << endl;
o << " vclass: " << vinfo.vclass << endl;
o << " delay: " << vinfo.delay << endl;
#ifdef FIX_PLINK_ENDPOINTS
o << " endpoints: " << vinfo.incorrect_endpoints << endl;
#endif
return o;
}
public: /* No real reason to hide this stuff */
violated_info():
unassigned(0), pnode_load(0), no_connection(0), link_users(0),
bandwidth(0), desires(0), vclass(0), delay(0),
incorrect_endpoints(0) { }
int unassigned;
int pnode_load;
int no_connection;
int link_users;
int bandwidth;
int desires;
int vclass;
int delay;
int incorrect_endpoints;
};
extern double score;
extern int violated;
extern violated_info vinfo;
extern bool allow_trivial_links;
/*
* Scoring functions
*/
void init_score();
void remove_node(vvertex vv);
int add_node(vvertex vv,pvertex pv,bool deterministic);
......
/*
* EMULAB-COPYRIGHT
* Copyright (c) 2003 University of Utah and the Flux Group.
* All rights reserved.
*/
#include "solution.h"
/*
* Print out the current solution
*/
void print_solution()
{
vvertex_iterator vit,veit;
tb_vnode *vn;
/*
* Start by printing out all node mappings
*/
cout << "Nodes:" << endl;
tie(vit,veit) = vertices(VG);
for (;vit != veit;++vit) {
vn = get(vvertex_pmap,*vit);
if (! vn->assigned) {
cout << "unassigned: " << vn->name << endl;
} else {
cout << vn->name << " "
<< get(pvertex_pmap,vn->assignment)->name << endl;
}
}
cout << "End Nodes" << endl;
/*
* Next, edges
*/
cout << "Edges:" << endl;
vedge_iterator eit,eendit;
tie(eit,eendit) = edges(VG);
for (;eit!=eendit;++eit) {
tb_vlink *vlink = get(vedge_pmap,*eit);
cout << vlink->name;
if (vlink->link_info.type == tb_link_info::LINK_DIRECT) {
// Direct link - just need the source and destination
tb_plink *p = get(pedge_pmap,vlink->link_info.plinks.front());
cout << " direct " << p->name << " (" <<
p->srcmac << "," << p->dstmac << ")";
} else if (vlink->link_info.type == tb_link_info::LINK_INTRASWITCH) {
// Intraswitch link - need to grab the plinks to both nodes
tb_plink *p = get(pedge_pmap,vlink->link_info.plinks.front());
tb_plink *p2 = get(pedge_pmap,vlink->link_info.plinks.back());
cout << " intraswitch " << p->name << " (" <<
p->srcmac << "," << p->dstmac << ") " <<
p2->name << " (" << p2->srcmac << "," << p2->dstmac << ")";
} else if (vlink->link_info.type == tb_link_info::LINK_INTERSWITCH) {
// Interswitch link - interate through each intermediate link
cout << " interswitch ";
for (pedge_path::iterator it=vlink->link_info.plinks.begin();
it != vlink->link_info.plinks.end();++it) {
tb_plink *p = get(pedge_pmap,*it);
cout << " " << p->name << " (" << p->srcmac << "," <<
</