13bbe2b08181aa2032b5d50b7ff73411862872d7
[gem5.git] / src / mem / ruby / network / garnet / flexible-pipeline / NetworkInterface.cc
1 /*
2 * Copyright (c) 2008 Princeton University
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met: redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer;
9 * redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution;
12 * neither the name of the copyright holders nor the names of its
13 * contributors may be used to endorse or promote products derived from
14 * this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 *
28 * Authors: Niket Agarwal
29 */
30
31 #include <cassert>
32 #include <cmath>
33
34 #include "base/cast.hh"
35 #include "base/stl_helpers.hh"
36 #include "debug/RubyNetwork.hh"
37 #include "mem/ruby/network/MessageBuffer.hh"
38 #include "mem/ruby/network/garnet/flexible-pipeline/NetworkInterface.hh"
39 #include "mem/ruby/network/garnet/flexible-pipeline/flitBuffer.hh"
40 #include "mem/ruby/slicc_interface/NetworkMessage.hh"
41
42 using namespace std;
43 using m5::stl_helpers::deletePointers;
44
45 NetworkInterface::NetworkInterface(const Params *p)
46 : ClockedObject(p), FlexibleConsumer(this)
47 {
48 m_id = p->id;
49 m_virtual_networks = p->virt_nets;
50 m_vc_per_vnet = p->vcs_per_vnet;
51 m_num_vcs = m_vc_per_vnet*m_virtual_networks;
52
53 m_vc_round_robin = 0;
54 m_ni_buffers.resize(m_num_vcs);
55 inNode_ptr.resize(m_virtual_networks);
56 outNode_ptr.resize(m_virtual_networks);
57
58 // instantiating the NI flit buffers
59 for (int i =0; i < m_num_vcs; i++)
60 m_ni_buffers[i] = new flitBuffer();
61
62 m_vc_allocator.resize(m_virtual_networks);
63 for (int i = 0; i < m_virtual_networks; i++) {
64 m_vc_allocator[i] = 0;
65 }
66
67 for (int i = 0; i < m_num_vcs; i++) {
68 m_out_vc_state.push_back(new OutVcState(i));
69 }
70 }
71
72 NetworkInterface::~NetworkInterface()
73 {
74 deletePointers(m_out_vc_state);
75 deletePointers(m_ni_buffers);
76 delete outSrcQueue;
77 }
78
79 void
80 NetworkInterface::addInPort(NetworkLink *in_link)
81 {
82 inNetLink = in_link;
83 in_link->setLinkConsumer(this);
84 }
85
86 void
87 NetworkInterface::addOutPort(NetworkLink *out_link)
88 {
89 outNetLink = out_link;
90 outSrcQueue = new flitBuffer();
91 out_link->setSourceQueue(outSrcQueue);
92 out_link->setSource(this);
93 }
94
95 void
96 NetworkInterface::addNode(vector<MessageBuffer*>& in,
97 vector<MessageBuffer*>& out)
98 {
99 assert(in.size() == m_virtual_networks);
100 inNode_ptr = in;
101 outNode_ptr = out;
102
103 // protocol injects messages into the NI
104 for (int j = 0; j < m_virtual_networks; j++) {
105 inNode_ptr[j]->setConsumer(this);
106 inNode_ptr[j]->setReceiver(this);
107 outNode_ptr[j]->setSender(this);
108 }
109 }
110
111 void
112 NetworkInterface::request_vc(int in_vc, int in_port, NetDest destination,
113 Cycles request_time)
114 {
115 inNetLink->grant_vc_link(in_vc, request_time);
116 }
117
118 bool
119 NetworkInterface::flitisizeMessage(MsgPtr msg_ptr, int vnet)
120 {
121 NetworkMessage *net_msg_ptr = safe_cast<NetworkMessage *>(msg_ptr.get());
122 NetDest net_msg_dest = net_msg_ptr->getInternalDestination();
123
124 // get all the destinations associated with this message.
125 vector<NodeID> dest_nodes = net_msg_dest.getAllDest();
126
127 // Number of flits is dependent on the link bandwidth available.
128 // This is expressed in terms of bytes/cycle or the flit size
129
130 int num_flits = (int) ceil((double) m_net_ptr->MessageSizeType_to_int(
131 net_msg_ptr->getMessageSize())/m_net_ptr->getNiFlitSize());
132
133 // loop to convert all multicast messages into unicast messages
134 for (int ctr = 0; ctr < dest_nodes.size(); ctr++) {
135 int vc = calculateVC(vnet); // this will return a free output vc
136
137 if (vc == -1) {
138 // did not find a free output vc
139 return false ;
140 }
141 MsgPtr new_msg_ptr = msg_ptr->clone();
142 NodeID destID = dest_nodes[ctr];
143
144 NetworkMessage *new_net_msg_ptr =
145 safe_cast<NetworkMessage *>(new_msg_ptr.get());
146 if (dest_nodes.size() > 1) {
147 NetDest personal_dest;
148 for (int m = 0; m < (int) MachineType_NUM; m++) {
149 if ((destID >= MachineType_base_number((MachineType) m)) &&
150 destID < MachineType_base_number((MachineType) (m+1))) {
151 // calculating the NetDest associated with this destID
152 personal_dest.clear();
153 personal_dest.add((MachineID) {(MachineType) m, (destID -
154 MachineType_base_number((MachineType) m))});
155 new_net_msg_ptr->getInternalDestination() = personal_dest;
156 break;
157 }
158 }
159 net_msg_dest.removeNetDest(personal_dest);
160
161 // removing the destination from the original message to reflect
162 // that a message with this particular destination has been
163 // flitisized and an output vc is acquired
164 net_msg_ptr->getInternalDestination().removeNetDest(personal_dest);
165 }
166 for (int i = 0; i < num_flits; i++) {
167 m_net_ptr->increment_injected_flits(vnet);
168 flit *fl = new flit(i, vc, vnet, num_flits, new_msg_ptr,
169 curCycle());
170 fl->set_delay(curCycle() - ticksToCycles(msg_ptr->getTime()));
171 m_ni_buffers[vc]->insert(fl);
172 }
173
174 m_out_vc_state[vc]->setState(VC_AB_, curCycle());
175
176 // setting an output vc request for the next hop.
177 // This flit will be ready to traverse the link and into the next hop
178 // only when an output vc is acquired at the next hop
179 outNetLink->request_vc_link(
180 vc, new_net_msg_ptr->getInternalDestination(), curCycle());
181 }
182
183 return true ;
184 }
185
186 // An output vc has been granted at the next hop to one of the vc's.
187 // We have to update the state of the vc to reflect this
188 void
189 NetworkInterface::grant_vc(int out_port, int vc, Cycles grant_time)
190 {
191 assert(m_out_vc_state[vc]->isInState(VC_AB_, grant_time));
192 m_out_vc_state[vc]->grant_vc(grant_time);
193 scheduleEvent(Cycles(1));
194 }
195
196 // The tail flit corresponding to this vc has been buffered at the next hop
197 // and thus this vc is now free
198 void
199 NetworkInterface::release_vc(int out_port, int vc, Cycles release_time)
200 {
201 assert(m_out_vc_state[vc]->isInState(ACTIVE_, release_time));
202 m_out_vc_state[vc]->setState(IDLE_, release_time);
203 scheduleEvent(Cycles(1));
204 }
205
206 // Looking for a free output vc
207 int
208 NetworkInterface::calculateVC(int vnet)
209 {
210 int vc_per_vnet;
211 if (m_net_ptr->isVNetOrdered(vnet))
212 vc_per_vnet = 1;
213 else
214 vc_per_vnet = m_vc_per_vnet;
215
216 for (int i = 0; i < vc_per_vnet; i++) {
217 int delta = m_vc_allocator[vnet];
218 m_vc_allocator[vnet]++;
219 if (m_vc_allocator[vnet] == vc_per_vnet)
220 m_vc_allocator[vnet] = 0;
221
222 if (m_out_vc_state[(vnet*m_vc_per_vnet) + delta]->
223 isInState(IDLE_, curCycle())) {
224 return ((vnet*m_vc_per_vnet) + delta);
225 }
226 }
227 return -1;
228 }
229
230 /*
231 * The NI wakeup checks whether there are any ready messages in the protocol
232 * buffer. If yes, it picks that up, flitisizes it into a number of flits and
233 * puts it into an output buffer and schedules the output link.
234 * On a wakeup it also checks whether there are flits in the input link.
235 * If yes, it picks them up and if the flit is a tail, the NI inserts the
236 * corresponding message into the protocol buffer.
237 */
238
239 void
240 NetworkInterface::wakeup()
241 {
242 MsgPtr msg_ptr;
243
244 //Checking for messages coming from the protocol
245 // can pick up a message/cycle for each virtual net
246 for (int vnet = 0; vnet < m_virtual_networks; vnet++) {
247 while (inNode_ptr[vnet]->isReady()) // Is there a message waiting
248 {
249 msg_ptr = inNode_ptr[vnet]->peekMsgPtr();
250 if (flitisizeMessage(msg_ptr, vnet)) {
251 inNode_ptr[vnet]->dequeue();
252 } else {
253 break;
254 }
255 }
256 }
257
258 scheduleOutputLink();
259 checkReschedule();
260
261 /*********** Picking messages destined for this NI **********/
262
263 if (inNetLink->isReady()) {
264 flit *t_flit = inNetLink->consumeLink();
265 if (t_flit->get_type() == TAIL_ || t_flit->get_type() == HEAD_TAIL_) {
266 DPRINTF(RubyNetwork, "m_id: %d, Message delivered at time: %lld\n",
267 m_id, curCycle());
268
269 outNode_ptr[t_flit->get_vnet()]->enqueue(
270 t_flit->get_msg_ptr(), Cycles(1));
271
272 // signal the upstream router that this vc can be freed now
273 inNetLink->release_vc_link(t_flit->get_vc(),
274 curCycle() + Cycles(1));
275 }
276
277 int vnet = t_flit->get_vnet();
278 m_net_ptr->increment_received_flits(vnet);
279 Cycles network_delay = curCycle() - t_flit->get_enqueue_time();
280 Cycles queueing_delay = t_flit->get_delay();
281
282 m_net_ptr->increment_network_latency(network_delay, vnet);
283 m_net_ptr->increment_queueing_latency(queueing_delay, vnet);
284 delete t_flit;
285 }
286 }
287
288 /* This function looks at the NI buffers and if some buffer has flits which
289 * are ready to traverse the link in the next cycle and also the downstream
290 * output vc associated with this flit has buffers left, the link is scheduled
291 * for the next cycle
292 */
293
294 void
295 NetworkInterface::scheduleOutputLink()
296 {
297 int vc = m_vc_round_robin;
298 m_vc_round_robin++;
299 if (m_vc_round_robin == m_num_vcs)
300 m_vc_round_robin = 0;
301
302 for (int i = 0; i < m_num_vcs; i++) {
303 vc++;
304 if (vc == m_num_vcs)
305 vc = 0;
306 if (m_ni_buffers[vc]->isReady(curCycle())) {
307 if (m_out_vc_state[vc]->isInState(ACTIVE_, curCycle()) &&
308 outNetLink->isBufferNotFull_link(vc)) { // buffer backpressure
309
310 // Just removing the flit
311 flit *t_flit = m_ni_buffers[vc]->getTopFlit();
312 t_flit->set_time(curCycle() + Cycles(1));
313 outSrcQueue->insert(t_flit);
314
315 // schedule the out link
316 outNetLink->
317 scheduleEventAbsolute(clockEdge(Cycles(1)));
318 return;
319 }
320 }
321 }
322 }
323
324 void
325 NetworkInterface::checkReschedule()
326 {
327 for (int vnet = 0; vnet < m_virtual_networks; vnet++) {
328 if (inNode_ptr[vnet]->isReady()) { // Is there a message waiting
329 scheduleEvent(Cycles(1));
330 return;
331 }
332 }
333 for (int vc = 0; vc < m_num_vcs; vc++) {
334 if (m_ni_buffers[vc]->isReadyForNext(curCycle())) {
335 scheduleEvent(Cycles(1));
336 return;
337 }
338 }
339 }
340
341 bool
342 NetworkInterface::functionalRead(Packet *pkt)
343 {
344 // Go through the internal buffers
345 for (unsigned int i = 0; i < m_ni_buffers.size(); ++i) {
346 if (m_ni_buffers[i]->functionalRead(pkt)) {
347 return true;
348 }
349 }
350
351 // Go through the buffer between this network interface and the router
352 if (outSrcQueue->functionalRead(pkt)) {
353 return true;
354 }
355
356 return false;
357 }
358
359 uint32_t
360 NetworkInterface::functionalWrite(Packet *pkt)
361 {
362 uint32_t num_functional_writes = 0;
363 for (unsigned int i = 0; i < m_ni_buffers.size(); ++i) {
364 num_functional_writes += m_ni_buffers[i]->functionalWrite(pkt);
365 }
366
367 num_functional_writes += outSrcQueue->functionalWrite(pkt);
368 return num_functional_writes;
369 }
370
371 void
372 NetworkInterface::print(std::ostream& out) const
373 {
374 out << "[Network Interface]";
375 }
376
377 NetworkInterface *
378 GarnetNetworkInterfaceParams::create()
379 {
380 return new NetworkInterface(this);
381 }