2 * Copyright (c) 2008 Princeton University
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.
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.
28 * Authors: Niket Agarwal
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/fixed-pipeline/NetworkInterface_d.hh"
39 #include "mem/ruby/network/garnet/fixed-pipeline/flitBuffer_d.hh"
40 #include "mem/ruby/slicc_interface/NetworkMessage.hh"
43 using m5::stl_helpers::deletePointers
;
45 NetworkInterface_d::NetworkInterface_d(const Params
*p
)
46 : ClockedObject(p
), Consumer(this)
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
;
54 m_ni_buffers
.resize(m_num_vcs
);
55 m_ni_enqueue_time
.resize(m_num_vcs
);
56 creditQueue
= new flitBuffer_d();
58 // instantiating the NI flit buffers
59 for (int i
= 0; i
< m_num_vcs
; i
++) {
60 m_ni_buffers
[i
] = new flitBuffer_d();
61 m_ni_enqueue_time
[i
] = Cycles(INFINITE_
);
64 m_vc_allocator
.resize(m_virtual_networks
); // 1 allocator per vnet
65 for (int i
= 0; i
< m_virtual_networks
; i
++) {
66 m_vc_allocator
[i
] = 0;
71 NetworkInterface_d::init()
73 for (int i
= 0; i
< m_num_vcs
; i
++) {
74 m_out_vc_state
.push_back(new OutVcState_d(i
, m_net_ptr
));
78 NetworkInterface_d::~NetworkInterface_d()
80 deletePointers(m_out_vc_state
);
81 deletePointers(m_ni_buffers
);
87 NetworkInterface_d::addInPort(NetworkLink_d
*in_link
,
88 CreditLink_d
*credit_link
)
91 in_link
->setLinkConsumer(this);
92 m_ni_credit_link
= credit_link
;
93 credit_link
->setSourceQueue(creditQueue
);
97 NetworkInterface_d::addOutPort(NetworkLink_d
*out_link
,
98 CreditLink_d
*credit_link
)
100 m_credit_link
= credit_link
;
101 credit_link
->setLinkConsumer(this);
103 outNetLink
= out_link
;
104 outSrcQueue
= new flitBuffer_d();
105 out_link
->setSourceQueue(outSrcQueue
);
109 NetworkInterface_d::addNode(map
<int, MessageBuffer
*>& in
,
110 map
<int, MessageBuffer
*>& out
)
115 for (auto& it
: in
) {
116 // the protocol injects messages into the NI
117 it
.second
->setConsumer(this);
118 it
.second
->setReceiver(this);
121 for (auto& it
: out
) {
122 it
.second
->setSender(this);
127 NetworkInterface_d::flitisizeMessage(MsgPtr msg_ptr
, int vnet
)
129 NetworkMessage
*net_msg_ptr
= safe_cast
<NetworkMessage
*>(msg_ptr
.get());
130 NetDest net_msg_dest
= net_msg_ptr
->getInternalDestination();
132 // gets all the destinations associated with this message.
133 vector
<NodeID
> dest_nodes
= net_msg_dest
.getAllDest();
135 // Number of flits is dependent on the link bandwidth available.
136 // This is expressed in terms of bytes/cycle or the flit size
137 int num_flits
= (int) ceil((double) m_net_ptr
->MessageSizeType_to_int(
138 net_msg_ptr
->getMessageSize())/m_net_ptr
->getNiFlitSize());
140 // loop to convert all multicast messages into unicast messages
141 for (int ctr
= 0; ctr
< dest_nodes
.size(); ctr
++) {
143 // this will return a free output virtual channel
144 int vc
= calculateVC(vnet
);
149 MsgPtr new_msg_ptr
= msg_ptr
->clone();
150 NodeID destID
= dest_nodes
[ctr
];
152 NetworkMessage
*new_net_msg_ptr
=
153 safe_cast
<NetworkMessage
*>(new_msg_ptr
.get());
154 if (dest_nodes
.size() > 1) {
155 NetDest personal_dest
;
156 for (int m
= 0; m
< (int) MachineType_NUM
; m
++) {
157 if ((destID
>= MachineType_base_number((MachineType
) m
)) &&
158 destID
< MachineType_base_number((MachineType
) (m
+1))) {
159 // calculating the NetDest associated with this destID
160 personal_dest
.clear();
161 personal_dest
.add((MachineID
) {(MachineType
) m
, (destID
-
162 MachineType_base_number((MachineType
) m
))});
163 new_net_msg_ptr
->getInternalDestination() = personal_dest
;
167 net_msg_dest
.removeNetDest(personal_dest
);
168 // removing the destination from the original message to reflect
169 // that a message with this particular destination has been
170 // flitisized and an output vc is acquired
171 net_msg_ptr
->getInternalDestination().removeNetDest(personal_dest
);
174 for (int i
= 0; i
< num_flits
; i
++) {
175 m_net_ptr
->increment_injected_flits(vnet
);
176 flit_d
*fl
= new flit_d(i
, vc
, vnet
, num_flits
, new_msg_ptr
,
179 fl
->set_delay(curCycle() - ticksToCycles(msg_ptr
->getTime()));
180 m_ni_buffers
[vc
]->insert(fl
);
183 m_ni_enqueue_time
[vc
] = curCycle();
184 m_out_vc_state
[vc
]->setState(ACTIVE_
, curCycle());
189 // Looking for a free output vc
191 NetworkInterface_d::calculateVC(int vnet
)
193 for (int i
= 0; i
< m_vc_per_vnet
; i
++) {
194 int delta
= m_vc_allocator
[vnet
];
195 m_vc_allocator
[vnet
]++;
196 if(m_vc_allocator
[vnet
] == m_vc_per_vnet
)
197 m_vc_allocator
[vnet
] = 0;
199 if (m_out_vc_state
[(vnet
*m_vc_per_vnet
) + delta
]->isInState(
200 IDLE_
, curCycle())) {
201 return ((vnet
*m_vc_per_vnet
) + delta
);
208 * The NI wakeup checks whether there are any ready messages in the protocol
209 * buffer. If yes, it picks that up, flitisizes it into a number of flits and
210 * puts it into an output buffer and schedules the output link. On a wakeup
211 * it also checks whether there are flits in the input link. If yes, it picks
212 * them up and if the flit is a tail, the NI inserts the corresponding message
213 * into the protocol buffer. It also checks for credits being sent by the
218 NetworkInterface_d::wakeup()
220 DPRINTF(RubyNetwork
, "m_id: %d woke up at time: %lld", m_id
, curCycle());
224 // Checking for messages coming from the protocol
225 // can pick up a message/cycle for each virtual net
226 for (auto it
= inNode_ptr
.begin(); it
!= inNode_ptr
.end(); ++it
) {
227 int vnet
= (*it
).first
;
228 MessageBuffer
*b
= (*it
).second
;
230 while (b
->isReady()) { // Is there a message waiting
231 msg_ptr
= b
->peekMsgPtr();
232 if (flitisizeMessage(msg_ptr
, vnet
)) {
240 scheduleOutputLink();
243 /*********** Picking messages destined for this NI **********/
245 if (inNetLink
->isReady(curCycle())) {
246 flit_d
*t_flit
= inNetLink
->consumeLink();
247 bool free_signal
= false;
248 if (t_flit
->get_type() == TAIL_
|| t_flit
->get_type() == HEAD_TAIL_
) {
251 outNode_ptr
[t_flit
->get_vnet()]->enqueue(
252 t_flit
->get_msg_ptr(), Cycles(1));
254 // Simply send a credit back since we are not buffering
255 // this flit in the NI
256 flit_d
*credit_flit
= new flit_d(t_flit
->get_vc(), free_signal
,
258 creditQueue
->insert(credit_flit
);
260 scheduleEventAbsolute(clockEdge(Cycles(1)));
262 int vnet
= t_flit
->get_vnet();
263 m_net_ptr
->increment_received_flits(vnet
);
264 Cycles network_delay
= curCycle() - t_flit
->get_enqueue_time();
265 Cycles queueing_delay
= t_flit
->get_delay();
267 m_net_ptr
->increment_network_latency(network_delay
, vnet
);
268 m_net_ptr
->increment_queueing_latency(queueing_delay
, vnet
);
272 /****************** Checking for credit link *******/
274 if (m_credit_link
->isReady(curCycle())) {
275 flit_d
*t_flit
= m_credit_link
->consumeLink();
276 m_out_vc_state
[t_flit
->get_vc()]->increment_credit();
277 if (t_flit
->is_free_signal()) {
278 m_out_vc_state
[t_flit
->get_vc()]->setState(IDLE_
, curCycle());
284 /** This function looks at the NI buffers
285 * if some buffer has flits which are ready to traverse the link in the next
286 * cycle, and the downstream output vc associated with this flit has buffers
287 * left, the link is scheduled for the next cycle
291 NetworkInterface_d::scheduleOutputLink()
293 int vc
= m_vc_round_robin
;
295 if (m_vc_round_robin
== m_num_vcs
)
296 m_vc_round_robin
= 0;
298 for (int i
= 0; i
< m_num_vcs
; i
++) {
303 // model buffer backpressure
304 if (m_ni_buffers
[vc
]->isReady(curCycle()) &&
305 m_out_vc_state
[vc
]->has_credits()) {
307 bool is_candidate_vc
= true;
308 int t_vnet
= get_vnet(vc
);
309 int vc_base
= t_vnet
* m_vc_per_vnet
;
311 if (m_net_ptr
->isVNetOrdered(t_vnet
)) {
312 for (int vc_offset
= 0; vc_offset
< m_vc_per_vnet
;
314 int t_vc
= vc_base
+ vc_offset
;
315 if (m_ni_buffers
[t_vc
]->isReady(curCycle())) {
316 if (m_ni_enqueue_time
[t_vc
] < m_ni_enqueue_time
[vc
]) {
317 is_candidate_vc
= false;
323 if (!is_candidate_vc
)
326 m_out_vc_state
[vc
]->decrement_credit();
327 // Just removing the flit
328 flit_d
*t_flit
= m_ni_buffers
[vc
]->getTopFlit();
329 t_flit
->set_time(curCycle() + Cycles(1));
330 outSrcQueue
->insert(t_flit
);
331 // schedule the out link
332 outNetLink
->scheduleEventAbsolute(clockEdge(Cycles(1)));
334 if (t_flit
->get_type() == TAIL_
||
335 t_flit
->get_type() == HEAD_TAIL_
) {
336 m_ni_enqueue_time
[vc
] = Cycles(INFINITE_
);
344 NetworkInterface_d::get_vnet(int vc
)
346 for (int i
= 0; i
< m_virtual_networks
; i
++) {
347 if (vc
>= (i
*m_vc_per_vnet
) && vc
< ((i
+1)*m_vc_per_vnet
)) {
351 fatal("Could not determine vc");
355 NetworkInterface_d::checkReschedule()
357 for (const auto& it
: inNode_ptr
) {
358 MessageBuffer
*b
= it
.second
;
360 while (b
->isReady()) { // Is there a message waiting
361 scheduleEvent(Cycles(1));
366 for (int vc
= 0; vc
< m_num_vcs
; vc
++) {
367 if (m_ni_buffers
[vc
]->isReady(curCycle() + Cycles(1))) {
368 scheduleEvent(Cycles(1));
375 NetworkInterface_d::print(std::ostream
& out
) const
377 out
<< "[Network Interface]";
381 NetworkInterface_d::functionalWrite(Packet
*pkt
)
383 uint32_t num_functional_writes
= 0;
384 for (unsigned int i
= 0; i
< m_num_vcs
; ++i
) {
385 num_functional_writes
+= m_ni_buffers
[i
]->functionalWrite(pkt
);
388 num_functional_writes
+= outSrcQueue
->functionalWrite(pkt
);
389 return num_functional_writes
;
393 GarnetNetworkInterface_dParams::create()
395 return new NetworkInterface_d(this);