-
Notifications
You must be signed in to change notification settings - Fork 0
/
topology.cpp
210 lines (189 loc) · 6.35 KB
/
topology.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
#include "router.h"
#include <assert.h>
// Get the component of id along 'direction' axis.
int torus_id_xyz_get(int id, int k, int direction)
{
int val = id;
for (int i = 0; i < direction; i++)
val /= k;
return val % k;
}
// Set the component of id along 'direction' axis to 'component'.
int torus_id_xyz_set(int id, int k, int direction, int component)
{
int weight = 1;
for (int i = 0; i < direction; i++)
weight *= k;
int delta = component - torus_id_xyz_get(id, k, direction);
return id + delta * weight;
}
int torus_set_id_xyz(int id, int k, int direction)
{
int val = id;
for (int i = 0; i < direction; i++)
val /= k;
return val % k;
}
Topology topology_create(void)
{
Topology top;
memset(&top, 0, sizeof(Topology));
return top;
}
void topology_destroy(Topology *top)
{
hmfree(top->forward_hash);
hmfree(top->reverse_hash);
}
int topology_connect(Topology *t, RouterPortPair input, RouterPortPair output)
{
int old_output_i = hmgeti(t->forward_hash, input);
int old_input_i = hmgeti(t->reverse_hash, output);
if (old_output_i >= 0 || old_input_i >= 0) {
// FIXME: When only one of _i's are >= 0, this results in buffer
// overflow.
RouterPortPair old_output = t->forward_hash[old_output_i].value.dst;
RouterPortPair old_input = t->reverse_hash[old_input_i].value.src;
if (input.id.type == old_input.id.type &&
input.id.value == old_input.id.value &&
input.port == old_input.port &&
output.id.type == old_output.id.type &&
output.id.value == old_output.id.value &&
output.port == old_output.port) {
// Already connected.
return 1;
} else {
// Bad connectivity: source or destination port is already connected
return 0;
}
}
int uniq = hmlen(t->forward_hash);
Connection conn = (Connection){.src = input, .dst = output, .uniq = uniq};
hmput(t->forward_hash, input, conn);
hmput(t->reverse_hash, output, conn);
assert(hmgeti(t->forward_hash, input) >= 0);
return 1;
}
int topology_connect_terminals(Topology *t, const int *ids)
{
int res = 1;
for (int i = 0; i < arrlen(ids); i++) {
RouterPortPair src_port = {src_id(ids[i]), 0};
RouterPortPair dst_port = {dst_id(ids[i]), 0};
RouterPortPair rtr_port = {rtr_id(ids[i]), 0};
// Bidirectional channel
res &= topology_connect(t, src_port, rtr_port);
res &= topology_connect(t, rtr_port, dst_port);
if (!res)
return 0;
}
return 1;
}
// direction: dimension that the path is in. XYZ = 012.
// to_larger: whether the output port points to a Router with higher ID or not.
int get_output_port(int direction, int to_larger)
{
return direction * 2 + (to_larger ? 2 : 1);
}
// Port usage: 0:terminal, 1:counter-clockwise, 2:clockwise
static int topology_connect_ring(Topology *t, long size, const int *ids, int direction)
{
printf("%s: ids={", __func__);
for (long i = 0; i < size; i++)
printf("%d,", ids[i]);
printf("}\n");
int port_cw = get_output_port(direction, 1);
int port_ccw = get_output_port(direction, 0);
int res = 1;
for (long i = 0; i < size; i++) {
int l = ids[i];
int r = ids[(i + 1) % size];
RouterPortPair lport = {rtr_id(l), port_cw};
RouterPortPair rport = {rtr_id(r), port_ccw};
// Bidirectional channel
res &= topology_connect(t, lport, rport);
res &= topology_connect(t, rport, lport);
if (!res)
return 0;
}
return 1;
}
// Connects part of the torus that corresponds to the the given parameters.
// Calls itself recursively to form the desired connection.
//
// dimension: size of the 'normal' array.
// offset: offset of the lowest index.
int topology_connect_torus_dimension(Topology *t, int k, int r, int dimension,
int *normal, int offset)
{
int res = 1;
int zeros = 0;
for (int i = 0; i < dimension; i++)
if (normal[i] == 0)
zeros++;
if (zeros == 1) {
// Ring
int stride = 1;
for (int i = 0; i < dimension; i++, stride *= k) {
if (normal[i] == 0) {
int ids[NORMALLEN];
for (int j = 0; j < k; j++)
ids[j] = offset + j * stride;
res &= topology_connect_ring(t, k, ids, i);
break; // only one 0 in normal
}
}
} else {
int stride = 1;
for (int i = 0; i < dimension; i++, stride *= k) {
if (normal[i] == 0) {
int subnormal[NORMALLEN];
memcpy(subnormal, normal, dimension * sizeof(int));
subnormal[i] = 1; // lock this dimension
for (int j = 0; j < k; j++) {
int suboffset = offset + j * stride;
res &= topology_connect_torus_dimension(
t, k, r, dimension, subnormal, suboffset);
}
}
}
}
return res;
}
Topology topology_torus(int k, int r)
{
Topology top = topology_create();
top.desc = (TopoDesc){TOP_TORUS, k, r};
int normal[NORMALLEN] = {0};
int res = 1;
// Inter-switch channels
res &= topology_connect_torus_dimension(&top, k, r, r, normal, 0);
// Terminal channels
int total_nodes = 1;
int *ids = NULL;
for (int i = 0; i < r; i++) total_nodes *= k; // k ^ r
for (int id = 0; id < total_nodes; id++) {
arrput(ids, id);
}
res &= topology_connect_terminals(&top, ids);
assert(res);
arrfree(ids);
return top;
}
// Compute the ID of the router which is the result of moving 'src_id' along
// the 'move_direction' axis to be aligned with 'dst__id'. That is, compute the
// ID that has the same component along the 'direction' axis as 'dst_id', and
// along all the other axes as 'src_id'.
//
// move_direction
// src_id -------------> (return)
// |
// dst_id
//
// This function is mainly used for computing IDs of the intermediate nodes in
// the dimension order routing.
int torus_align_id(int k, int src_id, int dst_id, int move_direction)
{
int component = torus_id_xyz_get(dst_id, k, move_direction);
return torus_id_xyz_set(src_id, k, move_direction, component);
}