Commit 8eaec842 authored by Robert Ricci's avatar Robert Ricci

Add support for the set-type-limit command in the ptop file.

It looks like this:
set-type-limit <type> <count>

This can be placed anywhere in the ptop file.  It limits the number of
physical nodes of a given type that an experimenter is allowed to use.

For example, we may limit a user to 10 PCs, or 5 pc850s. In the latter
case, if the experimenter had simply asked for 10 generic PCs, then we
will try to find them some mapping of nodes that uses types of PCs
other than pc850s.

Added a precheck to tell the user up-front if they asked for more
nodes than they are allowed to use of a given type.
parent 9b4a2c20
......@@ -54,9 +54,6 @@ tb_vgraph VG;
tb_vgraph_vertex_pmap vvertex_pmap = get(vertex_data, VG);
tb_vgraph_edge_pmap vedge_pmap = get(edge_data, VG);
// A simple list of physical types.
name_count_map ptypes;
// List of virtual types by name.
name_count_map vtypes;
name_list_map vclasses;
......@@ -127,6 +124,9 @@ double use_connected_pnode_find = 0.0f;
double absbest;
int absbestviolated, iters, iters_to_best;
// Map of all physical types in use in the system
tb_ptype_map ptypes;
/*
* Internal functions
*/
......@@ -353,17 +353,25 @@ int type_precheck() {
vtype_it != vtypes.end();++vtype_it) {
// Check to see if there were any pnodes of the type at all
name_count_map::iterator ptype_it = ptypes.find(vtype_it->first);
tb_ptype_map::iterator ptype_it = ptypes.find(vtype_it->first);
if (ptype_it == ptypes.end()) {
cout << " *** No physical nodes of type " << vtype_it->first
<< " found" << endl;
ok = false;
} else {
// Okay, there are some - are there enough?
if (ptype_it->second < vtype_it->second) {
if (ptype_it->second->pnode_slots() < vtype_it->second) {
cout << " *** " << vtype_it->second << " nodes of type " <<
vtype_it->first << " requested, but only "
<< ptype_it->second << " found" << endl;
<< ptype_it->second->pnode_slots() << " found" << endl;
ok = false;
}
// Okay, there are enough - but are we allowed to use them?
if (ptype_it->second->maxusers() &&
(ptype_it->second->maxusers() < vtype_it->second)) {
cout << " *** " << vtype_it->second << " nodes of type " <<
vtype_it->first << " requested, but you are only " <<
"allowed to use " << ptype_it->second->maxusers() << endl;
ok = false;
}
}
......
......@@ -127,6 +127,9 @@ static float SCORE_TRIVIAL_MIX = 0.5; /* Cost of mixing trivial and non-trivial
links */
static float SCORE_SUBNODE = 0.5; /* Cost of not properly assigning subnodes */
static float SCORE_MAX_TYPES = 0.15; /* Cost of going over type limits - low
* enough that assign ususally picks this
* over leaving a node unassigned */
// The following are used to weight possible link resolutions. Higher
// numbers mean a more likely resolution. Trivial resolutions are always
......
......@@ -17,7 +17,6 @@ using namespace boost;
#include "parser.h"
extern name_pvertex_map pname2vertex;
extern name_count_map ptypes;
#define ptop_error(s) errors++;cout << "PTOP:" << line << ": " << s << endl; exit(EXIT_FATAL)
#define ptop_error_noline(s) errors++;cout << "PTOP: " << s << endl
......@@ -98,15 +97,21 @@ int parse_ptop(tb_pgraph &PG, tb_sgraph &SG, istream& i)
ptop_error("Bad node line, bad load: " << load << ".");
iload = 1;
}
/*
* Make a tb_ptype structure for this guy - or just add this node to
* it if it already exists
*/
if (ptypes.find(type) == ptypes.end()) {
ptypes[type] = iload;
} else {
ptypes[type] += iload;
ptypes[type] = new tb_ptype(type);
}
ptypes[type]->add_slots(iload);
tb_ptype *ptype = ptypes[type];
if (type.compare("switch") == 0) {
isswitch = true;
p->is_switch = true;
p->types["switch"] = new tb_pnode::type_record(1,false);
p->types["switch"] = new tb_pnode::type_record(1,false,ptype);
svertex sv = add_vertex(SG);
tb_switch *s = new tb_switch();
put(svertex_pmap,sv,s);
......@@ -114,8 +119,9 @@ int parse_ptop(tb_pgraph &PG, tb_sgraph &SG, istream& i)
p->sgraph_switch = sv;
p->switches.insert(pv);
} else {
p->types[type] = new tb_pnode::type_record(iload,is_static);
p->types[type] = new tb_pnode::type_record(iload,is_static,ptype);
}
p->type_list.push_back(p->types[type]);
}
for (i=i+1;(i<parsed_line.size()) && (parsed_line[i].compare("-")) ;++i) {
crope feature,cost;
......@@ -294,6 +300,23 @@ int parse_ptop(tb_pgraph &PG, tb_sgraph &SG, istream& i)
#endif
}
}
} else if (command.compare("set-type-limit") == 0) {
if (parsed_line.size() != 3) {
ptop_error("Bad set-type-limit line, requires two arguments.");
}
crope type = parsed_line[1];
int max;
if (sscanf(parsed_line[2].c_str(),"%u",&max) != 1) {
ptop_error("Bad number argument: " << parsed_line[2] << ".");
}
// Look for a record for this ptype - create it if it doesn't exist
if (ptypes.find(type) == ptypes.end()) {
ptypes[type] = new tb_ptype(type);
}
ptypes[type]->set_max_users(max);
} else {
ptop_error("Unknown directive: " << command << ".");
}
......
......@@ -95,6 +95,52 @@ extern tb_pgraph_edge_pmap pedge_pmap;
extern tb_sgraph_vertex_pmap svertex_pmap;
extern tb_sgraph_edge_pmap sedge_pmap;
/*
* Represents a physical type
*/
class tb_ptype {
public:
tb_ptype(crope _name) : users(0), max_users(0), my_name(_name), slots(0)
{ ; }
inline crope name() const { return my_name; };
inline int pnode_slots() const { return slots; };
inline int maxusers() const { return max_users; };
inline int add_users(int count = 1) {
int oldusers = users;
users = users + count;
if (max_users && (oldusers <= max_users) && (users > max_users)) {
return 1;
} else {
return 0;
}
}
inline int remove_users(int count = 1) {
int oldusers = users;
users = users - count;
assert(users >= 0);
if (max_users && (oldusers > max_users) && (users <= max_users)) {
return 1;
} else {
return 0;
}
}
inline void set_max_users(int users) {
max_users = users;
}
inline void add_slots(int additional_slots) {
slots += additional_slots;
}
private:
crope my_name;
/* How many users are using this type right now */
int users;
/* The maximum number of nodes of this type we're allowed to use */
int max_users;
/* How many slots of this type are available in the physical topology */
int slots;
};
class tb_pnode {
public:
tb_pnode() { tb_pnode("(unnamed)"); }
......@@ -110,13 +156,16 @@ public:
class type_record {
public:
type_record(int _max_load, bool _is_static) :
type_record(int _max_load, bool _is_static, tb_ptype *_ptype) :
max_load(_max_load), current_load(0),
is_static(_is_static) { ; }
is_static(_is_static), ptype(_ptype) { ; }
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
tb_ptype *ptype; // Pointer to the global ptype strucutre for
// type
bool operator==(const type_record &b) {
return ((max_load == b.max_load) && (is_static == b.is_static));
}
......@@ -129,9 +178,15 @@ public:
}
};
// contains max nodes for each type
// Contains max nodes for each type
// NOTE: Parallel data strucure, see below!
typedef hash_map<crope,type_record*> types_map;
types_map types;
// Same as above, but a list for fast iteration
// If you touch the above list, you must touch this one too
typedef list<type_record*> types_list;
types_list type_list;
// contains cost of each feature
node_feature_set features;
......@@ -348,4 +403,8 @@ int parse_ptop(tb_pgraph &PG, tb_sgraph &SG, istream& i);
/* The physical graph, defined in assign.cc */
extern tb_pgraph PG;
/* A map of all tb_ptypes currently in existance */
typedef map<crope,tb_ptype*> tb_ptype_map;
extern tb_ptype_map ptypes;
#endif
......@@ -493,6 +493,17 @@ void remove_node(vvertex vv)
SDEBUG(cerr << " releasing pnode" << endl);
SSUB(SCORE_PNODE);
pnode->remove_current_type();
// ptypes
tb_pnode::types_list::iterator lit = pnode->type_list.begin();
while (lit != pnode->type_list.end()) {
int removed_violations = (*lit)->ptype->remove_users((*lit)->max_load);
if (removed_violations) {
SSUB(SCORE_MAX_TYPES * removed_violations);
violated -= removed_violations;
vinfo.max_types -= removed_violations;
}
lit++;
}
} else if (old_load > tr->max_load) {
// If the pnode was over its load, remove the penalties for the nodes we
// just removed, down to the max_load.
......@@ -1125,6 +1136,17 @@ int add_node(vvertex vv,pvertex pv, bool deterministic, bool is_fixed)
if (old_total_load == 0) {
SDEBUG(cerr << " new pnode" << endl);
SADD(SCORE_PNODE);
// ptypes
tb_pnode::types_list::iterator lit = pnode->type_list.begin();
while (lit != pnode->type_list.end()) {
int new_violations = (*lit)->ptype->add_users((*lit)->max_load);
if (new_violations) {
SADD(SCORE_MAX_TYPES * new_violations);
violated += new_violations;
vinfo.max_types += new_violations;
}
lit++;
}
}
#ifdef LOAD_BALANCE
SSUB(SCORE_PNODE * (powf(1 + ((pnode->current_load-1) * 1.0)/pnode->max_load,2)));
......
......@@ -39,6 +39,7 @@ class violated_info {
o << " delay: " << vinfo.delay << endl;
o << " trivial mix: " << vinfo.trivial_mix << endl;
o << " subnodes: " << vinfo.subnodes << endl;
o << " max_types: " << vinfo.max_types << endl;
#ifdef FIX_PLINK_ENDPOINTS
o << " endpoints: " << vinfo.incorrect_endpoints << endl;
#endif
......@@ -49,7 +50,8 @@ class violated_info {
violated_info():
unassigned(0), pnode_load(0), no_connection(0), link_users(0),
bandwidth(0), desires(0), vclass(0), delay(0),
incorrect_endpoints(0), trivial_mix(0), subnodes(0) { }
incorrect_endpoints(0), trivial_mix(0), subnodes(0), max_types(0)
{ }
int unassigned;
int pnode_load;
......@@ -62,6 +64,7 @@ class violated_info {
int incorrect_endpoints;
int trivial_mix;
int subnodes;
int max_types;
};
extern double score;
......
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