Skip to content
GitLab
Projects
Groups
Snippets
Help
Loading...
Help
What's new
10
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Open sidebar
emulab
emulab-devel
Commits
3353ffb3
Commit
3353ffb3
authored
May 18, 2000
by
Christopher Alfeld
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Now compiles. Completely untested however.
parent
0c5fa30e
Changes
8
Hide whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
583 additions
and
8 deletions
+583
-8
assign_hw/Makefile
assign_hw/Makefile
+26
-0
assign_hw/assign.cc
assign_hw/assign.cc
+503
-0
assign_hw/common.h
assign_hw/common.h
+5
-1
assign_hw/parse_ptop.cc
assign_hw/parse_ptop.cc
+3
-0
assign_hw/physical.h
assign_hw/physical.h
+7
-2
assign_hw/score.cc
assign_hw/score.cc
+8
-2
assign_hw/score.h
assign_hw/score.h
+3
-2
assign_hw/virtual.h
assign_hw/virtual.h
+28
-1
No files found.
assign_hw/Makefile
0 → 100644
View file @
3353ffb3
CXX
=
/usr/gnu/bin/g++
CC
=
/usr/gnu/bin/gcc
LEDA
=
/n/paria/z/dga/LEDA-4.0
OBJS
=
score.o parse_top.o parse_ptop.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
# Pick one of the two below.
#CXXFLAGS += -Wall -O3 -fomit-frame-pointer -m486
CXXFLAGS
+=
-O0
-g
-Wall
DEPLIBS
=
$(OBJS)
all
:
assign
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}
clean
:
/bin/rm
-f
*
.o assign
assign_hw/assign.cc
0 → 100644
View file @
3353ffb3
#include <LEDA/graph_alg.h>
#include <LEDA/graphwin.h>
#include <LEDA/dictionary.h>
#include <LEDA/map.h>
#include <LEDA/graph_iterator.h>
#include <iostream.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/time.h>
#include <string.h>
#include "common.h"
#include "physical.h"
#include "virtual.h"
#include "score.h"
tb_pgraph
PG
(
1
,
1
);
tb_vgraph
G
(
1
,
1
);
/* How can we chop things up? */
#define PARTITION_BY_ANNEALING 0
#define MAX_DELAYS 64
int
nparts
=
0
;
/* DEFAULTS */
int
accepts
=
0
;
int
nnodes
=
0
;
int
partition_mechanism
;
int
on_line
=
0
;
int
cycles_to_best
=
0
;
int
batch_mode
=
0
;
float
sensitivity
=
.1
;
static
const
int
initial_temperature
=
100
;
static
const
int
temp_prob
=
130
;
int
refreshed
=
0
;
node_array
<
int
>
bestnodes
,
absnodes
;
float
bestscore
,
absbest
;
extern
node
pnodes
[
MAX_PNODES
];
extern
node_array
<
int
>
switch_index
;
void
parse_top
(
tb_vgraph
&
G
,
istream
&
i
);
void
parse_ptop
(
tb_pgraph
&
G
,
istream
&
i
);
/*
* Basic simulated annealing parameters:
*
* Make changes proportional to T
* Accept worse solution with p = e^(change/Temperature*sensitivity)
*
*/
inline
int
accept
(
float
change
,
float
temperature
)
{
float
p
;
int
r
;
if
(
change
==
0
)
{
p
=
1000
*
temperature
/
temp_prob
;
}
else
{
p
=
expf
(
change
/
(
temperature
*
sensitivity
))
*
1000
;
}
r
=
random
()
%
1000
;
if
(
r
<
p
)
{
accepts
++
;
return
1
;
}
return
0
;
}
/*
* The workhorse of our program.
*
* Assign performs an assignment of the virtual nodes (vnodes) to
* nodes in the physical topology.
*
* The input virtual topology is the graph G (global)
* the input physical topology is the topology topo (global).
*
* The simulated annealing logic is contained herein,
* except for the "accept a bad change" computation,
* which is performed in accept().
*/
int
assign
()
{
float
newscore
,
bestscore
,
absbest
;
node
n
;
int
iters
=
0
;
float
timestart
=
used_time
();
float
timeend
;
float
scorediff
;
nnodes
=
G
.
number_of_nodes
();
float
cycles
=
120.0
*
(
float
)(
nnodes
+
G
.
number_of_edges
());
int
mintrans
=
(
int
)
cycles
;
int
trans
;
int
naccepts
=
40
*
nnodes
;
int
accepts
=
0
;
int
oldpos
;
float
temp
=
initial_temperature
;
/* Set up the initial counts */
init_score
();
bestscore
=
get_score
();
absbest
=
bestscore
;
node
n3
;
forall_nodes
(
n3
,
G
)
{
absnodes
[
n3
]
=
G
[
n3
].
posistion
;
}
if
(
bestscore
<
0.11
f
)
{
#ifdef VERBOSE
cout
<<
"Problem started optimal
\n
"
;
#endif
goto
DONE
;
}
while
(
temp
>=
2
)
{
#ifdef VERBOSE
cout
<<
"Temperature: "
<<
temp
<<
endl
;
#endif
trans
=
0
;
accepts
=
0
;
while
(
trans
<
mintrans
&&
accepts
<
naccepts
)
{
int
newpos
;
trans
++
;
iters
++
;
n
=
G
.
choose_node
();
oldpos
=
G
[
n
].
posistion
;
newpos
=
oldpos
;
/* XXX: Room for improvement. :-) */
while
(
newpos
==
oldpos
)
newpos
=
random
()
%
nparts
;
if
(
oldpos
!=
0
)
{
remove_node
(
n
);
}
add_node
(
n
,
newpos
);
newscore
=
get_score
();
if
(
newscore
<
0.11
f
)
{
timeend
=
used_time
(
timestart
);
cout
<<
"OPTIMAL (0.0) in "
<<
iters
<<
" iters, "
<<
timeend
<<
" seconds"
<<
endl
;
goto
DONE
;
}
/* So it's negative if bad */
scorediff
=
bestscore
-
newscore
;
if
(
newscore
<
bestscore
||
accept
(
scorediff
,
temp
))
{
bestnodes
[
n
]
=
G
[
n
].
posistion
;
bestscore
=
newscore
;
accepts
++
;
if
(
newscore
<
absbest
)
{
node
n2
;
forall_nodes
(
n2
,
G
)
{
absnodes
[
n2
]
=
G
[
n2
].
posistion
;
}
absbest
=
newscore
;
cycles_to_best
=
iters
;
}
}
else
{
/* Reject this change */
remove_node
(
n
);
add_node
(
n
,
oldpos
);
}
}
temp
*=
.9
;
}
DONE:
forall_nodes
(
n
,
G
)
{
bestnodes
[
n
]
=
absnodes
[
n
];
}
bestscore
=
absbest
;
forall_nodes
(
n
,
G
)
{
if
(
G
[
n
].
posistion
!=
0
)
remove_node
(
n
);
add_node
(
n
,
absnodes
[
n
]);
}
timeend
=
used_time
(
timestart
);
cout
<<
" BEST SCORE: "
<<
get_score
()
<<
" in "
<<
iters
<<
" iters and "
<<
timeend
<<
" seconds"
<<
endl
;
cout
<<
"With "
<<
accepts
<<
" accepts of increases
\n
"
;
cout
<<
"Iters to find best score: "
<<
cycles_to_best
<<
endl
;
return
0
;
}
/*
* A legacy function from a less general version of the program.
*
* Now simply resets the node assignment, performs a new assignment,
* and prints out the results.
*
*/
void
loopassign
()
{
node_array
<
int
>
nodestorage
;
int
optimal
=
0
;
float
timestart
=
used_time
();
float
totaltime
;
nodestorage
.
init
(
G
,
0
);
bestnodes
.
init
(
G
,
0
);
absnodes
.
init
(
G
,
0
);
nnodes
=
G
.
number_of_nodes
();
optimal
=
assign
();
totaltime
=
used_time
(
timestart
);
if
(
violated
>
0
)
{
cout
<<
"violations: "
<<
violated
<<
endl
;
}
cout
<<
"Total time to find solution "
<<
totaltime
<<
" seconds"
<<
endl
;
}
/*
* If we have more ways of partitioning the graph other than just
* simulated annealing, throw them in here.
*/
void
chopgraph
()
{
switch
(
partition_mechanism
)
{
case
PARTITION_BY_ANNEALING
:
loopassign
();
break
;
default:
cerr
<<
"Unknown partition mechanism. eeeek."
<<
endl
;
exit
(
-
1
);
}
}
/*
* Something in the graph has changed! Better redisplay.
*
* Performs the color assignment for whichever switch the
* node belongs to and shows the inter-switch links as
* dashed lines.
*/
void
display_scc
(
GraphWin
&
gw
)
{
edge
e
;
node
n
;
if
(
!
refreshed
)
{
if
(
on_line
)
chopgraph
();
}
refreshed
=
0
;
/* Now color them according to their partition */
// XXX - Need to color them according to switch now!
// XXX - Need to add labels based on physical node matching
forall_nodes
(
n
,
G
)
{
int
switchi
;
if
(
G
[
n
].
posistion
)
{
gw
.
set_label
(
n
,
PG
[
pnodes
[
G
[
n
].
posistion
]].
name
);
switchi
=
switch_index
[
PG
[
pnodes
[
G
[
n
].
posistion
]].
the_switch
];
switch
(
switchi
)
{
case
0
:
gw
.
set_color
(
n
,
black
);
break
;
case
1
:
gw
.
set_color
(
n
,
blue
);
break
;
case
2
:
gw
.
set_color
(
n
,
green
);
break
;
case
3
:
gw
.
set_color
(
n
,
red
);
break
;
case
4
:
gw
.
set_color
(
n
,
yellow
);
break
;
case
5
:
gw
.
set_color
(
n
,
violet
);
break
;
case
6
:
gw
.
set_color
(
n
,
cyan
);
break
;
case
7
:
gw
.
set_color
(
n
,
brown
);
break
;
case
8
:
gw
.
set_color
(
n
,
pink
);
break
;
case
9
:
gw
.
set_color
(
n
,
orange
);
break
;
case
10
:
gw
.
set_color
(
n
,
grey1
);
break
;
case
11
:
gw
.
set_color
(
n
,
grey3
);
break
;
}
}
}
forall_edges
(
e
,
G
)
{
node
v
=
G
.
source
(
e
);
node
w
=
G
.
target
(
e
);
node
sa
,
sb
;
if
(
G
[
v
].
posistion
&&
G
[
w
].
posistion
)
{
sa
=
PG
[
pnodes
[
G
[
v
].
posistion
]].
the_switch
;
sb
=
PG
[
pnodes
[
G
[
w
].
posistion
]].
the_switch
;
if
(
sa
==
sb
)
{
gw
.
set_style
(
e
,
solid_edge
);
}
else
{
gw
.
set_style
(
e
,
dashed_edge
);
}
}
}
gw
.
redraw
();
}
/*
* Someone clicked on the "reassign" button.
* Reset and redisplay.
*/
void
reassign
(
GraphWin
&
gw
)
{
bestnodes
.
init
(
G
,
0
);
absnodes
.
init
(
G
,
0
);
chopgraph
();
refreshed
=
1
;
display_scc
(
gw
);
}
// XXX : another code by copy
void
batch
()
{
bestnodes
.
init
(
G
,
0
);
absnodes
.
init
(
G
,
0
);
chopgraph
();
}
void
new_edge_handler
(
GraphWin
&
gw
,
edge
)
{
display_scc
(
gw
);
}
void
del_edge_handler
(
GraphWin
&
gw
)
{
display_scc
(
gw
);
}
void
new_node_handler
(
GraphWin
&
gw
,
node
)
{
display_scc
(
gw
);
}
void
del_node_handler
(
GraphWin
&
gw
)
{
display_scc
(
gw
);
}
void
usage
()
{
fprintf
(
stderr
,
"usage: assign [-h] [-bao] [-s <switches>] [-n nodes/switch] [-c cap] [file]
\n
"
" -h ...... brief help listing
\n
"
// " -s # ... number of switches in cluster\n"
// " -n # ... number of nodes per switch\n"
" -a ...... Use simulated annealing (default)
\n
"
" -o ...... Update on-line (vs batch, default)
\n
"
" -t <file> Input topology desc. from <file>
\n
"
" -b ...... batch mode (no gui)
\n
"
);
}
void
print_solution
()
{
node
n
;
cout
<<
"Best solution: "
<<
absbest
<<
endl
;
forall_nodes
(
n
,
G
)
{
if
(
!
G
[
n
].
posistion
)
{
cout
<<
"unassigned: "
<<
G
[
n
].
name
<<
endl
;
}
else
{
node
pnode
=
pnodes
[
G
[
n
].
posistion
];
tb_pnode
&
pnoder
=
PG
[
pnode
];
cout
<<
G
[
n
].
name
<<
" "
<<
PG
[
pnoder
.
the_switch
].
name
<<
" "
<<
pnoder
.
name
<<
endl
;
}
}
cout
<<
"End solution"
<<
endl
;
}
int
main
(
int
argc
,
char
**
argv
)
{
int
h_menu
;
extern
char
*
optarg
;
extern
int
optind
;
char
*
topofile
=
NULL
;
int
ch
;
partition_mechanism
=
PARTITION_BY_ANNEALING
;
while
((
ch
=
getopt
(
argc
,
argv
,
"boas:n:t:h"
))
!=
-
1
)
switch
(
ch
)
{
case
'h'
:
usage
();
exit
(
0
);
// case 's': nparts = atoi(optarg); break;
case
'a'
:
partition_mechanism
=
PARTITION_BY_ANNEALING
;
break
;
case
'o'
:
on_line
=
1
;
break
;
case
't'
:
topofile
=
optarg
;
break
;
case
'b'
:
batch_mode
=
1
;
break
;
default:
usage
();
exit
(
-
1
);
}
argc
-=
optind
;
argv
+=
optind
;
srandom
(
time
(
NULL
)
+
getpid
());
/*
* Set up the LEDA graph window environment. Whenever
* the user does anything to the graph, call the
* proper handler.
*/
// XXX: alas, we need this because all the GW stuff is not in
// the same spot.
GraphWin
gw
(
G
,
"Flux Testbed: Simulated Annealing"
);
if
(
!
batch_mode
)
{
gw
.
set_init_graph_handler
(
del_edge_handler
);
gw
.
set_new_edge_handler
(
new_edge_handler
);
gw
.
set_del_edge_handler
(
del_edge_handler
);
gw
.
set_new_node_handler
(
new_node_handler
);
gw
.
set_del_node_handler
(
del_node_handler
);
gw
.
set_node_width
(
24
);
gw
.
set_node_height
(
24
);
}
/*
* Allow the user to specify a topology in ".top" format.
*/
if
(
argc
==
1
)
{
ifstream
infile
;
infile
.
open
(
argv
[
0
]);
if
(
!
infile
||
!
infile
.
good
())
{
cerr
<<
"Error opening file: "
<<
argv
[
0
]
<<
endl
;
exit
(
-
11
);
}
parse_top
(
G
,
infile
);
if
(
!
batch_mode
)
{
gw
.
update_graph
();
node
n
;
forall_nodes
(
n
,
G
)
{
if
(
G
[
n
].
name
==
NULL
)
{
G
[
n
].
name
=
""
;
}
gw
.
set_label
(
n
,
G
[
n
].
name
);
gw
.
set_position
(
n
,
point
(
random
()
%
200
,
random
()
%
200
));
}
}
}
/*
* Allow the user to specify a physical topology
* in .phys format. Fills in the "topo" global variable.
* Make no mistake: This is actually mandatory now.
*/
if
(
topofile
!=
NULL
)
{
cout
<<
"Parsing ptop
\n
"
;
ifstream
ptopfile
;
ptopfile
.
open
(
topofile
);
if
(
!
ptopfile
||
!
ptopfile
.
good
())
{
cerr
<<
"Error opening file: "
<<
topofile
<<
endl
;
exit
(
-
1
);
}
parse_ptop
(
PG
,
ptopfile
);
nparts
=
PG
.
number_of_nodes
();
cout
<<
"Nparts: "
<<
nparts
<<
endl
;
}
if
(
!
batch_mode
)
{
gw
.
display
();
gw
.
set_directed
(
false
);
gw
.
set_node_shape
(
circle_node
);
gw
.
set_node_label_type
(
user_label
);
h_menu
=
gw
.
get_menu
(
"Layout"
);
gw_add_simple_call
(
gw
,
reassign
,
"Reassign"
,
h_menu
);
/* Run until the user quits. Everything is handled by callbacks
* from LEDA's event loop from here on. */
gw
.
edit
();
}
else
{
batch
();
}
print_solution
();
return
0
;
}
assign_hw/common.h
View file @
3353ffb3
#ifndef __COMON_H
#define __COMON_H
class
tb_type
{
public:
char
*
name
;
...
...
@@ -7,7 +10,8 @@ const int MAX_PNODES = 1024; // maximum # of physical nodes
typedef
enum
{
TYPE_UNKNOWN
,
TYPE_PC
,
TYPE_DNARD
,
TYPE_DELAY
,
TYPE_DELAY_PC
,
TYPE_SWITCH
}
nodeType
;
enum
{
MAX_TYPES
=
5
};
#endif
assign_hw/parse_ptop.cc
View file @
3353ffb3
...
...
@@ -22,9 +22,11 @@
extern
node
pnodes
[
MAX_PNODES
];
// int -> node map
extern
tb_pgraph
PG
;
// physical graph
node_array
<
int
>
switch_index
;
void
parse_ptop
(
tb_pgraph
&
G
,
istream
&
i
)
{
int
switchi
=
0
;
dictionary
<
string
,
node
>
nmap
;
node
no1
;
edge
ed1
;
...
...
@@ -87,6 +89,7 @@ void parse_ptop(tb_pgraph &G, istream& i)
PG
[
no1
].
types
[
TYPE_SWITCH
].
name
=
"switch"
;
PG
[
no1
].
types
[
TYPE_SWITCH
].
max
=
1
;
PG
[
no1
].
the_switch
=
no1
;
switch_index
[
no1
]
=
switchi
++
;
}
}
if
(
!
isswitch
)
...
...
assign_hw/physical.h
View file @
3353ffb3
#ifndef __PHYSICAL_H
#define __PHYSICAL_H
class
tb_pnode
{
public:
tb_pnode
()
{;}
friend
ostream
&
operator
<<
(
ostream
&
o
,
const
tb_pnode
&
node
)
{
o
<<
"TBNode: "
<<
node
.
name
<<
endl
;
...
...
@@ -10,13 +14,11 @@ public:
{
return
i
;
}
tb_pnode
();
tb_type
types
[
MAX_TYPES
];
// array of types, with counts of max
nodeType
current_type
;
// the current type of the node
int
max_load
;
// maxmium load for current type
int
current_load
;
// how many vnodes are assigned to this pnode
// int index; // index for switches
char
*
name
;
node
the_switch
;
// the switch the node is attached to
int
pnodes_used
;
// for switch nodes
...
...
@@ -24,6 +26,7 @@ public:
class
tb_plink
{
public:
tb_plink
()
{;}
friend
ostream
&
operator
<<
(
ostream
&
o
,
const
tb_plink
&
edge
)
{
o
<<
"unimplemeted ostream << for tb_plinke "
<<
endl
;
...
...
@@ -46,3 +49,5 @@ private:
};
typedef
GRAPH
<
tb_pnode
,
tb_plink
>
tb_pgraph
;
#endif
assign_hw/score.cc
View file @
3353ffb3
...
...
@@ -37,7 +37,13 @@ extern tb_pgraph PG; // physical grpaph
int
find_interswitch_path
(
node
src
,
node
dst
,
int
bandwidth
,
edge
*
f
,
edge
*
s
);
edge
*
direct_link
(
node
a
,
node
b
);
/*
* score()
* Returns the score.
*/
float
get_score
()
{
return
score
;}
/*
* init_score()
* This initialized the scoring system. It also clears all
...
...
@@ -55,7 +61,7 @@ void init_score()
vn
.
posistion
=
0
;
vn
.
no_connections
=
0
;
score
+=
SCORE_UNASSIGNED
;
violat
ions
++
;
violat
ed
++
;
}
forall_edges
(
e
,
G
)
{
tb_vlink
&
ve
=
G
[
e
];
...
...
assign_hw/score.h
View file @
3353ffb3
...
...
@@ -29,10 +29,11 @@ const float SCORE_UNASSIGNED = 1;