311564fc52ed760af3061e4a18402255d5c4a7fe
[gem5.git] / src / mem / ruby / network / garnet / Router.cc
1 /*
2 * Copyright (c) 2020 Advanced Micro Devices, Inc.
3 * Copyright (c) 2020 Inria
4 * Copyright (c) 2016 Georgia Institute of Technology
5 * Copyright (c) 2008 Princeton University
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions are
10 * met: redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer;
12 * redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution;
15 * neither the name of the copyright holders nor the names of its
16 * contributors may be used to endorse or promote products derived from
17 * this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 */
31
32
33 #include "mem/ruby/network/garnet/Router.hh"
34
35 #include "debug/RubyNetwork.hh"
36 #include "mem/ruby/network/garnet/CreditLink.hh"
37 #include "mem/ruby/network/garnet/GarnetNetwork.hh"
38 #include "mem/ruby/network/garnet/InputUnit.hh"
39 #include "mem/ruby/network/garnet/NetworkLink.hh"
40 #include "mem/ruby/network/garnet/OutputUnit.hh"
41
42 using namespace std;
43
44 Router::Router(const Params &p)
45 : BasicRouter(p), Consumer(this), m_latency(p.latency),
46 m_virtual_networks(p.virt_nets), m_vc_per_vnet(p.vcs_per_vnet),
47 m_num_vcs(m_virtual_networks * m_vc_per_vnet), m_bit_width(p.width),
48 m_network_ptr(nullptr), routingUnit(this), switchAllocator(this),
49 crossbarSwitch(this)
50 {
51 m_input_unit.clear();
52 m_output_unit.clear();
53 }
54
55 void
56 Router::init()
57 {
58 BasicRouter::init();
59
60 switchAllocator.init();
61 crossbarSwitch.init();
62 }
63
64 void
65 Router::wakeup()
66 {
67 DPRINTF(RubyNetwork, "Router %d woke up\n", m_id);
68 assert(clockEdge() == curTick());
69
70 // check for incoming flits
71 for (int inport = 0; inport < m_input_unit.size(); inport++) {
72 m_input_unit[inport]->wakeup();
73 }
74
75 // check for incoming credits
76 // Note: the credit update is happening before SA
77 // buffer turnaround time =
78 // credit traversal (1-cycle) + SA (1-cycle) + Link Traversal (1-cycle)
79 // if we want the credit update to take place after SA, this loop should
80 // be moved after the SA request
81 for (int outport = 0; outport < m_output_unit.size(); outport++) {
82 m_output_unit[outport]->wakeup();
83 }
84
85 // Switch Allocation
86 switchAllocator.wakeup();
87
88 // Switch Traversal
89 crossbarSwitch.wakeup();
90 }
91
92 void
93 Router::addInPort(PortDirection inport_dirn,
94 NetworkLink *in_link, CreditLink *credit_link)
95 {
96 fatal_if(in_link->bitWidth != m_bit_width, "Widths of link %s(%d)does"
97 " not match that of Router%d(%d). Consider inserting SerDes "
98 "Units.", in_link->name(), in_link->bitWidth, m_id, m_bit_width);
99
100 int port_num = m_input_unit.size();
101 InputUnit *input_unit = new InputUnit(port_num, inport_dirn, this);
102
103 input_unit->set_in_link(in_link);
104 input_unit->set_credit_link(credit_link);
105 in_link->setLinkConsumer(this);
106 in_link->setVcsPerVnet(get_vc_per_vnet());
107 credit_link->setSourceQueue(input_unit->getCreditQueue(), this);
108 credit_link->setVcsPerVnet(get_vc_per_vnet());
109
110 m_input_unit.push_back(std::shared_ptr<InputUnit>(input_unit));
111
112 routingUnit.addInDirection(inport_dirn, port_num);
113 }
114
115 void
116 Router::addOutPort(PortDirection outport_dirn,
117 NetworkLink *out_link,
118 std::vector<NetDest>& routing_table_entry, int link_weight,
119 CreditLink *credit_link, uint32_t consumerVcs)
120 {
121 fatal_if(out_link->bitWidth != m_bit_width, "Widths of units do not match."
122 " Consider inserting SerDes Units");
123
124 int port_num = m_output_unit.size();
125 OutputUnit *output_unit = new OutputUnit(port_num, outport_dirn, this,
126 consumerVcs);
127
128 output_unit->set_out_link(out_link);
129 output_unit->set_credit_link(credit_link);
130 credit_link->setLinkConsumer(this);
131 credit_link->setVcsPerVnet(consumerVcs);
132 out_link->setSourceQueue(output_unit->getOutQueue(), this);
133 out_link->setVcsPerVnet(consumerVcs);
134
135 m_output_unit.push_back(std::shared_ptr<OutputUnit>(output_unit));
136
137 routingUnit.addRoute(routing_table_entry);
138 routingUnit.addWeight(link_weight);
139 routingUnit.addOutDirection(outport_dirn, port_num);
140 }
141
142 PortDirection
143 Router::getOutportDirection(int outport)
144 {
145 return m_output_unit[outport]->get_direction();
146 }
147
148 PortDirection
149 Router::getInportDirection(int inport)
150 {
151 return m_input_unit[inport]->get_direction();
152 }
153
154 int
155 Router::route_compute(RouteInfo route, int inport, PortDirection inport_dirn)
156 {
157 return routingUnit.outportCompute(route, inport, inport_dirn);
158 }
159
160 void
161 Router::grant_switch(int inport, flit *t_flit)
162 {
163 crossbarSwitch.update_sw_winner(inport, t_flit);
164 }
165
166 void
167 Router::schedule_wakeup(Cycles time)
168 {
169 // wake up after time cycles
170 scheduleEvent(time);
171 }
172
173 std::string
174 Router::getPortDirectionName(PortDirection direction)
175 {
176 // PortDirection is actually a string
177 // If not, then this function should add a switch
178 // statement to convert direction to a string
179 // that can be printed out
180 return direction;
181 }
182
183 void
184 Router::regStats()
185 {
186 BasicRouter::regStats();
187
188 m_buffer_reads
189 .name(name() + ".buffer_reads")
190 .flags(Stats::nozero)
191 ;
192
193 m_buffer_writes
194 .name(name() + ".buffer_writes")
195 .flags(Stats::nozero)
196 ;
197
198 m_crossbar_activity
199 .name(name() + ".crossbar_activity")
200 .flags(Stats::nozero)
201 ;
202
203 m_sw_input_arbiter_activity
204 .name(name() + ".sw_input_arbiter_activity")
205 .flags(Stats::nozero)
206 ;
207
208 m_sw_output_arbiter_activity
209 .name(name() + ".sw_output_arbiter_activity")
210 .flags(Stats::nozero)
211 ;
212 }
213
214 void
215 Router::collateStats()
216 {
217 for (int j = 0; j < m_virtual_networks; j++) {
218 for (int i = 0; i < m_input_unit.size(); i++) {
219 m_buffer_reads += m_input_unit[i]->get_buf_read_activity(j);
220 m_buffer_writes += m_input_unit[i]->get_buf_write_activity(j);
221 }
222 }
223
224 m_sw_input_arbiter_activity = switchAllocator.get_input_arbiter_activity();
225 m_sw_output_arbiter_activity =
226 switchAllocator.get_output_arbiter_activity();
227 m_crossbar_activity = crossbarSwitch.get_crossbar_activity();
228 }
229
230 void
231 Router::resetStats()
232 {
233 for (int i = 0; i < m_input_unit.size(); i++) {
234 m_input_unit[i]->resetStats();
235 }
236
237 crossbarSwitch.resetStats();
238 switchAllocator.resetStats();
239 }
240
241 void
242 Router::printFaultVector(ostream& out)
243 {
244 int temperature_celcius = BASELINE_TEMPERATURE_CELCIUS;
245 int num_fault_types = m_network_ptr->fault_model->number_of_fault_types;
246 float fault_vector[num_fault_types];
247 get_fault_vector(temperature_celcius, fault_vector);
248 out << "Router-" << m_id << " fault vector: " << endl;
249 for (int fault_type_index = 0; fault_type_index < num_fault_types;
250 fault_type_index++) {
251 out << " - probability of (";
252 out <<
253 m_network_ptr->fault_model->fault_type_to_string(fault_type_index);
254 out << ") = ";
255 out << fault_vector[fault_type_index] << endl;
256 }
257 }
258
259 void
260 Router::printAggregateFaultProbability(std::ostream& out)
261 {
262 int temperature_celcius = BASELINE_TEMPERATURE_CELCIUS;
263 float aggregate_fault_prob;
264 get_aggregate_fault_probability(temperature_celcius,
265 &aggregate_fault_prob);
266 out << "Router-" << m_id << " fault probability: ";
267 out << aggregate_fault_prob << endl;
268 }
269
270 uint32_t
271 Router::functionalWrite(Packet *pkt)
272 {
273 uint32_t num_functional_writes = 0;
274 num_functional_writes += crossbarSwitch.functionalWrite(pkt);
275
276 for (uint32_t i = 0; i < m_input_unit.size(); i++) {
277 num_functional_writes += m_input_unit[i]->functionalWrite(pkt);
278 }
279
280 for (uint32_t i = 0; i < m_output_unit.size(); i++) {
281 num_functional_writes += m_output_unit[i]->functionalWrite(pkt);
282 }
283
284 return num_functional_writes;
285 }
286
287 Router *
288 GarnetRouterParams::create() const
289 {
290 return new Router(*this);
291 }