Commit 83cfa8ec authored by Robert Ricci's avatar Robert Ricci

Major changes to the way assign handles LAN nodes.

LAN nodes are no longer treated specially. Instead, I've introduced
the idea of 'static' types (old-style types retroactively become
'dynamic' types). While a pnode can only satisfy one dynamic type at a
time, it can always satisfy its static types (assuming it has enough
capacity left.) Static types are flagged by prepending them with a '*'
in the ptop file. So, for example, you may give switches the
'*lan:10000' type so that they can satisfy virtual LAN nodes. Of
course, other pnodes can have this type too, so that we can get
'trivial LANs'.

Actually, removing special treatment for LANs cleans up a lot of code.
However, it may have some negative impacts on solutions, since we're
not as smart about where to place LAN nodes as we used to be (they get
annealed along with everything else, and not migrated.) I haven't seen
any evidence of this yet, however.

This leaves us with a single type of special pnode, a switch.

Also added a new bit of syntax in ptop files - when '*' is given as a
the maxiumum load for a type, the node is allowed to take on an
infinite (well, actually, just a really big number of) vnodes of that
type.

ptopgen was modified to always report switches as being capable of
hosting LANs, and assign_wrapper now understands direct links to LANs,
which is what we get when the LAN is hosted directly on a switch.

Fixed a bug in scoring direct links, in which the penatly was being
added once when a direct link was mapped, but subtracted only once
when it was freed.

