Commit 690ec56d authored by Robert Ricci's avatar Robert Ricci

Fix PER_VNODE_TT to work with vclasses and emulated links. Now, we can turn it

on in production!

PER_VNODE_TT handles emulated links by simply adding up the total bandwidth
consumed by a vnode, and the total bandwidth available on each pnode. Of
course, this can lead to false positives (knapsack problem), but that's okay,
because it just means we won't bail up front - we'll have to do the full
annealing pass before we decide it's unmappable.

PER_VNODE_TT now also tries to figure out why a vnode is not mappable - if
there are _no_ pclasses that match one of the restrictions, it will print out
something like:
  *** No possible mapping for nodeA
      Too many links!
  *** No possible mapping for nodeB
      Too much bandwidth on emulated links!

This completes the following two items from assign_todo.txt:

6.   fix PER_VNODE_TT and vclasses
7.   fix PER_VNODE_TT and emulated vlinks
parent ae02e458
......@@ -41,9 +41,11 @@ CXXFLAGS += -DMELT -DEPSILON_TERMINATE -DCHILL -DNEIGHBOR_LENGTH \
CXXFLAGS += -DINTERSWITCH_LENGTH -DPNODE_SWITCH_LOAD -DFIX_SHARED_INTERFACES
# Various tweaks to the simulated annealing behavior
CXXFLAGS += -DFIND_PNODE_SEARCH -DNO_REVERT
# This should be enabled, for better mapping, but has to be disabled
# for now because it breaks vclasses
#CXXFLAGS += -DPER_VNODE_TT -DSMART_UNMAP
# 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
......
......@@ -372,6 +372,16 @@ REDO_SEARCH:
tb_pnode* firstmatch = NULL;
#endif
#ifdef FIND_PNODE_SEARCH
#ifdef PER_VNODE_TT
// If using PER_VNODE_TT and vclasses, it's possible that there are
// some pclasses in this node's type table that can't be used right now,
// becuase they contain entires that don't contain the vnodes _current_
// type
if ((*acceptable_types)[i]->members.find(vn->type) ==
(*acceptable_types)[i]->members.end()) {
continue;
}
#endif
list<tb_pnode*>::iterator it = (*acceptable_types)[i]->members[vn->type]->L.begin();
#ifdef LOAD_BALANCE
int skip = std::rand() % (*acceptable_types)[i]->members[vn->type]->L.size();
......@@ -1655,43 +1665,113 @@ int main(int argc,char **argv)
}
}
}
if (! ok) exit(-1);
if (! ok) {
cout << "Type preecheck failed!" << endl;
exit(-1);
}
cout << "Type preecheck passed." << endl;
#ifdef PER_VNODE_TT
cout << "Node mapping precheck:" << endl;
/*
* Build up an entry in the type table for each vnode, by first looking at the
* type table entry for the vnode's type, then checking each entry to make
* sure that it:
* (1) Has enough interfaces
* (2) Has enough total bandwidth (for emulated links)
* (3) TODO: Meets any 1.0-weight features and/or desires
*/
vvertex_iterator vit,vendit;
tie(vit,vendit) = vertices(VG);
/*
* Indicates whether all nodes have potential matches or not
*/
ok = true;
for (;vit != vendit;vit++) {
tb_vnode *v = get(vvertex_pmap,*vit);
int size = type_table[v->type].first;
pclass_vector *vec = new pclass_vector(size); // Could be an over-estimate
vnode_type_table[v->name] = tt_entry(size,vec);
pclass_vector::iterator it;
int i = 0;
// No reason to look for these for LAN nodes!
//
// No reason to do this work for LAN nodes!
if (!v->type.compare("lan")) {
continue;
}
for (it = type_table[v->type].second->begin();
it != type_table[v->type].second->end(); it++) {
tb_pnode *first = *((*it)->members[v->type]->L.begin());
//cout << "Checking " << first->total_interfaces << " >= " <<
// v->num_links << " ";
if ((first->total_interfaces >= v->num_links) ||
(first->types[v->type] > 1)) {
(*vec)[i++] = *it;
//cout << "Allowing!" << endl;
pclass_vector *vec = new pclass_vector();
vnode_type_table[v->name] = tt_entry(0,vec);
// This constitutes a list of the number of ptypes that matched the
// criteria. We use to guess what's wrong with the vnode.
int matched_links = 0;
int matched_bw = 0;
tb_vclass *vclass = v->vclass;
tb_vclass::members_map::iterator mit;
if (vclass) {
mit = vclass->members.begin();
}
for (;;) {
// Loop over all types this node can take on, which might be only
// one, if it's not part of a vclass
crope this_type;
if (vclass) {
this_type = mit->first;
} else {
//cout << "Skipping!" << endl;
vnode_type_table[v->name].first--;
this_type = v->type;
}
for (pclass_vector::iterator it = type_table[this_type].second->begin();
it != type_table[this_type].second->end(); it++) {
bool potential_match = true;
// 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) {
matched_links++;
} else {
potential_match = false;
}
// Check bandwidth on emulated links
if (pnode->total_bandwidth >= v->total_bandwidth) {
matched_bw++;
} else {
potential_match = false;
}
if (potential_match) {
vec->push_back(*it);
vnode_type_table[v->name].first++;
#ifdef PCLASS_DEBUG
cerr << v->name << " can map to " << (*it)->name << endl;
#endif
}
}
if (vclass) {
mit++;
if (mit == vclass->members.end()) {
break;
}
} else {
// If not a vtype, we only had to do this once
break;
}
}
assert(vnode_type_table[v->name].first >= 0);
if (vnode_type_table[v->name].first == 0) {
cerr << "No possible mapping for " << v->name;
exit(1);
cerr << " *** No possible mapping for " << v->name << endl;
// Make an attempt to figure out why it didn't match
if (!matched_links) {
cerr << " Too many links!" << endl;
}
if (!matched_bw) {
cerr << " Too much bandwidth on emulated links!" << endl;
}
ok = false;
}
#ifdef PCLASS_DEBUG
cerr << v->name << " can map to " << vnode_type_table[v->name].first << " pclasses"
......@@ -1699,6 +1779,12 @@ int main(int argc,char **argv)
#endif
}
if (!ok) {
cout << "Node mapping precheck failed!" << endl;
exit(-1);
}
cout << "Node mapping precheck succeeded" << endl;
#endif
// Output graphviz if necessary
......
......@@ -58,18 +58,6 @@ This is the current TODO list for assign (not in order by priority):
Merge back in Chris's delay node support.
6. fix PER_VNODE_TT and vclasses
PER_VNODE_TT is definitely a good thing, but it currently breaks vclasses, so
we can't use it in production. This might be tricky to fix, but is definitely
worth it. This will help to give better error messages when a vnode has too
many vlinks to fit into any of the pnodes.
7. fix PER_VNODE_TT and emulated vlinks
PER_VNODE_TT assume that each vlink is going to consume one plink - need to
relax this for emulated links.
8. prune pclasses when using PER_VNODE_TT
Right now, we use all pclasses, even those which we cannot possibly use, in
......
......@@ -214,16 +214,18 @@ int parse_ptop(tb_pgraph &PG, tb_sgraph &SG, istream& i)
if (ISSWITCH(srcnode) &&
! ISSWITCH(dstnode)) {
dstnode->switches.insert(srcv);
//#ifdef PENALIZE_UNUSED_INTERFACES
dstnode->total_interfaces++;
//#endif
#ifdef PER_VNODE_TT
dstnode->total_bandwidth += ibw;
#endif
}
else if (ISSWITCH(dstnode) &&
! ISSWITCH(srcnode)) {
srcnode->switches.insert(dstv);
//#ifdef PENALIZE_UNUSED_INTERFACES
#ifdef PER_VNODE_TT
srcnode->total_bandwidth += ibw;
#endif
srcnode->total_interfaces++;
//#endif
}
}
} else {
......
......@@ -80,6 +80,7 @@ int parse_top(tb_vgraph &VG, istream& i)
v->fixed = false; // this may get set to true later
#ifdef PER_VNODE_TT
v->num_links = 0;
v->total_bandwidth = 0;
#endif
for (unsigned int i = 3;i < parsed_line.size();++i) {
......@@ -167,13 +168,6 @@ int parse_top(tb_vgraph &VG, istream& i)
l->src = node1;
l->dst = node2;
put(vedge_pmap,e,l);
#ifdef PER_VNODE_TT
tb_vnode *vnode1 = get(vvertex_pmap,node1);
vnode1->num_links++;
tb_vnode *vnode2 = get(vvertex_pmap,node2);
vnode2->num_links++;
#endif
if ((sscanf(bw.c_str(),"%d",&(l->delay_info.bandwidth)) != 1) ||
(sscanf(bwunder.c_str(),"%d",&(l->delay_info.bw_under)) != 1) ||
......@@ -211,6 +205,18 @@ int parse_top(tb_vgraph &VG, istream& i)
parsed_line[i] << ".");
}
}
#ifdef PER_VNODE_TT
tb_vnode *vnode1 = get(vvertex_pmap,node1);
tb_vnode *vnode2 = get(vvertex_pmap,node2);
if (l->emulated) {
vnode1->total_bandwidth += l->delay_info.bandwidth;
vnode2->total_bandwidth += l->delay_info.bandwidth;
} else {
vnode1->num_links++;
vnode2->num_links++;
}
#endif
}
} else if (command.compare("make-vclass") == 0) {
if (parsed_line.size() < 4) {
......
......@@ -114,6 +114,9 @@ public:
#ifdef PENALIZE_UNUSED_INTERFACES
int used_interfaces;
#endif
#ifdef PER_VNODE_TT
int total_bandwidth;
#endif
tb_pclass *my_class;
......
......@@ -95,6 +95,7 @@ public:
#ifdef PER_VNODE_TT
int num_links;
int total_bandwidth;
#endif
};
......
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