2 * Copyright (c) 2019-2020 ARM Limited
5 * The license below extends only to copyright in the software and shall
6 * not be construed as granting a license to any other intellectual
7 * property including but not limited to intellectual property relating
8 * to a hardware implementation of the functionality of the software
9 * licensed hereunder. You may use the software subject to the license
10 * terms below provided that you ensure that this notice is replicated
11 * unmodified and in its entirety in all distributions of the software,
12 * modified or unmodified, in source code or in binary form.
14 * Copyright (c) 1999-2008 Mark D. Hill and David A. Wood
15 * Copyright (c) 2013 Advanced Micro Devices, Inc.
16 * All rights reserved.
18 * Redistribution and use in source and binary forms, with or without
19 * modification, are permitted provided that the following conditions are
20 * met: redistributions of source code must retain the above copyright
21 * notice, this list of conditions and the following disclaimer;
22 * redistributions in binary form must reproduce the above copyright
23 * notice, this list of conditions and the following disclaimer in the
24 * documentation and/or other materials provided with the distribution;
25 * neither the name of the copyright holders nor the names of its
26 * contributors may be used to endorse or promote products derived from
27 * this software without specific prior written permission.
29 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
30 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
31 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
32 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
33 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
34 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
35 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
36 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
37 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
38 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
39 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
42 #include "mem/ruby/system/Sequencer.hh"
44 #include "arch/x86/ldstflags.hh"
45 #include "base/logging.hh"
46 #include "base/str.hh"
47 #include "cpu/testers/rubytest/RubyTester.hh"
48 #include "debug/LLSC.hh"
49 #include "debug/MemoryAccess.hh"
50 #include "debug/ProtocolTrace.hh"
51 #include "debug/RubySequencer.hh"
52 #include "debug/RubyStats.hh"
53 #include "mem/packet.hh"
54 #include "mem/ruby/profiler/Profiler.hh"
55 #include "mem/ruby/protocol/PrefetchBit.hh"
56 #include "mem/ruby/protocol/RubyAccessMode.hh"
57 #include "mem/ruby/slicc_interface/RubyRequest.hh"
58 #include "mem/ruby/slicc_interface/RubySlicc_Util.hh"
59 #include "mem/ruby/system/RubySystem.hh"
60 #include "sim/system.hh"
65 RubySequencerParams::create()
67 return new Sequencer(this);
70 Sequencer::Sequencer(const Params
*p
)
71 : RubyPort(p
), m_IncompleteTimes(MachineType_NUM
),
72 deadlockCheckEvent([this]{ wakeup(); }, "Sequencer deadlock check")
74 m_outstanding_count
= 0;
76 m_instCache_ptr
= p
->icache
;
77 m_dataCache_ptr
= p
->dcache
;
78 m_max_outstanding_requests
= p
->max_outstanding_requests
;
79 m_deadlock_threshold
= p
->deadlock_threshold
;
81 m_coreId
= p
->coreid
; // for tracking the two CorePair sequencers
82 assert(m_max_outstanding_requests
> 0);
83 assert(m_deadlock_threshold
> 0);
84 assert(m_instCache_ptr
!= NULL
);
85 assert(m_dataCache_ptr
!= NULL
);
87 m_runningGarnetStandalone
= p
->garnet_standalone
;
90 Sequencer::~Sequencer()
95 Sequencer::llscLoadLinked(const Addr claddr
)
97 AbstractCacheEntry
*line
= m_dataCache_ptr
->lookup(claddr
);
99 line
->setLocked(m_version
);
100 DPRINTF(LLSC
, "LLSC Monitor - inserting load linked - "
101 "addr=0x%lx - cpu=%u\n", claddr
, m_version
);
106 Sequencer::llscClearMonitor(const Addr claddr
)
108 AbstractCacheEntry
*line
= m_dataCache_ptr
->lookup(claddr
);
109 if (line
&& line
->isLocked(m_version
)) {
111 DPRINTF(LLSC
, "LLSC Monitor - clearing due to store - "
112 "addr=0x%lx - cpu=%u\n", claddr
, m_version
);
117 Sequencer::llscStoreConditional(const Addr claddr
)
119 AbstractCacheEntry
*line
= m_dataCache_ptr
->lookup(claddr
);
123 DPRINTF(LLSC
, "LLSC Monitor - clearing due to "
124 "store conditional - "
125 "addr=0x%lx - cpu=%u\n",
128 if (line
->isLocked(m_version
)) {
138 Sequencer::llscCheckMonitor(const Addr address
)
140 const Addr claddr
= makeLineAddress(address
);
141 AbstractCacheEntry
*line
= m_dataCache_ptr
->lookup(claddr
);
145 if (line
->isLocked(m_version
)) {
153 Sequencer::llscClearLocalMonitor()
155 m_dataCache_ptr
->clearLockedAll(m_version
);
161 assert(drainState() != DrainState::Draining
);
163 // Check for deadlock of any of the requests
164 Cycles current_time
= curCycle();
166 // Check across all outstanding requests
167 int total_outstanding
= 0;
169 for (const auto &table_entry
: m_RequestTable
) {
170 for (const auto seq_req
: table_entry
.second
) {
171 if (current_time
- seq_req
.issue_time
< m_deadlock_threshold
)
174 panic("Possible Deadlock detected. Aborting!\n version: %d "
175 "request.paddr: 0x%x m_readRequestTable: %d current time: "
176 "%u issue_time: %d difference: %d\n", m_version
,
177 seq_req
.pkt
->getAddr(), table_entry
.second
.size(),
178 current_time
* clockPeriod(), seq_req
.issue_time
179 * clockPeriod(), (current_time
* clockPeriod())
180 - (seq_req
.issue_time
* clockPeriod()));
182 total_outstanding
+= table_entry
.second
.size();
185 assert(m_outstanding_count
== total_outstanding
);
187 if (m_outstanding_count
> 0) {
188 // If there are still outstanding requests, keep checking
189 schedule(deadlockCheckEvent
, clockEdge(m_deadlock_threshold
));
194 Sequencer::functionalWrite(Packet
*func_pkt
)
196 int num_written
= RubyPort::functionalWrite(func_pkt
);
198 for (const auto &table_entry
: m_RequestTable
) {
199 for (const auto& seq_req
: table_entry
.second
) {
200 if (seq_req
.functionalWrite(func_pkt
))
208 void Sequencer::resetStats()
210 m_outstandReqHist
.reset();
211 m_latencyHist
.reset();
212 m_hitLatencyHist
.reset();
213 m_missLatencyHist
.reset();
214 for (int i
= 0; i
< RubyRequestType_NUM
; i
++) {
215 m_typeLatencyHist
[i
]->reset();
216 m_hitTypeLatencyHist
[i
]->reset();
217 m_missTypeLatencyHist
[i
]->reset();
218 for (int j
= 0; j
< MachineType_NUM
; j
++) {
219 m_hitTypeMachLatencyHist
[i
][j
]->reset();
220 m_missTypeMachLatencyHist
[i
][j
]->reset();
224 for (int i
= 0; i
< MachineType_NUM
; i
++) {
225 m_missMachLatencyHist
[i
]->reset();
226 m_hitMachLatencyHist
[i
]->reset();
228 m_IssueToInitialDelayHist
[i
]->reset();
229 m_InitialToForwardDelayHist
[i
]->reset();
230 m_ForwardToFirstResponseDelayHist
[i
]->reset();
231 m_FirstResponseToCompletionDelayHist
[i
]->reset();
233 m_IncompleteTimes
[i
] = 0;
237 // Insert the request in the request table. Return RequestStatus_Aliased
238 // if the entry was already present.
240 Sequencer::insertRequest(PacketPtr pkt
, RubyRequestType primary_type
,
241 RubyRequestType secondary_type
)
243 // See if we should schedule a deadlock check
244 if (!deadlockCheckEvent
.scheduled() &&
245 drainState() != DrainState::Draining
) {
246 schedule(deadlockCheckEvent
, clockEdge(m_deadlock_threshold
));
249 Addr line_addr
= makeLineAddress(pkt
->getAddr());
250 // Check if there is any outstanding request for the same cache line.
251 auto &seq_req_list
= m_RequestTable
[line_addr
];
252 // Create a default entry
253 seq_req_list
.emplace_back(pkt
, primary_type
,
254 secondary_type
, curCycle());
255 m_outstanding_count
++;
257 if (seq_req_list
.size() > 1) {
258 return RequestStatus_Aliased
;
261 m_outstandReqHist
.sample(m_outstanding_count
);
263 return RequestStatus_Ready
;
267 Sequencer::markRemoved()
269 m_outstanding_count
--;
273 Sequencer::recordMissLatency(SequencerRequest
* srequest
, bool llscSuccess
,
274 const MachineType respondingMach
,
275 bool isExternalHit
, Cycles initialRequestTime
,
276 Cycles forwardRequestTime
,
277 Cycles firstResponseTime
)
279 RubyRequestType type
= srequest
->m_type
;
280 Cycles issued_time
= srequest
->issue_time
;
281 Cycles completion_time
= curCycle();
283 assert(curCycle() >= issued_time
);
284 Cycles total_lat
= completion_time
- issued_time
;
286 if (initialRequestTime
< issued_time
) {
287 // if the request was combined in the protocol with an earlier request
288 // for the same address, it is possible that it will return an
289 // initialRequestTime corresponding the earlier request. Since Cycles
290 // is unsigned, we can't let this request get profiled below.
292 total_lat
= Cycles(0);
295 DPRINTFR(ProtocolTrace
, "%15s %3s %10s%20s %6s>%-6s %s %d cycles\n",
296 curTick(), m_version
, "Seq", llscSuccess
? "Done" : "SC_Failed",
297 "", "", printAddress(srequest
->pkt
->getAddr()), total_lat
);
299 m_latencyHist
.sample(total_lat
);
300 m_typeLatencyHist
[type
]->sample(total_lat
);
303 m_missLatencyHist
.sample(total_lat
);
304 m_missTypeLatencyHist
[type
]->sample(total_lat
);
306 if (respondingMach
!= MachineType_NUM
) {
307 m_missMachLatencyHist
[respondingMach
]->sample(total_lat
);
308 m_missTypeMachLatencyHist
[type
][respondingMach
]->sample(total_lat
);
310 if ((issued_time
<= initialRequestTime
) &&
311 (initialRequestTime
<= forwardRequestTime
) &&
312 (forwardRequestTime
<= firstResponseTime
) &&
313 (firstResponseTime
<= completion_time
)) {
315 m_IssueToInitialDelayHist
[respondingMach
]->sample(
316 initialRequestTime
- issued_time
);
317 m_InitialToForwardDelayHist
[respondingMach
]->sample(
318 forwardRequestTime
- initialRequestTime
);
319 m_ForwardToFirstResponseDelayHist
[respondingMach
]->sample(
320 firstResponseTime
- forwardRequestTime
);
321 m_FirstResponseToCompletionDelayHist
[respondingMach
]->sample(
322 completion_time
- firstResponseTime
);
324 m_IncompleteTimes
[respondingMach
]++;
328 m_hitLatencyHist
.sample(total_lat
);
329 m_hitTypeLatencyHist
[type
]->sample(total_lat
);
331 if (respondingMach
!= MachineType_NUM
) {
332 m_hitMachLatencyHist
[respondingMach
]->sample(total_lat
);
333 m_hitTypeMachLatencyHist
[type
][respondingMach
]->sample(total_lat
);
339 Sequencer::writeCallbackScFail(Addr address
, DataBlock
& data
)
341 llscClearMonitor(address
);
342 writeCallback(address
, data
);
346 Sequencer::writeCallback(Addr address
, DataBlock
& data
,
347 const bool externalHit
, const MachineType mach
,
348 const Cycles initialRequestTime
,
349 const Cycles forwardRequestTime
,
350 const Cycles firstResponseTime
)
353 // Free the whole list as we assume we have had the exclusive access
354 // to this cache line when response for the write comes back
356 assert(address
== makeLineAddress(address
));
357 assert(m_RequestTable
.find(address
) != m_RequestTable
.end());
358 auto &seq_req_list
= m_RequestTable
[address
];
360 // Perform hitCallback on every cpu request made to this cache block while
361 // ruby request was outstanding. Since only 1 ruby request was made,
362 // profile the ruby latency once.
363 bool ruby_request
= true;
364 int aliased_stores
= 0;
365 int aliased_loads
= 0;
366 while (!seq_req_list
.empty()) {
367 SequencerRequest
&seq_req
= seq_req_list
.front();
369 assert(seq_req
.m_type
!= RubyRequestType_LD
);
370 assert(seq_req
.m_type
!= RubyRequestType_Load_Linked
);
371 assert(seq_req
.m_type
!= RubyRequestType_IFETCH
);
374 // handle write request
375 if ((seq_req
.m_type
!= RubyRequestType_LD
) &&
376 (seq_req
.m_type
!= RubyRequestType_Load_Linked
) &&
377 (seq_req
.m_type
!= RubyRequestType_IFETCH
)) {
378 // LL/SC support (tested with ARMv8)
381 if (seq_req
.m_type
!= RubyRequestType_Store_Conditional
) {
382 // Regular stores to addresses being monitored
383 // will fail (remove) the monitor entry.
384 llscClearMonitor(address
);
386 // Store conditionals must first check the monitor
387 // if they will succeed or not
388 success
= llscStoreConditional(address
);
389 seq_req
.pkt
->req
->setExtraData(success
? 1 : 0);
392 // Handle SLICC block_on behavior for Locked_RMW accesses. NOTE: the
393 // address variable here is assumed to be a line address, so when
394 // blocking buffers, must check line addresses.
395 if (seq_req
.m_type
== RubyRequestType_Locked_RMW_Read
) {
396 // blockOnQueue blocks all first-level cache controller queues
397 // waiting on memory accesses for the specified address that go
398 // to the specified queue. In this case, a Locked_RMW_Write must
399 // go to the mandatory_q before unblocking the first-level
400 // controller. This will block standard loads, stores, ifetches,
402 m_controller
->blockOnQueue(address
, m_mandatory_q_ptr
);
403 } else if (seq_req
.m_type
== RubyRequestType_Locked_RMW_Write
) {
404 m_controller
->unblock(address
);
408 recordMissLatency(&seq_req
, success
, mach
, externalHit
,
409 initialRequestTime
, forwardRequestTime
,
415 ruby_request
= false;
416 hitCallback(&seq_req
, data
, success
, mach
, externalHit
,
417 initialRequestTime
, forwardRequestTime
,
420 // handle read request
421 assert(!ruby_request
);
423 ruby_request
= false;
425 hitCallback(&seq_req
, data
, true, mach
, externalHit
,
426 initialRequestTime
, forwardRequestTime
,
429 seq_req_list
.pop_front();
432 // free all outstanding requests corresponding to this address
433 if (seq_req_list
.empty()) {
434 m_RequestTable
.erase(address
);
439 Sequencer::readCallback(Addr address
, DataBlock
& data
,
440 bool externalHit
, const MachineType mach
,
441 Cycles initialRequestTime
,
442 Cycles forwardRequestTime
,
443 Cycles firstResponseTime
)
446 // Free up read requests until we hit the first Write request
447 // or end of the corresponding list.
449 assert(address
== makeLineAddress(address
));
450 assert(m_RequestTable
.find(address
) != m_RequestTable
.end());
451 auto &seq_req_list
= m_RequestTable
[address
];
453 // Perform hitCallback on every cpu request made to this cache block while
454 // ruby request was outstanding. Since only 1 ruby request was made,
455 // profile the ruby latency once.
456 bool ruby_request
= true;
457 int aliased_loads
= 0;
458 while (!seq_req_list
.empty()) {
459 SequencerRequest
&seq_req
= seq_req_list
.front();
461 assert((seq_req
.m_type
== RubyRequestType_LD
) ||
462 (seq_req
.m_type
== RubyRequestType_Load_Linked
) ||
463 (seq_req
.m_type
== RubyRequestType_IFETCH
));
467 if ((seq_req
.m_type
!= RubyRequestType_LD
) &&
468 (seq_req
.m_type
!= RubyRequestType_Load_Linked
) &&
469 (seq_req
.m_type
!= RubyRequestType_IFETCH
)) {
470 // Write request: reissue request to the cache hierarchy
471 issueRequest(seq_req
.pkt
, seq_req
.m_second_type
);
475 recordMissLatency(&seq_req
, true, mach
, externalHit
,
476 initialRequestTime
, forwardRequestTime
,
480 ruby_request
= false;
481 hitCallback(&seq_req
, data
, true, mach
, externalHit
,
482 initialRequestTime
, forwardRequestTime
,
484 seq_req_list
.pop_front();
487 // free all outstanding requests corresponding to this address
488 if (seq_req_list
.empty()) {
489 m_RequestTable
.erase(address
);
494 Sequencer::hitCallback(SequencerRequest
* srequest
, DataBlock
& data
,
496 const MachineType mach
, const bool externalHit
,
497 const Cycles initialRequestTime
,
498 const Cycles forwardRequestTime
,
499 const Cycles firstResponseTime
)
501 warn_once("Replacement policy updates recently became the responsibility "
502 "of SLICC state machines. Make sure to setMRU() near callbacks "
505 PacketPtr pkt
= srequest
->pkt
;
506 Addr
request_address(pkt
->getAddr());
507 RubyRequestType type
= srequest
->m_type
;
509 // Load-linked handling
510 if (type
== RubyRequestType_Load_Linked
) {
511 Addr line_addr
= makeLineAddress(request_address
);
512 llscLoadLinked(line_addr
);
515 // update the data unless it is a non-data-carrying flush
516 if (RubySystem::getWarmupEnabled()) {
517 data
.setData(pkt
->getConstPtr
<uint8_t>(),
518 getOffset(request_address
), pkt
->getSize());
519 } else if (!pkt
->isFlush()) {
520 if ((type
== RubyRequestType_LD
) ||
521 (type
== RubyRequestType_IFETCH
) ||
522 (type
== RubyRequestType_RMW_Read
) ||
523 (type
== RubyRequestType_Locked_RMW_Read
) ||
524 (type
== RubyRequestType_Load_Linked
)) {
526 data
.getData(getOffset(request_address
), pkt
->getSize()));
527 DPRINTF(RubySequencer
, "read data %s\n", data
);
528 } else if (pkt
->req
->isSwap()) {
529 std::vector
<uint8_t> overwrite_val(pkt
->getSize());
530 pkt
->writeData(&overwrite_val
[0]);
532 data
.getData(getOffset(request_address
), pkt
->getSize()));
533 data
.setData(&overwrite_val
[0],
534 getOffset(request_address
), pkt
->getSize());
535 DPRINTF(RubySequencer
, "swap data %s\n", data
);
536 } else if (type
!= RubyRequestType_Store_Conditional
|| llscSuccess
) {
537 // Types of stores set the actual data here, apart from
538 // failed Store Conditional requests
539 data
.setData(pkt
->getConstPtr
<uint8_t>(),
540 getOffset(request_address
), pkt
->getSize());
541 DPRINTF(RubySequencer
, "set data %s\n", data
);
545 // If using the RubyTester, update the RubyTester sender state's
546 // subBlock with the recieved data. The tester will later access
548 if (m_usingRubyTester
) {
549 DPRINTF(RubySequencer
, "hitCallback %s 0x%x using RubyTester\n",
550 pkt
->cmdString(), pkt
->getAddr());
551 RubyTester::SenderState
* testerSenderState
=
552 pkt
->findNextSenderState
<RubyTester::SenderState
>();
553 assert(testerSenderState
);
554 testerSenderState
->subBlock
.mergeFrom(data
);
557 RubySystem
*rs
= m_ruby_system
;
558 if (RubySystem::getWarmupEnabled()) {
561 rs
->m_cache_recorder
->enqueueNextFetchRequest();
562 } else if (RubySystem::getCooldownEnabled()) {
564 rs
->m_cache_recorder
->enqueueNextFlushRequest();
566 ruby_hit_callback(pkt
);
572 Sequencer::empty() const
574 return m_RequestTable
.empty();
578 Sequencer::makeRequest(PacketPtr pkt
)
580 // HTM abort signals must be allowed to reach the Sequencer
581 // the same cycle they are issued. They cannot be retried.
582 if ((m_outstanding_count
>= m_max_outstanding_requests
) &&
583 !pkt
->req
->isHTMAbort()) {
584 return RequestStatus_BufferFull
;
587 RubyRequestType primary_type
= RubyRequestType_NULL
;
588 RubyRequestType secondary_type
= RubyRequestType_NULL
;
591 // LL/SC instructions need to be handled carefully by the cache
592 // coherence protocol to ensure they follow the proper semantics. In
593 // particular, by identifying the operations as atomic, the protocol
594 // should understand that migratory sharing optimizations should not
595 // be performed (i.e. a load between the LL and SC should not steal
596 // away exclusive permission).
598 // The following logic works correctly with the semantics
599 // of armV8 LDEX/STEX instructions.
601 if (pkt
->isWrite()) {
602 DPRINTF(RubySequencer
, "Issuing SC\n");
603 primary_type
= RubyRequestType_Store_Conditional
;
604 #if defined (PROTOCOL_MESI_Three_Level) || defined (PROTOCOL_MESI_Three_Level_HTM)
605 secondary_type
= RubyRequestType_Store_Conditional
;
607 secondary_type
= RubyRequestType_ST
;
610 DPRINTF(RubySequencer
, "Issuing LL\n");
611 assert(pkt
->isRead());
612 primary_type
= RubyRequestType_Load_Linked
;
613 secondary_type
= RubyRequestType_LD
;
615 } else if (pkt
->req
->isLockedRMW()) {
617 // x86 locked instructions are translated to store cache coherence
618 // requests because these requests should always be treated as read
619 // exclusive operations and should leverage any migratory sharing
620 // optimization built into the protocol.
622 if (pkt
->isWrite()) {
623 DPRINTF(RubySequencer
, "Issuing Locked RMW Write\n");
624 primary_type
= RubyRequestType_Locked_RMW_Write
;
626 DPRINTF(RubySequencer
, "Issuing Locked RMW Read\n");
627 assert(pkt
->isRead());
628 primary_type
= RubyRequestType_Locked_RMW_Read
;
630 secondary_type
= RubyRequestType_ST
;
633 // To support SwapReq, we need to check isWrite() first: a SwapReq
634 // should always be treated like a write, but since a SwapReq implies
635 // both isWrite() and isRead() are true, check isWrite() first here.
637 if (pkt
->isWrite()) {
639 // Note: M5 packets do not differentiate ST from RMW_Write
641 primary_type
= secondary_type
= RubyRequestType_ST
;
642 } else if (pkt
->isRead()) {
643 // hardware transactional memory commands
644 if (pkt
->req
->isHTMCmd()) {
645 primary_type
= secondary_type
= htmCmdToRubyRequestType(pkt
);
646 } else if (pkt
->req
->isInstFetch()) {
647 primary_type
= secondary_type
= RubyRequestType_IFETCH
;
649 bool storeCheck
= false;
650 // only X86 need the store check
651 if (system
->getArch() == Arch::X86ISA
) {
652 uint32_t flags
= pkt
->req
->getFlags();
654 (X86ISA::StoreCheck
<< X86ISA::FlagShift
);
657 primary_type
= RubyRequestType_RMW_Read
;
658 secondary_type
= RubyRequestType_ST
;
660 primary_type
= secondary_type
= RubyRequestType_LD
;
663 } else if (pkt
->isFlush()) {
664 primary_type
= secondary_type
= RubyRequestType_FLUSH
;
666 panic("Unsupported ruby packet type\n");
670 // Check if the line is blocked for a Locked_RMW
671 if (m_controller
->isBlocked(makeLineAddress(pkt
->getAddr())) &&
672 (primary_type
!= RubyRequestType_Locked_RMW_Write
)) {
673 // Return that this request's cache line address aliases with
674 // a prior request that locked the cache line. The request cannot
675 // proceed until the cache line is unlocked by a Locked_RMW_Write
676 return RequestStatus_Aliased
;
679 RequestStatus status
= insertRequest(pkt
, primary_type
, secondary_type
);
681 // It is OK to receive RequestStatus_Aliased, it can be considered Issued
682 if (status
!= RequestStatus_Ready
&& status
!= RequestStatus_Aliased
)
684 // non-aliased with any existing request in the request table, just issue
686 if (status
!= RequestStatus_Aliased
)
687 issueRequest(pkt
, secondary_type
);
689 // TODO: issue hardware prefetches here
690 return RequestStatus_Issued
;
694 Sequencer::issueRequest(PacketPtr pkt
, RubyRequestType secondary_type
)
697 ContextID proc_id
= pkt
->req
->hasContextId() ?
698 pkt
->req
->contextId() : InvalidContextID
;
700 ContextID core_id
= coreId();
702 // If valid, copy the pc to the ruby request
704 if (pkt
->req
->hasPC()) {
705 pc
= pkt
->req
->getPC();
708 // check if the packet has data as for example prefetch and flush
710 std::shared_ptr
<RubyRequest
> msg
=
711 std::make_shared
<RubyRequest
>(clockEdge(), pkt
->getAddr(),
713 nullptr : pkt
->getPtr
<uint8_t>(),
714 pkt
->getSize(), pc
, secondary_type
,
715 RubyAccessMode_Supervisor
, pkt
,
716 PrefetchBit_No
, proc_id
, core_id
);
718 DPRINTFR(ProtocolTrace
, "%15s %3s %10s%20s %6s>%-6s %#x %s\n",
719 curTick(), m_version
, "Seq", "Begin", "", "",
720 printAddress(msg
->getPhysicalAddress()),
721 RubyRequestType_to_string(secondary_type
));
723 // hardware transactional memory
724 // If the request originates in a transaction,
725 // then mark the Ruby message as such.
726 if (pkt
->isHtmTransactional()) {
727 msg
->m_htmFromTransaction
= true;
728 msg
->m_htmTransactionUid
= pkt
->getHtmTransactionUid();
731 Tick latency
= cyclesToTicks(
732 m_controller
->mandatoryQueueLatency(secondary_type
));
735 assert(m_mandatory_q_ptr
!= NULL
);
736 m_mandatory_q_ptr
->enqueue(msg
, clockEdge(), latency
);
739 template <class KEY
, class VALUE
>
741 operator<<(ostream
&out
, const std::unordered_map
<KEY
, VALUE
> &map
)
743 for (const auto &table_entry
: map
) {
744 out
<< "[ " << table_entry
.first
<< " =";
745 for (const auto &seq_req
: table_entry
.second
) {
746 out
<< " " << RubyRequestType_to_string(seq_req
.m_second_type
);
755 Sequencer::print(ostream
& out
) const
757 out
<< "[Sequencer: " << m_version
758 << ", outstanding requests: " << m_outstanding_count
759 << ", request table: " << m_RequestTable
764 Sequencer::recordRequestType(SequencerRequestType requestType
) {
765 DPRINTF(RubyStats
, "Recorded statistic: %s\n",
766 SequencerRequestType_to_string(requestType
));
770 Sequencer::evictionCallback(Addr address
)
772 llscClearMonitor(address
);
773 ruby_eviction_callback(address
);
777 Sequencer::regStats()
779 RubyPort::regStats();
781 // These statistical variables are not for display.
782 // The profiler will collate these across different
783 // sequencers and display those collated statistics.
784 m_outstandReqHist
.init(10);
785 m_latencyHist
.init(10);
786 m_hitLatencyHist
.init(10);
787 m_missLatencyHist
.init(10);
789 for (int i
= 0; i
< RubyRequestType_NUM
; i
++) {
790 m_typeLatencyHist
.push_back(new Stats::Histogram());
791 m_typeLatencyHist
[i
]->init(10);
793 m_hitTypeLatencyHist
.push_back(new Stats::Histogram());
794 m_hitTypeLatencyHist
[i
]->init(10);
796 m_missTypeLatencyHist
.push_back(new Stats::Histogram());
797 m_missTypeLatencyHist
[i
]->init(10);
800 for (int i
= 0; i
< MachineType_NUM
; i
++) {
801 m_hitMachLatencyHist
.push_back(new Stats::Histogram());
802 m_hitMachLatencyHist
[i
]->init(10);
804 m_missMachLatencyHist
.push_back(new Stats::Histogram());
805 m_missMachLatencyHist
[i
]->init(10);
807 m_IssueToInitialDelayHist
.push_back(new Stats::Histogram());
808 m_IssueToInitialDelayHist
[i
]->init(10);
810 m_InitialToForwardDelayHist
.push_back(new Stats::Histogram());
811 m_InitialToForwardDelayHist
[i
]->init(10);
813 m_ForwardToFirstResponseDelayHist
.push_back(new Stats::Histogram());
814 m_ForwardToFirstResponseDelayHist
[i
]->init(10);
816 m_FirstResponseToCompletionDelayHist
.push_back(new Stats::Histogram());
817 m_FirstResponseToCompletionDelayHist
[i
]->init(10);
820 for (int i
= 0; i
< RubyRequestType_NUM
; i
++) {
821 m_hitTypeMachLatencyHist
.push_back(std::vector
<Stats::Histogram
*>());
822 m_missTypeMachLatencyHist
.push_back(std::vector
<Stats::Histogram
*>());
824 for (int j
= 0; j
< MachineType_NUM
; j
++) {
825 m_hitTypeMachLatencyHist
[i
].push_back(new Stats::Histogram());
826 m_hitTypeMachLatencyHist
[i
][j
]->init(10);
828 m_missTypeMachLatencyHist
[i
].push_back(new Stats::Histogram());
829 m_missTypeMachLatencyHist
[i
][j
]->init(10);