Added a '-T' option for doing simple self-testing. When adding a node
to the solution, assign records the score, adds the node, removes it
again, and checks to make sure that the resulting score is the same as
the original score. The usefulness of this feature in debugging
scoring problems cannot be understated...
parent 84ff51eb
This diff is collapsed.
......@@ -80,8 +80,6 @@ inline int accept(double change, double temperature);
tb_pnode *find_pnode(tb_vnode *vn);
/* The big guy! */
void anneal();
void anneal(bool scoring_selftest);
#endif
......@@ -298,6 +298,7 @@ void print_help()
#ifdef PER_VNODE_TT
cerr << " -P - Prune unusable pclasses." << endl;
#endif
cerr << " -T - Doing some scoring self-testing." << endl;
exit(2);
}
......@@ -312,11 +313,6 @@ int type_precheck() {
for (name_count_map::iterator vtype_it=vtypes.begin();
vtype_it != vtypes.end();++vtype_it) {
// Ignore LAN vnodes
if (vtype_it->first == crope("lan")) {
continue;
}
// Check to see if there were any pnodes of the type at all
name_count_map::iterator ptype_it = ptypes.find(vtype_it->first);
if (ptype_it == ptypes.end()) {
......@@ -366,11 +362,6 @@ int mapping_precheck() {
for (;vit != vendit;vit++) {
tb_vnode *v = get(vvertex_pmap,*vit);
//
// No reason to do this work for LAN nodes!
if (!v->type.compare("lan")) {
continue;
}
pclass_vector *vec = new pclass_vector();
vnode_type_table[v->name] = tt_entry(0,vec);
......@@ -405,8 +396,12 @@ int mapping_precheck() {
// Grab the first node of the pclass as a representative sample
tb_pnode *pnode = *((*it)->members[this_type]->L.begin());
// Check the number of interfaces
if (pnode->total_interfaces >= v->num_links) {
// Check the number of interfaces - if the pnode is a switch,
// for now, we don't check this, since it can end up with more
// 'interfaces' due to the fact that it can have interswitch
// links
if ((pnode->total_interfaces >= v->num_links) ||
pnode->current_type.compare("switch")) {
matched_links++;
} else {
potential_match = false;
......@@ -529,6 +524,7 @@ int main(int argc,char **argv)
{
int seed = 0;
crope viz_prefix;
bool scoring_selftest = false;
// Handle command line
char ch;
......@@ -566,6 +562,8 @@ int main(int argc,char **argv)
case 'P':
prune_pclasses = true; break;
#endif
case 'T':
scoring_selftest = true; break;
default:
print_help();
}
......@@ -653,8 +651,9 @@ int main(int argc,char **argv)
}
timestart = used_time();
anneal();
anneal(scoring_selftest);
timeend = used_time();
#ifdef GNUPLOT_OUTPUT
fclose(scoresout);
fclose(tempout);
......
......@@ -63,20 +63,24 @@ Each vnode has a type and a valid solution must match each vnode to a
pnode that can support that type. A vnode has a single type but a
pnode may be able to support several types and even have multiple
vnodes in a single vnode. For example, a standard testbed PC with
four interfaces can either be a test node or up to two delay nodes. A
pnode that has not been matched to a vnode is called virgin and can
take on any of its types. Once it has been mapped to a vnode it
becomes typed and is locked into a certain type (that of the vnode).
When add_node is called the first thing checked is whether the pnode
has a suitable type for the vnode. If it is virgin then all its types
are checked, otherwise only its current type is checked. If the types
can not be matched then add_node returns an invalid condition,
otherwise it continues on.
four interfaces can either be a test node or up to two delay nodes.
The type system is composed of two classes of types: 'dynamic' types,
and 'static' types. A pnode can always satisfy any of its static
types, but has only one of its dynamic types 'active' at any time. A
pnode that has not been matched to a vnode using one of its dynamic
types is called virgin and can take on any of its dynamic types. Once
it has been mapped to a vnode it becomes typed and is locked into a
certain type (that of the vnode). When add_node is called the first
thing checked is whether the pnode has a suitable type for the vnode.
If the vnode uses a static type, the pnode must simply have available
capacity for that type. Otherwise, dynamic types are checked. If it is
virgin then all its types are checked, otherwise only its current type
is checked. If the types can not be matched then add_node returns an
invalid condition, otherwise it continues on.
Each type of a pnode also has a limit. This is the number of vnodes
of that type that can fit in the pnode. A vnode can not be placed in a pnode unless there is room left.
Under no conditions is a vnode mapped to a switch.
of that type that can fit in the pnode. A vnode can not be placed in
a pnode unless there is room left.
Links
-----
......
......@@ -67,8 +67,18 @@ int parse_ptop(tb_pgraph &PG, tb_sgraph &SG, istream& i)
if (split_two(parsed_line[i],':',type,load,"1") != 0) {
ptop_error("Bad node line, no load for type: " << type << ".");
}
// Check to see if this is a static type
bool is_static = false;
if (type[0] == '*') {
is_static = true;
type.pop_front();
}
int iload;
if (sscanf(load.c_str(),"%d",&iload) != 1) {
if (!load.compare("*")) { // Allow * to mean unlimited
// (okay, a really big number)
iload = 10000000;
} else if (sscanf(load.c_str(),"%d",&iload) != 1) {
ptop_error("Bad node line, bad load: " << load << ".");
iload = 1;
}
......@@ -79,14 +89,14 @@ int parse_ptop(tb_pgraph &PG, tb_sgraph &SG, istream& i)
}
if (type.compare("switch") == 0) {
isswitch = true;
p->types["switch"] = 1;
p->types["switch"] = new tb_pnode::type_record(1,false);
svertex sv = add_vertex(SG);
tb_switch *s = new tb_switch();
put(svertex_pmap,sv,s);
s->mate = pv;
p->sgraph_switch = sv;
} else {
p->types[type] = iload;
p->types[type] = new tb_pnode::type_record(iload,is_static);
}
}
for (i=i+1;(i<parsed_line.size()) && (parsed_line[i].compare("-")) ;++i) {
......@@ -103,7 +113,7 @@ int parse_ptop(tb_pgraph &PG, tb_sgraph &SG, istream& i)
p->features[feature] = gcost;
}
/*
* Parse any other node optios or flags
* Parse any other node options or flags
*/
for (i=i+1; i < parsed_line.size(); ++i) {
crope flag,value;
......@@ -215,10 +225,11 @@ int parse_ptop(tb_pgraph &PG, tb_sgraph &SG, istream& i)
pl->type = tb_plink::PLINK_INTERSWITCH;
}
}
srcnode->total_interfaces++;
dstnode->total_interfaces++;
if (ISSWITCH(srcnode) &&
! ISSWITCH(dstnode)) {
dstnode->switches.insert(srcv);
dstnode->total_interfaces++;
#ifdef PER_VNODE_TT
dstnode->total_bandwidth += ibw;
#endif
......@@ -226,7 +237,6 @@ int parse_ptop(tb_pgraph &PG, tb_sgraph &SG, istream& i)
else if (ISSWITCH(dstnode) &&
! ISSWITCH(srcnode)) {
srcnode->switches.insert(dstv);
srcnode->total_interfaces++;
#ifdef PER_VNODE_TT
srcnode->total_bandwidth += ibw;
#endif
......
......@@ -66,10 +66,10 @@ int pclass_equiv(tb_pgraph &PG, tb_pnode *a,tb_pnode *b)
for (tb_pnode::types_map::iterator it=a->types.begin();
it!=a->types.end();++it) {
const crope &a_type = (*it).first;
const int a_max_nodes = (*it).second;
tb_pnode::type_record *a_type_record = (*it).second;
tb_pnode::types_map::iterator bit = b->types.find(a_type);
if ((bit == b->types.end()) ||((*bit).second != a_max_nodes))
if ((bit == b->types.end()) || ! ( *(*bit).second == *a_type_record) )
return 0;
}
......@@ -222,7 +222,8 @@ int pclass_set(tb_vnode *v,tb_pnode *p)
for (dit=c->members.begin();dit!=c->members.end();dit++) {
if ((*dit).first == p->current_type) {
// same class - only remove if node is full
if (p->current_load == p->max_load) {
if (p->types[p->current_type]->current_load ==
p->types[p->current_type]->max_load) {
(*dit).second->remove(p);
//#ifdef SMART_UNMAP
// c->used_members[(*dit).first]->push_back(p);
......@@ -246,7 +247,7 @@ int pclass_set(tb_vnode *v,tb_pnode *p)
}
c->used += 1.0/(p->max_load);
c->used += 1.0/(p->current_type_record->max_load);
return 0;
}
......@@ -266,12 +267,12 @@ int pclass_unset(tb_pnode *p)
// empty and the front if it's not. Since unset is called before
// remove_node empty means only one user.
if (! (*dit).second->exists(p)) {
assert(p->current_load > 0);
assert(p->types[p->current_type]->current_load > 0);
#ifdef PNODE_ALWAYS_FRONT
(*dit).second->push_front(p);
#else
#ifdef PNODE_SWITCH_LOAD
if (p->current_load == 0) {
if (p->types[p->current_type]->current_load == 0) {
#else
if (p->current_load == 1) {
#endif
......@@ -295,7 +296,7 @@ int pclass_unset(tb_pnode *p)
//cout << endl;
c->used -= 1.0/(p->max_load);
c->used -= 1.0/(p->current_type_record->max_load);
return 0;
}
......
......@@ -71,13 +71,34 @@ class tb_pnode {
public:
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),
current_type_record(NULL), total_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;
class type_record {
public:
type_record(int _max_load, bool _is_static) :
max_load(_max_load), current_load(0),
is_static(_is_static) { ; }
int max_load; // maximum load for this type
int current_load; // how many vnodes are assigned of this type
bool is_static; // whether this type is static or dynamic
bool operator==(const type_record &b) {
return ((max_load == b.max_load) && (is_static == b.is_static));
}
friend ostream &operator<<(ostream &o, const type_record& node)
{
o << "max_load = " << node.max_load <<
" current_load = " << node.current_load <<
" is_static = " << node.is_static;
}
};
typedef hash_map<crope,type_record*> types_map;
typedef hash_map<crope,double> features_map;
// contains max nodes for each type
......@@ -89,8 +110,10 @@ public:
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
type_record* current_type_record;
int total_load; // total load for all types
//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
......@@ -111,6 +134,22 @@ public:
int trivial_bw_used; // the amount of bandwidth currently used by
// trivial links
bool set_current_type(crope type) {
if (types.find(type) == types.end()) {
//cout << "Failed to find type " << type << endl;
return false;
}
current_type = type;
typed = true;
current_type_record = types[type];
return true;
}
void remove_current_type() {
typed = false;
current_type_record = NULL;
}
// Output operator for debugging
friend ostream &operator<<(ostream &o, const tb_pnode& node)
{
......@@ -123,8 +162,8 @@ public:
for (features_map::const_iterator it = node.features.begin();
it!=node.features.end();it++)
cout << " " << (*it).first << " -> " << (*it).second << endl;
o << " Current Type: " << node.current_type <<
" (" << node.current_load << "/" << node.max_load << ")" << endl;
o << " Current Type: " << node.current_type << endl; /* <<
" (" << node.current_load << "/" << node.max_load << ")" << endl; */
o << " switches=";
for (pvertex_set::const_iterator it = node.switches.begin();
it != node.switches.end();++it) {
......
This diff is collapsed.
......@@ -44,8 +44,10 @@ void print_solution()
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());
tb_plink *p2 = get(pedge_pmap,vlink->link_info.plinks.back());
cout << " direct " << p->name << " (" <<
p->srcmac << "," << p->dstmac << ")";
p->srcmac << "," << p->dstmac << ") " <<
p2->name << " (" << p2->srcmac << "," << p2->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());
......
......@@ -1154,8 +1154,9 @@ while (1) {
last SWITCH1;
};
/^direct$/ && do {
fatal(65, "*** $0:\n".
" Unsupported link type: direct.\n");
($vlink,$rawA,$rawB) = @info[0,3,5];
#fatal(65, "*** $0:\n".
# " Unsupported link type: direct.\n");
};
/^trivial$/ && do {
# we don't have plinks for trivial links
......
......@@ -90,7 +90,7 @@ $nodetypes{"switch"} = 0;
# Print switches
if (defined($switchtouse)) {
print "node $switchtouse switch:1\n";
print "node $switchtouse switch:1 *lan:*\n";
$switches{$switchtouse} = 1;
}
else {
......@@ -98,7 +98,7 @@ else {
DBQueryFatal("select node_id from nodes where role = \"testswitch\"");
while (($switch) = $result->fetchrow_array) {
print "node $switch switch:1\n";
print "node $switch switch:1 *lan:*\n";
$switches{$switch} = 1;
}
$result->finish;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment