All new accounts created on Gitlab now require administrator approval. If you invite any collaborators, please let Flux staff know so they can approve the accounts.

Commit 8078740b authored by Christopher Alfeld's avatar Christopher Alfeld

This is a nearly complete rewrite of the assign interswitch code. Assign

now precomputers the shortest path between all pairs of switches and uses
this to computer paths through the switch fabric.  In the process of
writing this I also removed the limitations of two switch hops.  Packets
can now travel through any number of switches to reach their destination.
Of course, the longer the path the more it costs so assign will prefer
shorter paths.

Also did various other tweaks in the process.  We now use strings almost
everywhere instead of char*'s and the makefile is cleaner.
parent 5f414bc0
......@@ -16,15 +16,16 @@ LEDA=@LEDA@
OBJS=score.o parse_top.o parse_ptop.o config.o
LIBS+=-L${LEDA} -lD3 -lW -lP -lG -lL -L/usr/X11R6/lib -lX11 -lm -L.
LDFLAGS+= -O3 -fomit-frame-pointer -m486
CXXFLAGS = -I${LEDA}/incl -fomit-frame-pointer -m486
LDFLAGS+= -O3
CXXFLAGS = -I${LEDA}/incl
# Pick one of the following:
CXXFLAGS += -Wall -O3
#CXXFLAGS += -O0 -g -Wall -DVERBOSE #-DSTATS
#CXXFLAGS += -O0 -g -Wall -DVERBOSE -DGRAPH_DEBUG #=DSTATS
#CXXFLAGS += -O0 -g -Wall -DVERBOSE -DSCORE_DEBUG #-DSTATS
#CXXFLAGS += -O0 -g -Wall -DVERBOSE -DSCORE_DEBUG -DSCORE_DEBUG_MORE #-DSTATS
#CXXFLAGS += -O0 -g -Wall -DVERBOSE
#CXXFLAGS += -O0 -g -Wall -DVERBOSE -DSCORE_DEBUG
#CXXFLAGS += -O0 -g -Wall -DVERBOSE -DSCORE_DEBUG -DSCORE_DEBUG_MORE
#CXXFLAGS += -DSTATS
# If you're looking to turn on or off USE_OPTIMAL, its now a cmdline
# option. Use OP={0,1} on the command line at run time... :)
......@@ -34,12 +35,6 @@ DEPLIBS=$(OBJS)
assign: ${DEPLIBS} ${OBJS} assign.o
${CXX} assign.o -o assign ${LIBS} $(OBJS) ${LDFLAGS}
assign_p: assign.po $(DEPLIBS) $(POBJS)
${CXX} assign.po -pg -g -o assign_p ${LIBS} $(POBJS)
assign.po: assign.cc
${CXX} -c -pg -g -o assign.po assign.cc ${CXXFLAGS}
install: $(INSTALL_LIBEXECDIR)/assign
clean:
......
#include <LEDA/graph_alg.h>
#include <LEDA/graphwin.h>
#include <LEDA/ugraph.h>
#include <LEDA/dictionary.h>
#include <LEDA/map.h>
#include <LEDA/graph_iterator.h>
......@@ -35,8 +36,14 @@ void dump_options(const char *str, struct config_param cparams[], int nparams);
#define OPTIMAL_SCORE(edges,nodes) 0
#endif
tb_pgraph PG(1,1);
tb_vgraph G(1,1);
tb_sgraph SG;
edge_array<int> edge_costs;
typedef node_array<int> switch_distance_array;
typedef node_array<edge> switch_pred_array;
node_array<switch_distance_array> switch_distances;
node_array<switch_pred_array> switch_preds;
tb_pgraph PG;
tb_vgraph G;
/* How can we chop things up? */
#define PARTITION_BY_ANNEALING 0
......@@ -63,7 +70,7 @@ extern node_array<int> switch_index;
node_pq<int> unassigned_nodes(G);
int parse_top(tb_vgraph &G, istream& i);
int parse_ptop(tb_pgraph &G, istream& i);
int parse_ptop(tb_pgraph &PG, tb_sgraph &SG, istream& i);
/*
* Basic simulated annealing parameters:
......@@ -364,6 +371,17 @@ void usage() {
);
}
int mst_comp(const edge &A,const edge &B)
{
edge pA,pB;
pA = SG[A].mate;
pB = SG[B].mate;
// Highbandwidth = low score
if (PG[pA].bandwidth > PG[pB].bandwidth) return -1;
if (PG[pA].bandwidth < PG[pB].bandwidth) return 1;
return 0;
}
void print_solution()
{
node n;
......@@ -375,11 +393,13 @@ void print_solution()
} else {
node pnode = pnodes[G[n].posistion];
tb_pnode &pnoder = PG[pnode];
cout << G[n].name << " " << (pnoder.the_switch ?
PG[pnoder.the_switch].name :
"NO_SWITCH") <<
" " << pnoder.name << endl;
cout << G[n].name << " ";
if (pnoder.the_switch) {
cout << PG[pnoder.the_switch].name;
} else {
cout << "NO_SWITCH";
}
cout << " " << pnoder.name << endl;
}
}
cout << "End Nodes" << endl;
......@@ -387,33 +407,30 @@ void print_solution()
edge e;
forall_edges(e,G) {
tb_vlink &v = G[e];
tb_plink *p,*p2,*p3,*p4;
cout << G[e].name;
if (v.type == tb_vlink::LINK_DIRECT) {
p = &PG[v.plink];
cout << " direct " << PG[v.plink].name << " (" <<
p->srcmac << "," << p->dstmac << ")" << endl;
tb_plink &p = PG[v.plink];
cout << " direct " << p.name << " (" <<
p.srcmac << "," << p.dstmac << ")" << endl;
} else if (v.type == tb_vlink::LINK_INTRASWITCH) {
p = &PG[v.plink];
p2 = &PG[v.plink_two];
cout << " intraswitch " << PG[v.plink].name << " (" <<
p->srcmac << "," << p->dstmac << ") " <<
PG[v.plink_two].name << " (" << p2->srcmac << "," << p2->dstmac <<
tb_plink &p = PG[v.plink];
tb_plink &p2 = PG[v.plink_two];
cout << " intraswitch " << p.name << " (" <<
p.srcmac << "," << p.dstmac << ") " <<
p2.name << " (" << p2.srcmac << "," << p2.dstmac <<
")" << endl;
} else if (v.type == tb_vlink::LINK_INTERSWITCH) {
p = &PG[v.plink];
p3 = &PG[v.plink_local_one];
p4 = &PG[v.plink_local_two];
cout << " interswitch " << PG[v.plink].name << " (" <<
p->srcmac << "," << p->dstmac << ")";
if (v.plink_two) {
p2 = &PG[v.plink_two];
cout << " " << PG[v.plink_two].name << " (" << p2->srcmac << "," <<
p2->dstmac << ")";
cout << " interswitch ";
edge e;
tb_plink &lp = PG[v.plink_local_one];
tb_plink &lp2 = PG[v.plink_local_two];
cout << lp.name << " (" << lp.srcmac << "," << lp.dstmac << ")";
forall(e,v.path) {
tb_plink &p = PG[e];
cout << " " << p.name << " (" << p.srcmac << "," << p.dstmac << ")";
}
cout << " " << PG[v.plink_local_one].name << " (" << p3->srcmac << "," <<
p3->dstmac << ") " << PG[v.plink_local_two].name << " (" <<
p4->srcmac << "," << p4->dstmac << ")" << endl;
cout << " " << lp2.name << " (" << lp2.srcmac << "," <<
lp2.dstmac << ")" << endl;
} else {
cout << "Unknown link type" << endl;
}
......@@ -491,10 +508,46 @@ int main(int argc, char **argv)
cerr << "Error opening file: " << topofile << endl;
exit(-1);
}
nparts = parse_ptop(PG,ptopfile);
nparts = parse_ptop(PG,SG,ptopfile);
cout << "Nparts: " << nparts << endl;
}
cout << "Initializing data structures." << endl;
edge_costs.init(SG);
switch_distances.init(SG);
switch_preds.init(SG);
cout << "Calculating shortest paths on switch fabric." << endl;
edge ed;
forall_edges(ed,SG) {
edge_costs[ed] = 10000-PG[SG[ed].mate].bandwidth;
#ifdef SCORE_DEBUG
cerr << " " << PG[SG[ed].mate].name << " " << edge_costs[ed] << endl;
#endif
}
node sw;
forall_nodes(sw,SG) {
switch_distances[sw].init(SG);
switch_preds[sw].init(SG);
DIJKSTRA_T(SG,sw,edge_costs,
switch_distances[sw],switch_preds[sw]);
#ifdef SCORE_DEBUG
cerr << "Source " << PG[SG[sw].mate].name << endl;
node dsw;
forall_nodes(dsw,SG) {
cerr << " " << PG[SG[dsw].mate].name;
int dist = switch_distances[sw][dsw];
cerr << " dist " << dist;
edge de = switch_preds[sw][dsw];
if (de == nil) {
cerr << " pred nil" << endl;
} else {
cerr << " pred " << PG[SG[de].mate].name << endl;
}
}
#endif
}
}
cout << "Annealing!" << endl;
batch();
print_solution();
......
......@@ -12,6 +12,7 @@
#include <LEDA/graph_alg.h>
#include <LEDA/graphwin.h>
#include <LEDA/ugraph.h>
#include <LEDA/dictionary.h>
#include <LEDA/map.h>
#include <LEDA/graph_iterator.h>
......@@ -26,7 +27,7 @@
extern node pnodes[MAX_PNODES]; // int -> node map
node_array<int> switch_index;
int parse_ptop(tb_pgraph &PG, istream& i)
int parse_ptop(tb_pgraph &PG, tb_sgraph &SG, istream& i)
{
int switchi=0;
dictionary<string, node> nmap;
......@@ -66,7 +67,7 @@ int parse_ptop(tb_pgraph &PG, istream& i)
#ifdef GRAPH_DEBUG
cout << "Found phys. node '"<<snode<<"'\n";
#endif
PG[no1].name=strdup(snode);
PG[no1].name=string(snode);
PG[no1].typed = false;
PG[no1].max_load = 0;
PG[no1].current_load = 0;
......@@ -89,6 +90,9 @@ int parse_ptop(tb_pgraph &PG, istream& i)
isswitch = 1;
PG[no1].types.insert(stype,1);
PG[no1].the_switch = no1;
node sw = SG.new_node();
SG[sw].mate = no1;
PG[no1].sgraph_switch = sw;
switch_index[no1] = switchi++;
} else {
PG[no1].types.insert(stype,iload);
......@@ -118,40 +122,49 @@ int parse_ptop(tb_pgraph &PG, istream& i)
!= 5) {
fprintf(stderr, "bad link line: %s\n", inbuf);
} else {
string linkname(lname);
char *snode,*smac;
char *dnode,*dmac;
smac = n1;
dmac = n2;
snode = strsep(&smac,":");
dnode = strsep(&dmac,":");
string s1(snode);
string s2(dnode);
if (nmap.lookup(s1) == nil) {
if (nmap.lookup(snode) == nil) {
fprintf(stderr,"PTOP error: Unknown source node %s\n",snode);
exit(1);
}
if (nmap.lookup(s2) == nil) {
if (nmap.lookup(dnode) == nil) {
fprintf(stderr,"PTOP error: Unknown destination node %s\n",dnode);
exit(1);
}
node node1 = nmap.access(s1);
node node2 = nmap.access(s2);
node node1 = nmap.access(snode);
node node2 = nmap.access(dnode);
#define ISSWITCH(n) (PG[n].types.lookup("switch") != nil)
for (int i = 0; i < num; ++i) {
ed1=PG.new_edge(node1, node2);
PG[ed1].bandwidth=size;
PG[ed1].bw_used=0;
PG[ed1].users=0;
PG[ed1].name=strdup(lname);
PG[ed1].name=linkname;
if (smac)
PG[ed1].srcmac = strdup(smac);
PG[ed1].srcmac = string(smac);
else
PG[ed1].srcmac = NULL;
PG[ed1].srcmac = string("(null)");
if (dmac)
PG[ed1].dstmac = strdup(dmac);
PG[ed1].dstmac = string(dmac);
else
PG[ed1].dstmac = NULL;
PG[ed1].dstmac = string("(null)");
if (ISSWITCH(node1) && ISSWITCH(node2)) {
if (i != 0) {
cout <<
"Warning: Extra links between switches will be ignored." <<
endl;
}
edge swedge = SG.new_edge(PG[node1].sgraph_switch,
PG[node2].sgraph_switch);
SG[swedge].mate = ed1;
}
}
#define ISSWITCH(n) (PG[n].types.lookup("switch") != nil)
if (ISSWITCH(node1) &&
! ISSWITCH(node2))
PG[node2].the_switch = node1;
......
......@@ -7,6 +7,7 @@
#include <stdio.h>
#include <LEDA/graph_alg.h>
#include <LEDA/graphwin.h>
#include <LEDA/ugraph.h>
#include <LEDA/dictionary.h>
#include <LEDA/map.h>
#include <LEDA/graph_iterator.h>
......@@ -53,7 +54,7 @@ int parse_top(tb_vgraph &G, istream& i)
#ifdef GRAPH_DEBUG
cout << "Found virt. node '"<<scur<<"'\n";
#endif
G[no1].name=strdup(scur);
G[no1].name=string(scur);
G[no1].posistion = 0;
G[no1].no_connections=0;
nmap.insert(s1, no1);
......@@ -89,7 +90,7 @@ int parse_top(tb_vgraph &G, istream& i)
G[e].type = tb_vlink::LINK_UNKNOWN;
G[e].plink = NULL;
G[e].plink_two = NULL;
G[e].name = strdup(lname);
G[e].name = string(lname);
}
}
else {
......
......@@ -21,9 +21,29 @@ public:
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
char *name;
string name;
node the_switch; // the switch the node is attached to
// this is in the physical graph.
int pnodes_used; // for switch nodes
node sgraph_switch; // only for switches, the corresponding
// sgraph switch.
};
class tb_switch {
public:
tb_switch() {;}
friend ostream &operator<<(ostream &o, const tb_switch& node)
{
o << "unimplemented osteam << for tb_switch" << endl;
return o;
}
friend istream &operator>>(istream &i, const tb_switch& node)
{
return i;
}
node mate; // match in PG
};
class tb_plink {
......@@ -31,7 +51,7 @@ public:
tb_plink() {;}
friend ostream &operator<<(ostream &o, const tb_plink& edge)
{
o << "unimplemeted ostream << for tb_plinke " << endl;
o << "unimplemeted ostream << for tb_plink " << endl;
return o;
}
friend istream & operator>>(istream &i, const tb_plink& edge)
......@@ -41,17 +61,26 @@ public:
int bandwidth; // maximum bandwidth of this link
int bw_used; // how much is used
int users; // number of users in direct links
char *srcmac,*dstmac; // source and destination MAC addresses.
char *name; // The name
string srcmac,dstmac; // source and destination MAC addresses.
string name; // The name
};
class tb_route {
class tb_slink {
public:
private:
int length;
list<tb_plink> links;
tb_slink() {;}
friend ostream &operator<<(ostream &o, const tb_slink& edge)
{
o << "unimplemeted ostream << for tb_psink " << endl;
return o;
}
friend istream & operator>>(istream &i, const tb_slink& edge)
{
return i;
}
edge mate; // match in PG
};
typedef GRAPH<tb_pnode,tb_plink> tb_pgraph;
typedef UGRAPH<tb_switch,tb_slink> tb_sgraph;
#endif
......@@ -10,6 +10,7 @@
// Not sure we need all these LEDA includes.
#include <LEDA/graph_alg.h>
#include <LEDA/ugraph.h>
#include <LEDA/graphwin.h>
#include <LEDA/dictionary.h>
#include <LEDA/map.h>
......@@ -30,6 +31,9 @@
#include "assert.h"
typedef node_array<edge> switch_pred_array;
extern node_array<switch_pred_array> switch_preds;
float score; // The score of the current mapping
int violated; // How many times the restrictions
// have been violated.
......@@ -40,13 +44,14 @@ violated_info vinfo; // specific info on violations
extern tb_vgraph G; // virtual graph
extern tb_pgraph PG; // physical grpaph
extern tb_sgraph SG; // switch fabric
int find_interswitch_path(node src,node dst,int bandwidth,edge *f,edge *s);
edge direct_link(node a,node b);
void score_link(edge e,edge v,bool interswitch);
void unscore_link(edge e,edge v,bool interswitch);
edge find_link_to_switch(node n);
int find_intraswitch_path(node src,node dst,edge *first,edge *second);
int find_interswitch_path(node src,node dst,int bandwidth,list<edge> &L);
#ifdef SCORE_DEBUG_MORE
#define SADD(amount) fprintf(stderr,"SADD: %s = %.2f\n",#amount,amount);score+=amount
......@@ -124,7 +129,7 @@ void remove_node(node n)
tb_pnode &pnoder = PG[pnode];
#ifdef SCORE_DEBUG
fprintf(stderr,"SCORE: remove_node(%s)\n",vnoder.name);
cerr << "SCORE: remove_node(" << vnoder.name << ")\n";
fprintf(stderr," no_connections = %d\n",vnoder.no_connections);
#endif
......@@ -146,7 +151,7 @@ void remove_node(node n)
vdst = G.source(e);
vdstr=&G[vdst];
#ifdef SCORE_DEBUG
fprintf(stderr," edge to %s\n",vdstr->name);
cerr << " edge to " << vdstr->name << endl;
#endif
if (vdstr->posistion == 0) continue;
if (vlink->type == tb_vlink::LINK_DIRECT) {
......@@ -159,28 +164,19 @@ void remove_node(node n)
// INTERSWITCH LINK
pdst=pnodes[vdstr->posistion];
pdstr=&PG[pdst];
edge first,second;
first = vlink->plink;
second = vlink->plink_two;
#ifdef SCORE_DEBUG
node through;
if (PG.source(first) == pnode)
through = PG.target(first);
else
through = PG.source(first);
fprintf(stderr," interswitch link (through %s)\n",
PG[through].name);
cerr << " interswitch link\n";
#endif
unscore_link(first,e,true);
if (second) unscore_link(second,e,true);
edge cur;
forall(cur,G[e].path) {
SSUB(SCORE_INTERSWITCH_LINK);
unscore_link(cur,e,true);
}
G[e].path.clear();
unscore_link(vlink->plink_local_one,e,false);
unscore_link(vlink->plink_local_two,e,false);
// adjust score apropriately.
SSUB(SCORE_INTERSWITCH_LINK);
if (second)
SSUB(SCORE_INTERSWITCH_LINK);
} else if (vlink->type == tb_vlink::LINK_INTRASWITCH) {
// INTRASWITCH LINK
#ifdef SCORE_DEBUG
......@@ -215,7 +211,7 @@ void remove_node(node n)
if (the_switch) {
if ((--PG[the_switch].pnodes_used) == 0) {
#ifdef SCORE_DEBUG
fprintf(stderr," releasing switch %s\n",PG[the_switch].name);
cerr << " releasing switch " << PG[the_switch].name << endl;
#endif
// release switch
SSUB(SCORE_SWITCH);
......@@ -296,11 +292,14 @@ int add_node(node n,int ploc)
tb_pnode &pnoder=PG[pnode];
#ifdef SCORE_DEBUG
fprintf(stderr,"SCORE: add_node(%s,%s[%d])\n",
vnoder.name,pnoder.name,ploc);
cerr << "SCORE: add_node(" << vnoder.name << "," << pnoder.name << "[" << ploc << "])\n";
fprintf(stderr," vnode type = ");
cerr << vnoder.type << " pnode switch = ";
cerr << (pnoder.the_switch ? PG[pnoder.the_switch].name : "No switch");
if (pnoder.the_switch) {
cerr << PG[pnoder.the_switch].name;
} else {
cerr << "No switch";
}
cerr << endl;
#endif
......@@ -374,7 +373,7 @@ int add_node(node n,int ploc)
assert(dst != n);
assert(&dstr != &vnoder);
#ifdef SCORE_DEBUG
fprintf(stderr," edge to %s\n",dstr.name);
cerr << " edge to " << dstr.name << endl;
#endif
if (dstr.posistion != 0) {
......@@ -383,7 +382,7 @@ int add_node(node n,int ploc)
tb_pnode &dpnoder=PG[dpnode];
#ifdef SCORE_DEBUG
fprintf(stderr," goes to %s\n",dpnoder.name);
cerr << " goes to " << dpnoder.name << endl;
#endif
if ((pedge=direct_link(dpnode,pnode)) != NULL) {
......@@ -423,16 +422,13 @@ int add_node(node n,int ploc)
score_link(second,e,false);
} else {
// try to find interswitch
// XXX - need to do user and bandwidth checking for links to
// and from node as well!
#ifdef SCORE_DEBUG
fprintf(stderr," looking for interswitch link\n");
cerr << " looking for interswitch link " <<
PG[pnoder.the_switch].name << " " <<
PG[dpnoder.the_switch].name << endl;
#endif
edge first,second;
first=second=NULL;
if (find_interswitch_path(pnoder.the_switch,dpnoder.the_switch,
er->bandwidth,
&first,&second) == 0) {
er->bandwidth,er->path) == 0) {
#ifdef SCORE_DEBUG
fprintf(stderr," could not find path - no connection\n");
#endif
......@@ -447,18 +443,18 @@ int add_node(node n,int ploc)
violated++;
} else {
#ifdef SCORE_DEBUG
fprintf(stderr," found interswitch link (%p, %p)\n",first,second);
fprintf(stderr," found interswitch link\n");
#endif
er->type=tb_vlink::LINK_INTERSWITCH;
SADD(SCORE_INTERSWITCH_LINK);
if (second)
SADD(SCORE_INTERSWITCH_LINK);
score_link(first,e,true);
if (second) score_link(second,e,true);
er->plink = first;
er->plink_two = second;
edge cur;
forall(cur,er->path) {
SADD(SCORE_INTERSWITCH_LINK);
#ifdef SCORE_DEBUG
cerr << " " << PG[cur].name << endl;
#endif
score_link(cur,e,true);
}
er->plink_local_one = find_link_to_switch(pnode);
assert(er->plink_local_one != NULL);
......@@ -630,82 +626,39 @@ int find_intraswitch_path(node src,node dst,edge *first,edge *second)
return 1;
}
// this needs to find a path between switches src and dst (in PG).
// needs to return the best of all possible
// best =
// shorter is better
// lowest % of bw used after link added is better.
int find_interswitch_path(node src,node dst,int bandwidth,edge *f,edge *s)
// this uses the shortest paths calculated over the switch graph to
// find a path between src and dst. It passes out list<edge>, a list
// of the edges used. (assumed to be empty to begin with).
// Returns 0 if no path exists and 1 otherwise.
int find_interswitch_path(node src,node dst,int bandwidth,list<edge> &L)
{
edge best_first,best_second;
float best_bw;
float bw;
int best_length = 1000;
// We know the shortest path from src to node already. It's stored
// in switch_preds[src] and is a node_array<edge>. Let P be this
// array. We can trace our shortest path by starting at the end and
// following the pred edges back until we reach src. We need to be
// careful though because the switch_preds deals with elements of SG
// and we have elements of PG.
if ((src == nil) || (dst == nil)) {return 0;}
best_bw=100.0;
best_first = best_second = NULL;
if (!src || ! dst) return 0;
// try to find a path to the destination
node ldst,ldstb;
edge first,second;
#ifdef SCORE_DEBUG
tb_pnode *ldstr,*ldstbr;
tb_plink *firstr,*secondr;
#endif
forall_inout_edges(first,src) {
ldst = PG.target(first);
if (ldst == src)
ldst = PG.source(first);
#ifdef SCORE_DEBUG
ldstr = &PG[ldst];
firstr = &PG[first];
#endif
if (ldst == dst) {
// we've found a path, it's just firstedge
if (first)
bw = (PG[first].bw_used+bandwidth)/PG[first].bandwidth;
if (! best_first || bw < best_bw) {
best_first = first;
best_bw = bw;
best_second = NULL;
best_length = 1;
}
}
forall_inout_edges(second,ldst) {
ldstb = PG.target(second);
if (ldstb == ldst)
ldstb = PG.source(second);
#ifdef SCORE_DEBUG
ldstbr = &PG[ldstb];
secondr = &PG[second];
#endif