Commit 7de8df4f authored by Robert Ricci's avatar Robert Ricci

Merge in the version of assign from the paper branch.

In addition to assign, assign_wrapper and ptopgen have been modified
to output the new formats used by assign.
parent c63f476a
#
# EMULAB-COPYRIGHT
# Copyright (c) 2000-2002 University of Utah and the Flux Group.
# All rights reserved.
# Insert Copyright Here.
#
SRCDIR = @srcdir@
TESTBED_SRCDIR = @top_srcdir@
OBJDIR = ..
SUBDIR = assign
#
# Support for optional assign binary to avoid LEDA restrictions
#
ASSIGNBINARY = @ASSIGN@
include $(OBJDIR)/Makeconf
all: assign
include $(TESTBED_SRCDIR)/GNUmakerules
LEDA=@LEDA@
OBJS=parse_top.o parse_ptop.o assign.o pclass.o vclass.o config.o score.o \
parser.o
LIBS+= -lm
LDFLAGS+= -pipe -O3
CXXFLAGS = -pipe -I/usr/local/include -ftemplate-depth-30
OBJS=score.o parse_top.o parse_ptop.o config.o pclass.o vclass.o
LIBS+=-L${LEDA} -lD3 -lW -lP -lG -lL -L/usr/X11R6/lib -lX11 -lm -L.
LDFLAGS+= -O3
CXXFLAGS = -I${LEDA}/incl
# Pick one of the following:
# Pick either this
CXXFLAGS += -Wall -O3
# or this
#CXXFLAGS += -O0 -g -Wall -DVERBOSE
#CXXFLAGS += -O0 -g -Wall -DVERBOSE -DSCORE_DEBUG -DPCLASS_DEBUG
#CXXFLAGS += -O0 -g -Wall -DVERBOSE -DSCORE_DEBUG -DPCLASS_DEBUG -DPCLASS_DEBUG_MORE
#CXXFLAGS += -O0 -g -Wall -DVERBOSE -DSCORE_DEBUG -DSCORE_DEBUG_MORE -DPCLASS_DEBUG -DPCLASS_DEBUG_MORE
# and then zero or more of these
#CXXFLAGS += -DSCORE_DEBUG
#CXXFLAGS += -DSCORE_DEBUG_MORE
#CXXFLAGS += -DPCLASS_DEBUG
#CXXFLAGS += -DDUMP_GRAPH
#CXXFLAGS += -DSCORE_DEBUG_LOTS
# And then, regardless, you can also have this
#CXXFLAGS += -DSTATS
# assign now supports a dizzing array of defines, which are as-yet undocumented
# Here are the ones used for a typical build:
# Pick cooling schedule
CXXFLAGS += -DMELT -DEPSILON_TERMINATE -DCHILL -DNEIGHBOR_LENGTH \
-DLOCAL_DERIVATIVE -DALLOW_NEGATIVE_DELTA
# Bug/scoring fixes
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
# 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... :)
DEPLIBS=$(OBJS)
ifdef ASSIGNBINARY
assign: ${ASSIGNBINARY}
rm -f assign
cp $< assign
else
assign: ${DEPLIBS} ${OBJS} assign.o
${CXX} assign.o -o assign ${LIBS} $(OBJS) ${LDFLAGS}
endif
assign: ${DEPLIBS} ${OBJS}
${CXX} -o assign ${LIBS} $(OBJS) ${LDFLAGS}
install: $(INSTALL_LIBEXECDIR)/assign
......
This diff is collapsed.
/*
* EMULAB-COPYRIGHT
* Copyright (c) 2000-2002 University of Utah and the Flux Group.
* All rights reserved.
*/
#ifndef __COMON_H
#define __COMON_H
#include "config.h"
const int MAX_PNODES = 2048; /* maximum # of physical nodes */
const int MAX_PNODES = 1024; /* maximum # of physical nodes */
/*
To use these on the command line, each entry gets a
......@@ -17,29 +11,78 @@ const int MAX_PNODES = 2048; /* maximum # of physical nodes */
Here we declare them all and give them defaults.
*/
static int init_temp = 100;
//static int init_temp = 100;
static int init_temp = 10;
static int USE_OPTIMAL = 1;
static int temp_prob = 130;
static int temp_stop = 20;
#ifdef LOW_TEMP_STOP
//static int temp_stop = 1;
static float temp_stop = .005;
#else
static float temp_stop = 2;
//static int temp_stop = 20;
#endif
static int CYCLES = 20;
// The following are basically arbitrary constants
// Initial acceptance ratio for melting
static float X0 = .95;
//static float epsilon = 0.1;
#ifdef LOCAL_DERIVATIVE
static float epsilon = 0.0001;
#else
static float epsilon = 0.01;
#endif
static float delta = 2;
//static float delta = 1;
//static float min_temp_end = 0.01;
//static float min_temp_end = 10000000.0;
// Number of runs to spend melting
static int melt_trans = 500;
static int min_neighborhood_size = 500;
static float temp_rate = 0.9;
static float opt_nodes_per_sw = 5.0;
#ifdef PENALIZE_BANDWIDTH
static float SCORE_DIRECT_LINK = 0.0;/* Cost of a direct link */
static float SCORE_INTRASWITCH_LINK = 0.0;/* Cost of an intraswitch link*/
static float SCORE_INTERSWITCH_LINK = 0.0;/* Cost of an interswitch link*/
#else
static float SCORE_DIRECT_LINK = 0.01;/* Cost of a direct link */
static float SCORE_DIRECT_LINK_PENALTY = 0.5;/* Cost of overused direct link*/
static float SCORE_INTRASWITCH_LINK = 0.02;/* Cost of an intraswitch link*/
static float SCORE_INTERSWITCH_LINK = 0.05;/* Cost of an interswitch link*/
static float SCORE_INTERSWITCH_LINK = 0.2;/* Cost of an interswitch link*/
#endif
static float SCORE_DIRECT_LINK_PENALTY = 0.5;/* Cost of overused direct link*/
static float SCORE_NO_CONNECTION = 0.5;/* Cost of not filling a virt. link*/
static float SCORE_PNODE = 0.05;/* Cost of using a pnode*/
static float SCORE_PNODE = 0.2;/* Cost of using a pnode*/
static float SCORE_PNODE_PENALTY = 0.5;/* Cost of overusing a pnode*/
static float SCORE_SWITCH = 0.5;/* Cost of using a switch.*/
static float SCORE_UNASSIGNED = 1;/* Cost of an unassigned node*/
static float SCORE_OVER_BANDWIDTH = 0.5;/* Cost of going over bandwidth*/
static float SCORE_DESIRE = 1;/* Multiplier for desire costs*/
static float SCORE_FEATURE = 1;/* Multiplier for feature weights*/
static float SCORE_UNASSIGNED = 1.0;/* Cost of an unassigned node*/
static float SCORE_DESIRE = 1.0;/* Multiplier for desire costs*/
static float SCORE_FEATURE = 1.0;/* Multiplier for feature weights*/
#ifdef NO_PCLASS_PENALTY
static float SCORE_PCLASS = 0.0; /* Cost of each pclass */
#else
static float SCORE_PCLASS = 0.5; /* Cost of each pclass */
static float SCORE_VCLASS = 1; /* vclass score multiplier */
#endif
static float SCORE_VCLASS = 1.0; /* vclass score multiplier */
static float SCORE_EMULATED_LINK = 0.01; /* cost of an emualted link */
static float SCORE_OUTSIDE_DELAY = 0.5; /* penalty for going out of delay
requirements */
static float SCORE_DELAY = 10.0; /* multiplier to distance for delay scoring */
#ifdef PENALIZE_UNUSED_INTERFACES
static float SCORE_UNUSED_INTERFACE = 0.04;
#endif
// The following are used to weight possible link resolutions. Higher
// numbers mean a more likely resolution. Trivial resolutions are always
// used if possible.
static float LINK_RESOLVE_DIRECT = 4.0;
static float LINK_RESOLVE_INTRASWITCH = 2.0;
static float LINK_RESOLVE_INTERSWITCH = 1.0;
static struct config_param options[] = {
{ "IT", CONFIG_INT, &init_temp, 0 },
......@@ -53,7 +96,6 @@ static struct config_param options[] = {
{ "1S", CONFIG_FLOAT, &SCORE_INTERSWITCH_LINK, 0 },
{ "2S", CONFIG_FLOAT, &SCORE_INTRASWITCH_LINK, 0 },
{ "NC", CONFIG_FLOAT, &SCORE_NO_CONNECTION, 0 },
{ "OB", CONFIG_FLOAT, &SCORE_OVER_BANDWIDTH, 0 },
{ "DL", CONFIG_FLOAT, &SCORE_DIRECT_LINK, 0 },
{ "DP", CONFIG_FLOAT, &SCORE_DIRECT_LINK_PENALTY, 0 },
{ "PN", CONFIG_FLOAT, &SCORE_PNODE, 0 },
......@@ -63,12 +105,41 @@ static struct config_param options[] = {
{ "SW", CONFIG_FLOAT, &SCORE_SWITCH, 0 },
{ "EL", CONFIG_FLOAT, &SCORE_EMULATED_LINK, 0 },
{ "ON", CONFIG_FLOAT, &opt_nodes_per_sw, 0 },
{ "TR", CONFIG_FLOAT, &temp_rate, 0 }
{ "TR", CONFIG_FLOAT, &temp_rate, 0 },
{ "LD", CONFIG_FLOAT, &LINK_RESOLVE_DIRECT, 0 },
{ "LI", CONFIG_FLOAT, &LINK_RESOLVE_INTRASWITCH, 0 },
{ "LT", CONFIG_FLOAT, &LINK_RESOLVE_INTERSWITCH, 0 },
{ "OD", CONFIG_FLOAT, &SCORE_OUTSIDE_DELAY, 0 },
{ "DM", CONFIG_FLOAT, &SCORE_DELAY, 0 }
};
static int noptions = sizeof(options) / sizeof(options[0]);
#endif
void parse_options(char **argv, struct config_param options[], int nopt);
struct eqstr
{
bool operator()(const char* A, const char* B) const
{
return (! strcmp(A, B));
}
};
enum edge_data_t {edge_data};
enum vertex_data_t {vertex_data};
namespace boost {
BOOST_INSTALL_PROPERTY(edge,data);
BOOST_INSTALL_PROPERTY(vertex,data);
}
typedef hash_map<crope,crope> name_name_map;
typedef slist<crope> name_slist;
template <class T> struct hashptr {
size_t operator()(T const &A) const {
return (size_t) A;
}
};
#endif
/*
* EMULAB-COPYRIGHT
* Copyright (c) 2000-2002 University of Utah and the Flux Group.
* Copyright (c) 1999-2001 The University of Utah and the Flux Group.
* All rights reserved.
*/
......@@ -25,7 +24,7 @@ struct config_param {
/* types */
#define CONFIG_INT 0
#define CONFIG_FLOAT 1
void parse_options(char **argv, struct config_param options[], int nopt);
int config_parse(char **args, struct config_param cparams[], int nparams);
void dump_options(const char *str, struct config_param cparams[], int nparams);
......
/*
* EMULAB-COPYRIGHT
* Copyright (c) 2000-2002 University of Utah and the Flux Group.
* All rights reserved.
*/
/*
* parse ptop files. These are basic topologies
* that are used to represent the physical topology.
*
* format:
* node <name> <type> [<type2> ...]
* <type> = <t>[:<max>]
* <t> = pc | switch | dnard
* <max> = how many virtual entities of that type per physical entity.
* link <name> <src>[:<mac>] <dst>[:<mac>] <size> <number>
*/
#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>
#include <LEDA/sortseq.h>
#include "port.h"
#include <hash_map>
#include <slist>
#include <rope>
#include <hash_set>
#include <boost/config.hpp>
#include <boost/utility.hpp>
#include <boost/property_map.hpp>
#include <boost/graph/graph_traits.hpp>
#include <boost/graph/adjacency_list.hpp>
#include <iostream.h>
#include <string.h>
#include <stdio.h>
using namespace boost;
using namespace boost;
#include "common.h"
#include "delay.h"
#include "physical.h"
#include "parser.h"
extern dictionary<string,node> pname2node;
extern node pnodes[MAX_PNODES]; // int -> node map
node_array<int> switch_index;
extern list<string> ptypes;
extern name_pvertex_map pname2vertex;
extern name_slist ptypes;
#define ptop_error(s) errors++;cerr << "PTOP:" << line << ": " << s << endl
int parse_ptop(tb_pgraph &PG, tb_sgraph &SG, istream& i)
{
int switchi=0;
node no1;
edge ed1;
string s1, s2;
char inbuf[255];
char n1[32], n2[32];
int size, num;
int n=1;
char *snext;
char *snode;
char *scur;
char lname[32];
int isswitch;
switch_index.init(PG,MAX_PNODES,0);
pnodes[0] = NULL;
int num_nodes = 0;
int line=0,errors=0;
char inbuf[1024];
string_vector parsed_line;
while (!i.eof()) {
char *ret;
i.getline(inbuf, 254);
ret = strchr(inbuf, '\n');
if (ret) *ret = 0;
if (strlen(inbuf) == 0) { continue; }
if (!strncmp(inbuf, "node", 4)) {
isswitch = 0;
snext = inbuf;
scur = strsep(&snext," ");
if (strcmp("node",scur) != 0) {
fprintf(stderr, "bad node line: %s\n", inbuf);
line++;
i.getline(inbuf,1024);
parsed_line = split_line(inbuf,' ');
if (parsed_line.size() == 0) {continue;}
crope command = parsed_line[0];
if (command.compare("node") == 0) {
if (parsed_line.size() < 3) {
ptop_error("Bad node line, too few arguments.");
} else {
scur = strsep(&snext," ");
snode = scur;
string s(snode);
#ifdef GRAPH_DEBUG
cout << "Found phys. node '"<<snode<<"'\n";
#endif
no1 = PG.new_node();
PG[no1].name=string(snode);
PG[no1].typed = false;
PG[no1].max_load = 0;
PG[no1].current_load = 0;
PG[no1].pnodes_used=0;
while ((scur = strsep(&snext," ")) != NULL &&
(strcmp(scur,"-"))) {
char *t,*load=scur;
num_nodes++;
crope name = parsed_line[1];
bool isswitch = false;
pvertex pv = add_vertex(PG);
tb_pnode *p = new tb_pnode();
put(pvertex_pmap,pv,p);
p->name = name;
p->typed = false;
p->max_load = 0;
p->current_load = 0;
p->pnodes_used = 0;
//#ifdef PENALIZE_UNUSED_INTERFACES
p->total_interfaces = 0;
//#endif
unsigned int i;
for (i = 2;
(i < parsed_line.size()) &&
(parsed_line[i].compare("-") != 0);++i) {
crope type,load;
if (split_two(parsed_line[i],':',type,load,"1") != 0) {
ptop_error("Bad node line, no load for type: " << type << ".");
}
int iload;
t = strsep(&load,":");
string stype(t);
if (load) {
if (sscanf(load,"%d",&iload) != 1) {
fprintf(stderr,"Bad load specifier: %s\n",load);
iload=1;
}
} else {
iload=1;
if (sscanf(load.c_str(),"%d",&iload) != 1) {
ptop_error("Bad node line, bad load: " << load << ".");
iload = 1;
}
ptypes.push(stype);
if (strcmp(t,"switch") == 0) {
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++;
ptypes.push_front(type);
if (type.compare("switch") == 0) {
isswitch = true;
p->types["switch"] = 1;
svertex sv = add_vertex(SG);
tb_switch *s = new tb_switch();
put(svertex_pmap,sv,s);
s->mate = pv;
p->sgraph_switch = sv;
} else {
PG[no1].types.insert(stype,iload);
p->types[type] = iload;
}
}
/* Either end of line or - . Read in features */
while ((scur = strsep(&snext," ")) != NULL) {
char *feature=scur;
double icost;
char *t;
t = strsep(&feature,":");
string sfeat(t);
if ((! feature) || sscanf(feature,"%lg",&icost) != 1) {
fprintf(stderr,"Bad cost specifier for %s\n",t);
icost = 0.01;
for (i=i+1;i<parsed_line.size();++i) {
crope feature,cost;
if (split_two(parsed_line[i],':',feature,cost,"0") != 0) {
ptop_error("Bad node line, no cost for feature: " <<
feature << ".");
}
double gcost;
if (sscanf(cost.c_str(),"%lg",&gcost) != 1) {
ptop_error("Bad node line, bad cost: " << gcost << ".");
gcost = 0;
}
PG[no1].features.insert(sfeat,icost);
p->features[feature] = gcost;
}
/* Done */
if (! isswitch)
pnodes[n++]=no1;
pname2node.insert(s, no1);
pname2vertex[name] = pv;
}
}
else if (!strncmp(inbuf, "link", 4)) {
if (sscanf(inbuf, "link %s %s %s %d %d", lname, n1, n2, &size, &num)
!= 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,":");
if (pname2node.lookup(snode) == nil) {
fprintf(stderr,"PTOP error: Unknown source node %s\n",snode);
exit(1);
} else if (command.compare("link") == 0) {
if (parsed_line.size() < 7) {
ptop_error("Bad link line, too few arguments.");
}
int num = 1;
#ifdef PENALIZE_BANDWIDTH
float penalty;
if (parsed_line.size() == 8) {
if (sscanf(parsed_line[7].c_str(),"%f",&penalty) != 1) {
ptop_error("Bad number argument: " << parsed_line[7] << ".");
penalty=1.0;
}
if (pname2node.lookup(dnode) == nil) {
fprintf(stderr,"PTOP error: Unknown destination node %s\n",dnode);
exit(1);
}
#else
if (parsed_line.size() == 8) {
if (sscanf(parsed_line[7].c_str(),"%d",&num) != 1) {
ptop_error("Bad number argument: " << parsed_line[7] << ".");
num=1;
}
node node1 = pname2node.access(snode);
node node2 = pname2node.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].name=linkname;
PG[ed1].emulated=0;
PG[ed1].nonemulated=0;
if (smac)
PG[ed1].srcmac = string(smac);
else
PG[ed1].srcmac = string("(null)");
if (dmac)
PG[ed1].dstmac = string(dmac);
else
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;
}
#endif
#ifdef FIX_PLINK_ENDPOINTS
bool fixends = false;
if (parsed_line.size() == 9) {
if (parsed_line[8].compare("fixends") == 0) {
fixends = true;
}
}
#else
if (parsed_line.size() > 8) {
ptop_error("Bad link line, too many arguments.");
}
#endif
crope name = parsed_line[1];
crope src,srcmac;
split_two(parsed_line[2],':',src,srcmac,"(null)");
crope dst,dstmac;
split_two(parsed_line[3],':',dst,dstmac,"(null)");
crope bw = parsed_line[4];
crope delay = parsed_line[5];
crope loss = parsed_line[6];
int ibw,idelay;
double gloss;
if ((sscanf(bw.c_str(),"%d",&ibw) != 1) ||
(sscanf(delay.c_str(),"%d",&idelay) != 1) ||
(sscanf(loss.c_str(),"%lg",&gloss) != 1)) {
ptop_error("Bad link line, bad delay characteristics.");
}
#define ISSWITCH(n) (n->types.find("switch") != n->types.end())
pvertex srcv = pname2vertex[src];
pvertex dstv = pname2vertex[dst];
tb_pnode *srcnode = get(pvertex_pmap,srcv);
tb_pnode *dstnode = get(pvertex_pmap,dstv);
for (int cur = 0;cur<num;++cur) {
pedge pe = (add_edge(srcv,dstv,PG)).first;
tb_plink *pl = new tb_plink();
put(pedge_pmap,pe,pl);
pl->delay_info.bandwidth = ibw;
pl->delay_info.delay = idelay;
pl->delay_info.loss = gloss;
pl->bw_used = 0;
pl->name = name;
pl->emulated = 0;
pl->nonemulated = 0;
#ifdef FIX_PLINK_ENDPOINTS
pl->fixends = fixends;
#endif
#ifdef PENALIZE_BANDWIDTH
pl->penalty = penalty;
#endif
pl->type = tb_plink::PLINK_NORMAL;
pl->srcmac = srcmac;
pl->dstmac = dstmac;
if (ISSWITCH(srcnode) && ISSWITCH(dstnode)) {
if (cur != 0) {
cout <<
"Warning: Extra links between switches will be ignored. (" <<
name << ")" << endl;
} else {
svertex src_switch = get(pvertex_pmap,srcv)->sgraph_switch;
svertex dst_switch = get(pvertex_pmap,dstv)->sgraph_switch;
sedge swedge = add_edge(src_switch,dst_switch,SG).first;
tb_slink *sl = new tb_slink();
put(sedge_pmap,swedge,sl);
sl->mate = pe;
pl->type = tb_plink::PLINK_INTERSWITCH;
}
}
if (ISSWITCH(node1) &&
! ISSWITCH(node2))
PG[node2].the_switch = node1;
else if (ISSWITCH(node2) &&
! ISSWITCH(node1))
PG[node1].the_switch = node2;
if (ISSWITCH(srcnode) &&
! ISSWITCH(dstnode)) {
dstnode->switches.insert(srcv);
//#ifdef PENALIZE_UNUSED_INTERFACES
dstnode->total_interfaces++;
//#endif
}
else if (ISSWITCH(dstnode) &&
! ISSWITCH(srcnode)) {
srcnode->switches.insert(dstv);
//#ifdef PENALIZE_UNUSED_INTERFACES
srcnode->total_interfaces++;
//#endif
}
}