diff --git a/assign/anneal.cc b/assign/anneal.cc index aea837f9b17a58b23b08b7b9f5cab0c958575362..76a55b2540cd2746a943e386a0c79f9ff375a2dd 100644 --- a/assign/anneal.cc +++ b/assign/anneal.cc @@ -48,6 +48,18 @@ inline int accept(double change, double temperature) return 0; } +// finds a random pnode, of any type at all +tb_pnode *find_random_pnode() { + int choice = std::random() % num_vertices(PG); + pvertex_iterator vit, vendit; + tie(vit,vendit) = vertices(PG); + cout << "Chose pnode " << choice << " of " << num_vertices(PG) << endl; + for (int i = 0; i < choice;++vit, ++i) { + } + tb_pnode *curP = get(pvertex_pmap,*vit); + return curP; +} + tb_pnode *find_pnode(tb_vnode *vn) { #ifdef PER_VNODE_TT @@ -67,7 +79,6 @@ tb_pnode *find_pnode(tb_vnode *vn) #ifdef PCLASS_SIZE_BALANCE int acceptchance = 1000 * (*acceptable_types)[i]->size * 1.0 / npnodes; - //cout << "Chance was " << acceptchance << endl; if ((std::rand() % 1000) < acceptchance) { continue; } @@ -119,7 +130,8 @@ REDO_SEARCH: } #else if ((*it)->typed && ((*it)->current_type.compare(vn->type) || - ((*it)->current_load >= (*it)->max_load))) { + ((*it)->current_type_record->current_load >= + (*it)->current_type_record->max_load))) { it++; } else { break; @@ -152,7 +164,7 @@ REDO_SEARCH: RDEBUG(cout << " to " << newpnode->name << endl;) return newpnode; } - + #ifndef PCLASS_SIZE_BALANCE if (i == first) { // couldn't find one @@ -164,7 +176,7 @@ REDO_SEARCH: /* When this is finished the state will reflect the best solution found. */ -void anneal() +void anneal(bool scoring_selftest) { cout << "Annealing." << endl; @@ -213,6 +225,10 @@ void anneal() /* Set up the initial counts */ init_score(); + /* We'll check against this later to make sure that whe we've unmapped + * everything, the score is the same */ + double initial_score = get_score(); + /* Set up fixed nodes */ for (name_name_map::iterator fixed_it=fixed_nodes.begin(); fixed_it!=fixed_nodes.end();++fixed_it) { @@ -383,12 +399,7 @@ void anneal() } else { int start = std::random()%nnodes; int choice = start; -#if defined(FIX_LAN_NODES) || defined(AUTO_MIGRATE) - while (get(vvertex_pmap,virtual_nodes[choice])->fixed || - !get(vvertex_pmap,virtual_nodes[choice])->type.compare("lan")) { -#else while (get(vvertex_pmap,virtual_nodes[choice])->fixed) { -#endif choice = (choice +1) % nnodes; if (choice == start) { choice = -1; @@ -423,192 +434,156 @@ void anneal() vn->vclass->dominant << endl; #endif } - if (vn->type.compare("lan") == 0) { - // LAN node - pvertex lanv = make_lan_node(vv); -#ifndef FREE_IMMEDIATELY - if (oldassigned) { - RDEBUG(cout << "removing: lan,oldassigned" << endl;) - remove_node(vv); - } -#endif - if (add_node(vv,lanv,false) != 0) { - delete_lan_node(lanv); - unassigned_nodes.push(vvertex_int_pair(vv,std::random())); - continue; - } - } else { - tb_pnode *newpnode = find_pnode(vn); + tb_pnode *newpnode = find_pnode(vn); #ifndef FREE_IMMEDIATELY - if (oldassigned) { - RDEBUG(cout << "removing: !lan, oldassigned" << endl;) + if (oldassigned) { + RDEBUG(cout << "removing: !lan, oldassigned" << endl;) remove_node(vv); - } + } #endif - if (newpnode == NULL) { - // We're not going to be re-assigning this one + if (newpnode == NULL) { + // We're not going to be re-assigning this one #ifndef SMART_UNMAP - unassigned_nodes.push(vvertex_int_pair(vv,std::random())); + unassigned_nodes.push(vvertex_int_pair(vv,std::random())); #endif - // need to free up nodes + // need to free up nodes #ifdef 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 = std::rand(); - 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; + // 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 = std::rand(); + 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 = std::rand() % (*acceptable_types)[index]->used_members[vn->type]->size(); - while (j > 0) { - it++; - j--; - } - tb_vnode_set::iterator it2 = (*it)->assigned_nodes.begin(); - int k = std::rand() % (*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, - std::random())); - } else { - cerr << "Failed to find a replacement!" << endl; + 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 = std::rand() % (*acceptable_types)[index]->used_members[vn->type]->size(); + while (j > 0) { + it++; + j--; + } + tb_vnode_set::iterator it2 = (*it)->assigned_nodes.begin(); + int k = std::rand() % (*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, + std::random())); + } else { + cerr << "Failed to find a replacement!" << endl; + } #else - int start = std::random()%nnodes; - int toremove = start; -#if defined(FIX_LAN_NODES) || defined(AUTO_MIGRATE) - while (get(vvertex_pmap,virtual_nodes[toremove])->fixed || - (!get(vvertex_pmap,virtual_nodes[toremove])->assigned) || - (get(vvertex_pmap,virtual_nodes[toremove])->type.compare("lan"))) { -#else + int start = std::random()%nnodes; + int toremove = start; #ifdef SMART_UNMAP #ifdef PER_VNODE_TT - tt_entry tt = vnode_type_table[vn->name]; + 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) { + 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; + } + #else - while (get(vvertex_pmap,virtual_nodes[toremove])->fixed || - (! get(vvertex_pmap,virtual_nodes[toremove])->assigned)) { -#endif + while (get(vvertex_pmap,virtual_nodes[toremove])->fixed || + (! get(vvertex_pmap,virtual_nodes[toremove])->assigned)) { #endif toremove = (toremove +1) % nnodes; if (toremove == start) { - toremove = -1; - break; + toremove = -1; + break; } - } - if (toremove >= 0) { + } + if (toremove >= 0) { RDEBUG(cout << "removing: freeing up nodes" << endl;) - remove_node(virtual_nodes[toremove]); + remove_node(virtual_nodes[toremove]); unassigned_nodes.push(vvertex_int_pair(virtual_nodes[toremove], - std::random())); - } - continue; + std::random())); + } + continue; #endif /* SMART_UNMAP */ #ifndef SMART_UNMAP - } else { + } else { #else - } + } #endif if (newpnode != NULL) { - newpos = pnode2vertex[newpnode]; - if (add_node(vv,newpos,false) != 0) { - unassigned_nodes.push(vvertex_int_pair(vv,std::random())); - continue; + newpos = pnode2vertex[newpnode]; + if (scoring_selftest) { + // Run a little test here - see if the score we get by adding + // this node, then removing it, is the same one we would have + // gotten otherwise + double oldscore = get_score(); + if (!add_node(vv,newpos,false)) { + remove_node(vv); } + assert(oldscore == get_score()); + } + if (add_node(vv,newpos,false) != 0) { + unassigned_nodes.push(vvertex_int_pair(vv,std::random())); + continue; + } } else { #ifdef SMART_UNMAP - unassigned_nodes.push(vvertex_int_pair(vv,std::random())); + unassigned_nodes.push(vvertex_int_pair(vv,std::random())); #endif - if (freednode) { - continue; - } + if (freednode) { + continue; + } } #ifndef SMART_UNMAP } -#endif - } - -#ifdef FIX_LAN_NODES - // OK, we're going to do something silly here: Migrate LAN nodes! - vvertex_iterator lanvertex_it,end_lanvertex_it; - vvertex_list migrate_lan_nodes; - tie(lanvertex_it,end_lanvertex_it) = vertices(VG); - for (;lanvertex_it!=end_lanvertex_it;++lanvertex_it) { - tb_vnode *vnode = get(vvertex_pmap,*lanvertex_it); - if (vnode->assigned) { - if (vnode->type.compare("lan") == 0) { - migrate_lan_nodes.push_front(*lanvertex_it); - } - } - } - while (migrate_lan_nodes.size() > 0) { - vvertex lanv = migrate_lan_nodes.front(); - migrate_lan_nodes.pop_front(); - RDEBUG(cout << "removing: migration" << endl;) - remove_node(lanv); - pvertex lanpv = make_lan_node(lanv); - add_node(lanv,lanpv,true); - } - #endif newscore = get_score(); @@ -717,9 +692,6 @@ void anneal() RDEBUG(cout << "removing: rejected change" << endl;) remove_node(vv); if (oldassigned) { - if (vn->type.compare("lan") == 0) { - oldpos = make_lan_node(vv); - } add_node(vv,oldpos,false); } } @@ -904,18 +876,7 @@ NOTQUITEDONE: // Only revert if the best configuration has better violations vvertex_list lan_nodes; vvertex_iterator vvertex_it,end_vvertex_it; - if (!revert) { - // Just find LAN nodes, for migration - tie(vvertex_it,end_vvertex_it) = vertices(VG); - for (;vvertex_it!=end_vvertex_it;++vvertex_it) { - tb_vnode *vnode = get(vvertex_pmap,*vvertex_it); - if (vnode->assigned) { - if (vnode->type.compare("lan") == 0) { - lan_nodes.push_front(*vvertex_it); - } - } - } - } else { + if (revert) { cout << "Reverting to best solution\n"; // Do a full revert tie(vvertex_it,end_vvertex_it) = vertices(VG); @@ -929,36 +890,28 @@ NOTQUITEDONE: RDEBUG(cout << "not removing: revert " << vnode->name << endl;) } } + + // Check to make sure that our 'clean' solution scores the same as + // the initial score - if not, that indicates a bug + if (get_score() != initial_score) { + cerr << "*** WARNING: 'Clean' score does not match initial score" << + endl << " This indicates a bug - contact the operators" << + endl << " (initial score: " << initial_score << + ", current score: " << get_score() << ")" << endl; + } tie(vvertex_it,end_vvertex_it) = vertices(VG); for (;vvertex_it!=end_vvertex_it;++vvertex_it) { tb_vnode *vnode = get(vvertex_pmap,*vvertex_it); if (vnode->fixed) continue; if (absassigned[*vvertex_it]) { - if (vnode->type.compare("lan") == 0) { - lan_nodes.push_front(*vvertex_it); - } else { - if (vnode->vclass != NULL) { - vnode->type = abstypes[*vvertex_it]; - } - assert(!add_node(*vvertex_it,absassignment[*vvertex_it],true)); + if (vnode->vclass != NULL) { + vnode->type = abstypes[*vvertex_it]; } + assert(!add_node(*vvertex_it,absassignment[*vvertex_it],true)); } } } - // Do LAN migration - RDEBUG(cout << "Doing LAN migration" << endl;) - while (lan_nodes.size() > 0) { - vvertex lanv = lan_nodes.front(); - lan_nodes.pop_front(); - if (!revert) { // If reverting, we've already done this - RDEBUG(cout << "removing: migration" << endl;) - remove_node(lanv); - } - pvertex lanpv = make_lan_node(lanv); - add_node(lanv,lanpv,true); - } - tsteps++; if (finished) { diff --git a/assign/anneal.h b/assign/anneal.h index 047839611bab5ab935d1896fc3764199bddadf3b..5cbd264a68ad93fc4fc334f03f81d42482b310e0 100644 --- a/assign/anneal.h +++ b/assign/anneal.h @@ -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 diff --git a/assign/assign.cc b/assign/assign.cc index e428ec7be97d3e5a2e4d330ede160d377c931213..93a3d74223cc5e90ae49861151d5044c335338f8 100644 --- a/assign/assign.cc +++ b/assign/assign.cc @@ -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); diff --git a/assign/assign_internals.txt b/assign/assign_internals.txt index 1d721218a034ceffdcbdef26798a7e101462c6a6..bb5e8ec7a729f0ae9f46868692ae6293bc57f55e 100644 --- a/assign/assign_internals.txt +++ b/assign/assign_internals.txt @@ -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 ----- diff --git a/assign/parse_ptop.cc b/assign/parse_ptop.cc index 370e08c1b6baec92aa9bbba8645d1ab12144cf6c..1a31b7932c168fbd481f279333a10a3509db40a3 100644 --- a/assign/parse_ptop.cc +++ b/assign/parse_ptop.cc @@ -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;(ifeatures[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 diff --git a/assign/pclass.cc b/assign/pclass.cc index 04b386e9c1c24070afa7a7bcfae95a2ce2c531e9..4e211b7a7083711801cae43ba220866427c75959 100644 --- a/assign/pclass.cc +++ b/assign/pclass.cc @@ -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; } diff --git a/assign/physical.h b/assign/physical.h index d46f55da30edb82c4d4f6b21580905bdc7bc662a..531edccd7afad1bbb35bc63e9c0665fd83eafdfe 100644 --- a/assign/physical.h +++ b/assign/physical.h @@ -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 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 types_map; typedef hash_map 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) { diff --git a/assign/score.cc b/assign/score.cc index 842969ec3b175dfbdc18db54e8a7345f0c797d6f..8641afa75fa9e66020800aa31c70b27d7c9c53a2 100644 --- a/assign/score.cc +++ b/assign/score.cc @@ -144,16 +144,18 @@ void unscore_link_info(vedge ve,tb_pnode *src_pnode,tb_pnode *dst_pnode) if (vlink->link_info.type == tb_link_info::LINK_DIRECT) { // DIRECT LINK SDEBUG(cerr << " direct link" << endl); + SSUB(SCORE_DIRECT_LINK); unscore_link(vlink->link_info.plinks.front(),ve,src_pnode,dst_pnode); vlink->link_info.plinks.clear(); } else if (vlink->link_info.type == tb_link_info::LINK_INTERSWITCH) { // INTERSWITCH LINK SDEBUG(cerr << " interswitch link" << endl); - pedge_path &path = vlink->link_info.plinks; #ifndef INTERSWITCH_LENGTH SSUB(SCORE_INTERSWITCH_LINK); #endif + + pedge_path &path = vlink->link_info.plinks; // XXX: Potentially bogus; int numinterlinks; numinterlinks = -2; @@ -231,11 +233,32 @@ void remove_node(vvertex vv) assert(pnode != NULL); + /* + * Find the type on the pnode that this vnode is associated with + */ + tb_pnode::types_map::iterator mit = pnode->types.find(vnode->type); + tb_pnode::type_record *tr; + if (mit == pnode->types.end()) { + // This is kind of a hack - if we don't find the type, then the vnode + // must have a vtype. So, we assume it must have been assigned to this + // node's dynamic type at some point. + // A consequence of this hack is that vtypes can't map to static types, + // for now. + RDEBUG(cerr << "Failed to find type " << vnode->type << " (for vnode " << + vnode->name << ") on pnode " << pnode->name << endl;) + tr = pnode->current_type_record; + } else { + tr = mit->second; + } + + /* * Clean up the pnode's state */ - if (pnode->my_class) { - pclass_unset(pnode); + if (!tr->is_static) { + if (pnode->my_class) { + pclass_unset(pnode); + } } #ifdef SMART_UNMAP @@ -288,7 +311,13 @@ void remove_node(vvertex vv) // Only unscore the link if the vnode on the other end is assigned - this // way, only the first end to be unmapped causes unscoring - if (! dest_vnode->assigned) continue; + if (! dest_vnode->assigned) { + //cerr << "Skipping link unassignment, because " << dest_vnode->name + //<< " is unassigned " << endl; + continue; + } else { + //cerr << "Unassigning, " << dest_vnode->name << " is assigned " << endl; + } // Find the pnode on the ther end of the link, and unscore it! pvertex dest_pv = dest_vnode->assignment; @@ -305,7 +334,8 @@ void remove_node(vvertex vv) /* * Adjust scores for the pnode */ - pnode->current_load--; + tr->current_load--; + pnode->total_load--; #ifdef LOAD_BALANCE // Use this tricky formula to score based on how 'full' the pnode is, so that // we prefer to equally fill the minimum number of pnodes @@ -313,18 +343,19 @@ void remove_node(vvertex vv) SADD(SCORE_PNODE * (powf(1+ pnode->current_load * 1.0/pnode->max_load,2))); #endif - if (pnode->current_load == 0) { + if (pnode->total_load == 0) { // If the pnode is now free, we need to do some cleanup SDEBUG(cerr << " releasing pnode" << endl); SSUB(SCORE_PNODE); - pnode->typed=false; - } else if (pnode->current_load >= pnode->max_load) { + pnode->remove_current_type(); + } else if (tr->current_load >= tr->max_load) { // If the pnode is still over its max load, reduce the penalty to adjust // for the new load. // XXX - This shouldn't ever happen, right? I don't think we can ever // over-assign to a pnode. - SDEBUG(cerr << " reducing penalty, new load=" << pnode->current_load << - " (>= " << pnode->max_load << ")" << endl); + SDEBUG(cerr << " reducing penalty, new load=" << + pnode->current_type_record->current_load << + " (>= " << pnode->current_type_record->max_load << ")" << endl); SSUB(SCORE_PNODE_PENALTY); vinfo.pnode_load--; violated--; @@ -347,14 +378,6 @@ void remove_node(vvertex vv) violated -= fd_violated; vinfo.desires -= fd_violated; - /* - * If we just unassigned a LAN node, we can delete the pnode entirely - */ - if (vnode->type.compare("lan") == 0) { - SDEBUG(cerr << "Deleting lan node." << endl); - delete_lan_node(pv); - } - SDEBUG(cerr << " new score = " << score << " new violated = " << violated << endl); } @@ -453,53 +476,76 @@ int add_node(vvertex vv,pvertex pv, bool deterministic) SDEBUG(cerr << " vnode type = " << vnode->type << endl); /* - * Set up pnode + * Handle types - first, check to see if the node is capable of taking on the + * vnode's type. If it can with a static type, just do the bookkeeping for + * that static type. Otherwise convert the node to the correct dynamic type, + * failing if we can't for some reason (ie. it already has another type. */ + tb_pnode::type_record *tr; + tb_pnode::types_map::iterator mit = pnode->types.find(vnode->type); - // Figure out the pnode's type - if (!pnode->typed) { - // If this pnode has no type yet, give it one - SDEBUG(cerr << " virgin pnode" << endl); - SDEBUG(cerr << " vtype = " << vnode->type << endl); - - // Remove check assuming at higher level? - // Remove higher level checks? - pnode->max_load=0; - if (pnode->types.find(vnode->type) != pnode->types.end()) { - pnode->max_load = pnode->types[vnode->type]; - } - if (pnode->max_load == 0) { - // didn't find a type - SDEBUG(cerr << " no matching type" << endl); + if (mit == pnode->types.end()) { + // This pnode can't take on the vnode's type - we normally shouldn't get + // here, due to the way we pick pnodes + return 1; + } + + tr = mit->second; + if (tr->is_static) { + // XXX: Scoring??? + if (tr->current_load < tr->max_load) { + } else { return 1; } - - pnode->current_type=vnode->type; - pnode->typed=true; - - SDEBUG(cerr << " matching type found (" <current_type << - ", max = " << pnode->max_load << ")" << endl); } else { - // The pnode already has a type, let's just make sure it's compatible - SDEBUG(cerr << " pnode already has type" << endl); - if (pnode->current_type != vnode->type) { - SDEBUG(cerr << " incompatible types" << endl); - return 1; - } else { - SDEBUG(cerr << " compatible types" << endl); - if (pnode->current_load == pnode->max_load) { - /* XXX - We could ignore this check and let the code - at the end of the routine penalize for going over - load. Failing here seems to work better though. */ - - // XXX is this a bug? do we need to revert the pnode/vnode to - // it's initial state. - SDEBUG(cerr << " node is full" << endl); - cerr << " node is full" << endl; + // Figure out the pnode's type + if (!pnode->typed) { + // If this pnode has no type yet, give it one + SDEBUG(cerr << " virgin pnode" << endl); + SDEBUG(cerr << " vtype = " << vnode->type << endl); + + // Remove check assuming at higher level? + // Remove higher level checks? + if (!pnode->set_current_type(vnode->type)) { + // pnode->max_load=0; + // if (pnode->types.find(vnode->type) != pnode->types.end()) { + // pnode->max_load = pnode->types[vnode->type]; + // } + //if (pnode->max_load == 0) { + // didn't find a type + SDEBUG(cerr << " no matching type" << endl); + //cerr << "Failed due to bad type!" << endl; return 1; } + + // pnode->current_type=vnode->type; + // pnode->typed=true; + + SDEBUG(cerr << " matching type found (" << pnode->current_type << + ", max = " << pnode->current_type_record->max_load << ")" << endl); + } else { + // The pnode already has a type, let's just make sure it's compatible + SDEBUG(cerr << " pnode already has type" << endl); + if (pnode->current_type != vnode->type) { + SDEBUG(cerr << " incompatible types" << endl); + return 1; + } else { + SDEBUG(cerr << " compatible types" << endl); + if (pnode->current_type_record->current_load + == pnode->current_type_record->max_load) { + /* XXX - We could ignore this check and let the code + at the end of the routine penalize for going over + load. Failing here seems to work better though. */ + + // XXX is this a bug? do we need to revert the pnode/vnode to + // it's initial state. + SDEBUG(cerr << " node is full" << endl); + cerr << " node is full" << endl; + return 1; + } + } + } } - } #ifdef PENALIZE_UNUSED_INTERFACES pnode->used_interfaces = 0; @@ -657,9 +703,7 @@ int add_node(vvertex vv,pvertex pv, bool deterministic) // check for no link if (resolution_index == 0) { - //cerr << "No resolutions at all" << endl; - SDEBUG(cerr << " Could not find any resolutions. Trying delay." << - endl); + SDEBUG(cerr << " Could not find any resolutions." << endl); SADD(SCORE_NO_CONNECTION); vlink->no_connection=true; @@ -667,7 +711,6 @@ int add_node(vvertex vv,pvertex pv, bool deterministic) vlink->link_info.type = tb_link_info::LINK_UNKNOWN; violated++; } else { - //cerr << "Some resolutions" << endl; // Check to see if we are fixing a violation if (vlink->no_connection) { SDEBUG(cerr << " Fixing previous violations." << endl); @@ -724,20 +767,12 @@ int add_node(vvertex vv,pvertex pv, bool deterministic) score_link_info(*vedge_it,pnode,dest_pnode); } } -#ifdef AUTO_MIGRATE - if (dest_vnode->type.compare("lan") == 0) { - //cout << "Auto-migrating LAN " << dest_vnode->name << " (because of " - // << vnode->name << ")" << endl; - remove_node(dest_vv); - pvertex lanpv = make_lan_node(dest_vv); - add_node(dest_vv,lanpv,false); - } -#endif } } // finish setting up pnode - pnode->current_load++; + tr->current_load++; + pnode->total_load++; #ifdef PENALIZE_UNUSED_INTERFACES assert(pnode->used_interfaces <= pnode->total_interfaces); @@ -746,16 +781,16 @@ int add_node(vvertex vv,pvertex pv, bool deterministic) vnode->assignment = pv; vnode->assigned = true; - if (pnode->current_load > pnode->max_load) { - SDEBUG(cerr << " load to high - penalty (" << pnode->current_load << - ")" << endl); + if (tr->current_load > tr->max_load) { + SDEBUG(cerr << " load too high - penalty (" << + pnode->current_type_record->current_load << ")" << endl); SADD(SCORE_PNODE_PENALTY); vinfo.pnode_load++; violated++; } else { SDEBUG(cerr << " load is fine" << endl); } - if (pnode->current_load == 1) { + if (pnode->total_load == 1) { SDEBUG(cerr << " new pnode" << endl); SADD(SCORE_PNODE); #ifdef LOAD_BALANCE @@ -802,8 +837,10 @@ int add_node(vvertex vv,pvertex pv, bool deterministic) SDEBUG(cerr << " assignment=" << vnode->assignment << endl); SDEBUG(cerr << " new score=" << score << " new violated=" << violated << endl); - if (pnode->my_class) { - pclass_set(vnode,pnode); + if (!tr->is_static) { + if (pnode->my_class) { + pclass_set(vnode,pnode); + } } return 0; @@ -971,7 +1008,7 @@ void score_link(pedge pe,vedge ve,tb_pnode *src_pnode, tb_pnode *dst_pnode) #endif if (plink->type == tb_plink::PLINK_NORMAL) { - // need too account for three things here, the possiblity of a new plink + // need to account for three things here, the possiblity of a new plink // the user of a new emulated link, and a possible violation. if (vlink->emulated) { plink->emulated++; @@ -994,8 +1031,7 @@ void score_link(pedge pe,vedge ve,tb_pnode *src_pnode, tb_pnode *dst_pnode) } #ifdef FIX_SHARED_INTERFACES if ((! vlink->emulated) && (plink->nonemulated > 1)) { - //cerr << "Penalizing overused link" << endl; - assert(false); + //assert(false); SADD(SCORE_DIRECT_LINK_PENALTY); vinfo.link_users++; violated++; @@ -1250,6 +1286,10 @@ double fd_score(tb_vnode *vnode,tb_pnode *pnode,int &fd_violated) * connect the LAN node to. Specifically, it connects it to the switch * which will maximize the number of intra (rather than inter) links for * assigned adjancent nodes of vv. + * + * NOTE: This function is deprecated, since there are no longer special + * physical LAN nodes. + * */ pvertex make_lan_node(vvertex vv) { @@ -1295,10 +1335,8 @@ pvertex make_lan_node(vvertex vv) pvertex pv = add_vertex(PG); tb_pnode *p = new tb_pnode(vnode->name); put(pvertex_pmap,pv,p); - p->typed = true; - p->current_type = "lan"; - p->max_load = 1; - p->types["lan"] = 1; + p->types["lan"] = new tb_pnode::type_record(1,false); + p->set_current_type("lan"); // If the below is false then we have an orphaned lan node which will // quickly be destroyed when add_node fails. @@ -1333,6 +1371,10 @@ pvertex make_lan_node(vvertex vv) /* delete_lan_node(pvertex pv) * Removes the physical lan node and the physical lan link. Assumes that * nothing is assigned to it. + * + * NOTE: This function is deprecated, since there are no longer special + * physical LAN nodes. + * */ void delete_lan_node(pvertex pv) { diff --git a/assign/solution.cc b/assign/solution.cc index 4b10586f26e9de1cc529f60d8c25493e085746e5..851645b6c4bfdacd146dde225c7d84382991283e 100644 --- a/assign/solution.cc +++ b/assign/solution.cc @@ -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()); diff --git a/tbsetup/assign_wrapper.in b/tbsetup/assign_wrapper.in index 59bda89b44ac03d897963d06ee5951132f6de419..78e177e9b4cd7c684cb4cb6662a550996a82edc1 100644 --- a/tbsetup/assign_wrapper.in +++ b/tbsetup/assign_wrapper.in @@ -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 diff --git a/tbsetup/ptopgen.in b/tbsetup/ptopgen.in index 4e6cf8f14664cb16a07f6517b0cf1b69f2d5d38e..3c5674d0c8250ff30b8cca71829070ad6d344bae 100644 --- a/tbsetup/ptopgen.in +++ b/tbsetup/ptopgen.in @@ -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;