2 * Copyright (c) 1999-2008 Mark D. Hill and David A. Wood
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.
29 #include "mem/ruby/system/Sequencer.hh"
31 #include "arch/x86/ldstflags.hh"
32 #include "base/misc.hh"
33 #include "base/str.hh"
34 #include "cpu/testers/rubytest/RubyTester.hh"
35 #include "debug/MemoryAccess.hh"
36 #include "debug/ProtocolTrace.hh"
37 #include "debug/RubySequencer.hh"
38 #include "debug/RubyStats.hh"
39 #include "mem/packet.hh"
40 #include "mem/protocol/PrefetchBit.hh"
41 #include "mem/protocol/RubyAccessMode.hh"
42 #include "mem/ruby/profiler/Profiler.hh"
43 #include "mem/ruby/slicc_interface/RubyRequest.hh"
44 #include "mem/ruby/system/RubySystem.hh"
45 #include "sim/system.hh"
50 RubySequencerParams::create()
52 return new Sequencer(this);
55 Sequencer::Sequencer(const Params
*p
)
56 : RubyPort(p
), m_IncompleteTimes(MachineType_NUM
), deadlockCheckEvent(this)
58 m_outstanding_count
= 0;
60 m_instCache_ptr
= p
->icache
;
61 m_dataCache_ptr
= p
->dcache
;
62 m_data_cache_hit_latency
= p
->dcache_hit_latency
;
63 m_inst_cache_hit_latency
= p
->icache_hit_latency
;
64 m_max_outstanding_requests
= p
->max_outstanding_requests
;
65 m_deadlock_threshold
= p
->deadlock_threshold
;
67 m_coreId
= p
->coreid
; // for tracking the two CorePair sequencers
68 assert(m_max_outstanding_requests
> 0);
69 assert(m_deadlock_threshold
> 0);
70 assert(m_instCache_ptr
!= NULL
);
71 assert(m_dataCache_ptr
!= NULL
);
72 assert(m_data_cache_hit_latency
> 0);
73 assert(m_inst_cache_hit_latency
> 0);
75 m_runningGarnetStandalone
= p
->garnet_standalone
;
78 Sequencer::~Sequencer()
85 assert(drainState() != DrainState::Draining
);
87 // Check for deadlock of any of the requests
88 Cycles current_time
= curCycle();
90 // Check across all outstanding requests
91 int total_outstanding
= 0;
93 RequestTable::iterator read
= m_readRequestTable
.begin();
94 RequestTable::iterator read_end
= m_readRequestTable
.end();
95 for (; read
!= read_end
; ++read
) {
96 SequencerRequest
* request
= read
->second
;
97 if (current_time
- request
->issue_time
< m_deadlock_threshold
)
100 panic("Possible Deadlock detected. Aborting!\n"
101 "version: %d request.paddr: 0x%x m_readRequestTable: %d "
102 "current time: %u issue_time: %d difference: %d\n", m_version
,
103 request
->pkt
->getAddr(), m_readRequestTable
.size(),
104 current_time
* clockPeriod(), request
->issue_time
* clockPeriod(),
105 (current_time
* clockPeriod()) - (request
->issue_time
* clockPeriod()));
108 RequestTable::iterator write
= m_writeRequestTable
.begin();
109 RequestTable::iterator write_end
= m_writeRequestTable
.end();
110 for (; write
!= write_end
; ++write
) {
111 SequencerRequest
* request
= write
->second
;
112 if (current_time
- request
->issue_time
< m_deadlock_threshold
)
115 panic("Possible Deadlock detected. Aborting!\n"
116 "version: %d request.paddr: 0x%x m_writeRequestTable: %d "
117 "current time: %u issue_time: %d difference: %d\n", m_version
,
118 request
->pkt
->getAddr(), m_writeRequestTable
.size(),
119 current_time
* clockPeriod(), request
->issue_time
* clockPeriod(),
120 (current_time
* clockPeriod()) - (request
->issue_time
* clockPeriod()));
123 total_outstanding
+= m_writeRequestTable
.size();
124 total_outstanding
+= m_readRequestTable
.size();
126 assert(m_outstanding_count
== total_outstanding
);
128 if (m_outstanding_count
> 0) {
129 // If there are still outstanding requests, keep checking
130 schedule(deadlockCheckEvent
, clockEdge(m_deadlock_threshold
));
134 void Sequencer::resetStats()
136 m_latencyHist
.reset();
137 m_hitLatencyHist
.reset();
138 m_missLatencyHist
.reset();
139 for (int i
= 0; i
< RubyRequestType_NUM
; i
++) {
140 m_typeLatencyHist
[i
]->reset();
141 m_hitTypeLatencyHist
[i
]->reset();
142 m_missTypeLatencyHist
[i
]->reset();
143 for (int j
= 0; j
< MachineType_NUM
; j
++) {
144 m_hitTypeMachLatencyHist
[i
][j
]->reset();
145 m_missTypeMachLatencyHist
[i
][j
]->reset();
149 for (int i
= 0; i
< MachineType_NUM
; i
++) {
150 m_missMachLatencyHist
[i
]->reset();
151 m_hitMachLatencyHist
[i
]->reset();
153 m_IssueToInitialDelayHist
[i
]->reset();
154 m_InitialToForwardDelayHist
[i
]->reset();
155 m_ForwardToFirstResponseDelayHist
[i
]->reset();
156 m_FirstResponseToCompletionDelayHist
[i
]->reset();
158 m_IncompleteTimes
[i
] = 0;
162 // Insert the request on the correct request table. Return true if
163 // the entry was already present.
165 Sequencer::insertRequest(PacketPtr pkt
, RubyRequestType request_type
)
167 assert(m_outstanding_count
==
168 (m_writeRequestTable
.size() + m_readRequestTable
.size()));
170 // See if we should schedule a deadlock check
171 if (!deadlockCheckEvent
.scheduled() &&
172 drainState() != DrainState::Draining
) {
173 schedule(deadlockCheckEvent
, clockEdge(m_deadlock_threshold
));
176 Addr line_addr
= makeLineAddress(pkt
->getAddr());
178 // Check if the line is blocked for a Locked_RMW
179 if (m_controller
->isBlocked(line_addr
) &&
180 (request_type
!= RubyRequestType_Locked_RMW_Write
)) {
181 // Return that this request's cache line address aliases with
182 // a prior request that locked the cache line. The request cannot
183 // proceed until the cache line is unlocked by a Locked_RMW_Write
184 return RequestStatus_Aliased
;
187 // Create a default entry, mapping the address to NULL, the cast is
188 // there to make gcc 4.4 happy
189 RequestTable::value_type
default_entry(line_addr
,
190 (SequencerRequest
*) NULL
);
192 if ((request_type
== RubyRequestType_ST
) ||
193 (request_type
== RubyRequestType_RMW_Read
) ||
194 (request_type
== RubyRequestType_RMW_Write
) ||
195 (request_type
== RubyRequestType_Load_Linked
) ||
196 (request_type
== RubyRequestType_Store_Conditional
) ||
197 (request_type
== RubyRequestType_Locked_RMW_Read
) ||
198 (request_type
== RubyRequestType_Locked_RMW_Write
) ||
199 (request_type
== RubyRequestType_FLUSH
)) {
201 // Check if there is any outstanding read request for the same
203 if (m_readRequestTable
.count(line_addr
) > 0) {
204 m_store_waiting_on_load
++;
205 return RequestStatus_Aliased
;
208 pair
<RequestTable::iterator
, bool> r
=
209 m_writeRequestTable
.insert(default_entry
);
211 RequestTable::iterator i
= r
.first
;
212 i
->second
= new SequencerRequest(pkt
, request_type
, curCycle());
213 m_outstanding_count
++;
215 // There is an outstanding write request for the cache line
216 m_store_waiting_on_store
++;
217 return RequestStatus_Aliased
;
220 // Check if there is any outstanding write request for the same
222 if (m_writeRequestTable
.count(line_addr
) > 0) {
223 m_load_waiting_on_store
++;
224 return RequestStatus_Aliased
;
227 pair
<RequestTable::iterator
, bool> r
=
228 m_readRequestTable
.insert(default_entry
);
231 RequestTable::iterator i
= r
.first
;
232 i
->second
= new SequencerRequest(pkt
, request_type
, curCycle());
233 m_outstanding_count
++;
235 // There is an outstanding read request for the cache line
236 m_load_waiting_on_load
++;
237 return RequestStatus_Aliased
;
241 m_outstandReqHist
.sample(m_outstanding_count
);
242 assert(m_outstanding_count
==
243 (m_writeRequestTable
.size() + m_readRequestTable
.size()));
245 return RequestStatus_Ready
;
249 Sequencer::markRemoved()
251 m_outstanding_count
--;
252 assert(m_outstanding_count
==
253 m_writeRequestTable
.size() + m_readRequestTable
.size());
257 Sequencer::invalidateSC(Addr address
)
259 AbstractCacheEntry
*e
= m_dataCache_ptr
->lookup(address
);
260 // The controller has lost the coherence permissions, hence the lock
261 // on the cache line maintained by the cache should be cleared.
262 if (e
&& e
->isLocked(m_version
)) {
268 Sequencer::handleLlsc(Addr address
, SequencerRequest
* request
)
270 AbstractCacheEntry
*e
= m_dataCache_ptr
->lookup(address
);
274 // The success flag indicates whether the LLSC operation was successful.
275 // LL ops will always succeed, but SC may fail if the cache line is no
278 if (request
->m_type
== RubyRequestType_Store_Conditional
) {
279 if (!e
->isLocked(m_version
)) {
281 // For failed SC requests, indicate the failure to the cpu by
282 // setting the extra data to zero.
284 request
->pkt
->req
->setExtraData(0);
288 // For successful SC requests, indicate the success to the cpu by
289 // setting the extra data to one.
291 request
->pkt
->req
->setExtraData(1);
294 // Independent of success, all SC operations must clear the lock
297 } else if (request
->m_type
== RubyRequestType_Load_Linked
) {
299 // Note: To fully follow Alpha LLSC semantics, should the LL clear any
300 // previously locked cache lines?
302 e
->setLocked(m_version
);
303 } else if (e
->isLocked(m_version
)) {
305 // Normal writes should clear the locked address
313 Sequencer::recordMissLatency(const Cycles cycles
, const RubyRequestType type
,
314 const MachineType respondingMach
,
315 bool isExternalHit
, Cycles issuedTime
,
316 Cycles initialRequestTime
,
317 Cycles forwardRequestTime
,
318 Cycles firstResponseTime
, Cycles completionTime
)
320 m_latencyHist
.sample(cycles
);
321 m_typeLatencyHist
[type
]->sample(cycles
);
324 m_missLatencyHist
.sample(cycles
);
325 m_missTypeLatencyHist
[type
]->sample(cycles
);
327 if (respondingMach
!= MachineType_NUM
) {
328 m_missMachLatencyHist
[respondingMach
]->sample(cycles
);
329 m_missTypeMachLatencyHist
[type
][respondingMach
]->sample(cycles
);
331 if ((issuedTime
<= initialRequestTime
) &&
332 (initialRequestTime
<= forwardRequestTime
) &&
333 (forwardRequestTime
<= firstResponseTime
) &&
334 (firstResponseTime
<= completionTime
)) {
336 m_IssueToInitialDelayHist
[respondingMach
]->sample(
337 initialRequestTime
- issuedTime
);
338 m_InitialToForwardDelayHist
[respondingMach
]->sample(
339 forwardRequestTime
- initialRequestTime
);
340 m_ForwardToFirstResponseDelayHist
[respondingMach
]->sample(
341 firstResponseTime
- forwardRequestTime
);
342 m_FirstResponseToCompletionDelayHist
[respondingMach
]->sample(
343 completionTime
- firstResponseTime
);
345 m_IncompleteTimes
[respondingMach
]++;
349 m_hitLatencyHist
.sample(cycles
);
350 m_hitTypeLatencyHist
[type
]->sample(cycles
);
352 if (respondingMach
!= MachineType_NUM
) {
353 m_hitMachLatencyHist
[respondingMach
]->sample(cycles
);
354 m_hitTypeMachLatencyHist
[type
][respondingMach
]->sample(cycles
);
360 Sequencer::writeCallback(Addr address
, DataBlock
& data
,
361 const bool externalHit
, const MachineType mach
,
362 const Cycles initialRequestTime
,
363 const Cycles forwardRequestTime
,
364 const Cycles firstResponseTime
)
366 assert(address
== makeLineAddress(address
));
367 assert(m_writeRequestTable
.count(makeLineAddress(address
)));
369 RequestTable::iterator i
= m_writeRequestTable
.find(address
);
370 assert(i
!= m_writeRequestTable
.end());
371 SequencerRequest
* request
= i
->second
;
373 m_writeRequestTable
.erase(i
);
376 assert((request
->m_type
== RubyRequestType_ST
) ||
377 (request
->m_type
== RubyRequestType_ATOMIC
) ||
378 (request
->m_type
== RubyRequestType_RMW_Read
) ||
379 (request
->m_type
== RubyRequestType_RMW_Write
) ||
380 (request
->m_type
== RubyRequestType_Load_Linked
) ||
381 (request
->m_type
== RubyRequestType_Store_Conditional
) ||
382 (request
->m_type
== RubyRequestType_Locked_RMW_Read
) ||
383 (request
->m_type
== RubyRequestType_Locked_RMW_Write
) ||
384 (request
->m_type
== RubyRequestType_FLUSH
));
387 // For Alpha, properly handle LL, SC, and write requests with respect to
388 // locked cache blocks.
390 // Not valid for Garnet_standalone protocl
393 if (!m_runningGarnetStandalone
)
394 success
= handleLlsc(address
, request
);
396 // Handle SLICC block_on behavior for Locked_RMW accesses. NOTE: the
397 // address variable here is assumed to be a line address, so when
398 // blocking buffers, must check line addresses.
399 if (request
->m_type
== RubyRequestType_Locked_RMW_Read
) {
400 // blockOnQueue blocks all first-level cache controller queues
401 // waiting on memory accesses for the specified address that go to
402 // the specified queue. In this case, a Locked_RMW_Write must go to
403 // the mandatory_q before unblocking the first-level controller.
404 // This will block standard loads, stores, ifetches, etc.
405 m_controller
->blockOnQueue(address
, m_mandatory_q_ptr
);
406 } else if (request
->m_type
== RubyRequestType_Locked_RMW_Write
) {
407 m_controller
->unblock(address
);
410 hitCallback(request
, data
, success
, mach
, externalHit
,
411 initialRequestTime
, forwardRequestTime
, firstResponseTime
);
415 Sequencer::readCallback(Addr address
, DataBlock
& data
,
416 bool externalHit
, const MachineType mach
,
417 Cycles initialRequestTime
,
418 Cycles forwardRequestTime
,
419 Cycles firstResponseTime
)
421 assert(address
== makeLineAddress(address
));
422 assert(m_readRequestTable
.count(makeLineAddress(address
)));
424 RequestTable::iterator i
= m_readRequestTable
.find(address
);
425 assert(i
!= m_readRequestTable
.end());
426 SequencerRequest
* request
= i
->second
;
428 m_readRequestTable
.erase(i
);
431 assert((request
->m_type
== RubyRequestType_LD
) ||
432 (request
->m_type
== RubyRequestType_IFETCH
));
434 hitCallback(request
, data
, true, mach
, externalHit
,
435 initialRequestTime
, forwardRequestTime
, firstResponseTime
);
439 Sequencer::hitCallback(SequencerRequest
* srequest
, DataBlock
& data
,
441 const MachineType mach
, const bool externalHit
,
442 const Cycles initialRequestTime
,
443 const Cycles forwardRequestTime
,
444 const Cycles firstResponseTime
)
446 warn_once("Replacement policy updates recently became the responsibility "
447 "of SLICC state machines. Make sure to setMRU() near callbacks "
450 PacketPtr pkt
= srequest
->pkt
;
451 Addr
request_address(pkt
->getAddr());
452 RubyRequestType type
= srequest
->m_type
;
453 Cycles issued_time
= srequest
->issue_time
;
455 assert(curCycle() >= issued_time
);
456 Cycles total_latency
= curCycle() - issued_time
;
458 // Profile the latency for all demand accesses.
459 recordMissLatency(total_latency
, type
, mach
, externalHit
, issued_time
,
460 initialRequestTime
, forwardRequestTime
,
461 firstResponseTime
, curCycle());
463 DPRINTFR(ProtocolTrace
, "%15s %3s %10s%20s %6s>%-6s %#x %d cycles\n",
464 curTick(), m_version
, "Seq",
465 llscSuccess
? "Done" : "SC_Failed", "", "",
466 printAddress(request_address
), total_latency
);
468 // update the data unless it is a non-data-carrying flush
469 if (RubySystem::getWarmupEnabled()) {
470 data
.setData(pkt
->getConstPtr
<uint8_t>(),
471 getOffset(request_address
), pkt
->getSize());
472 } else if (!pkt
->isFlush()) {
473 if ((type
== RubyRequestType_LD
) ||
474 (type
== RubyRequestType_IFETCH
) ||
475 (type
== RubyRequestType_RMW_Read
) ||
476 (type
== RubyRequestType_Locked_RMW_Read
) ||
477 (type
== RubyRequestType_Load_Linked
)) {
478 memcpy(pkt
->getPtr
<uint8_t>(),
479 data
.getData(getOffset(request_address
), pkt
->getSize()),
481 DPRINTF(RubySequencer
, "read data %s\n", data
);
482 } else if (pkt
->req
->isSwap()) {
483 std::vector
<uint8_t> overwrite_val(pkt
->getSize());
484 memcpy(&overwrite_val
[0], pkt
->getConstPtr
<uint8_t>(),
486 memcpy(pkt
->getPtr
<uint8_t>(),
487 data
.getData(getOffset(request_address
), pkt
->getSize()),
489 data
.setData(&overwrite_val
[0],
490 getOffset(request_address
), pkt
->getSize());
491 DPRINTF(RubySequencer
, "swap data %s\n", data
);
493 data
.setData(pkt
->getConstPtr
<uint8_t>(),
494 getOffset(request_address
), pkt
->getSize());
495 DPRINTF(RubySequencer
, "set data %s\n", data
);
499 // If using the RubyTester, update the RubyTester sender state's
500 // subBlock with the recieved data. The tester will later access
502 if (m_usingRubyTester
) {
503 DPRINTF(RubySequencer
, "hitCallback %s 0x%x using RubyTester\n",
504 pkt
->cmdString(), pkt
->getAddr());
505 RubyTester::SenderState
* testerSenderState
=
506 pkt
->findNextSenderState
<RubyTester::SenderState
>();
507 assert(testerSenderState
);
508 testerSenderState
->subBlock
.mergeFrom(data
);
513 RubySystem
*rs
= m_ruby_system
;
514 if (RubySystem::getWarmupEnabled()) {
518 rs
->m_cache_recorder
->enqueueNextFetchRequest();
519 } else if (RubySystem::getCooldownEnabled()) {
521 rs
->m_cache_recorder
->enqueueNextFlushRequest();
523 ruby_hit_callback(pkt
);
529 Sequencer::empty() const
531 return m_writeRequestTable
.empty() && m_readRequestTable
.empty();
535 Sequencer::makeRequest(PacketPtr pkt
)
537 if (m_outstanding_count
>= m_max_outstanding_requests
) {
538 return RequestStatus_BufferFull
;
541 RubyRequestType primary_type
= RubyRequestType_NULL
;
542 RubyRequestType secondary_type
= RubyRequestType_NULL
;
546 // Alpha LL/SC instructions need to be handled carefully by the cache
547 // coherence protocol to ensure they follow the proper semantics. In
548 // particular, by identifying the operations as atomic, the protocol
549 // should understand that migratory sharing optimizations should not
550 // be performed (i.e. a load between the LL and SC should not steal
551 // away exclusive permission).
553 if (pkt
->isWrite()) {
554 DPRINTF(RubySequencer
, "Issuing SC\n");
555 primary_type
= RubyRequestType_Store_Conditional
;
557 DPRINTF(RubySequencer
, "Issuing LL\n");
558 assert(pkt
->isRead());
559 primary_type
= RubyRequestType_Load_Linked
;
561 secondary_type
= RubyRequestType_ATOMIC
;
562 } else if (pkt
->req
->isLockedRMW()) {
564 // x86 locked instructions are translated to store cache coherence
565 // requests because these requests should always be treated as read
566 // exclusive operations and should leverage any migratory sharing
567 // optimization built into the protocol.
569 if (pkt
->isWrite()) {
570 DPRINTF(RubySequencer
, "Issuing Locked RMW Write\n");
571 primary_type
= RubyRequestType_Locked_RMW_Write
;
573 DPRINTF(RubySequencer
, "Issuing Locked RMW Read\n");
574 assert(pkt
->isRead());
575 primary_type
= RubyRequestType_Locked_RMW_Read
;
577 secondary_type
= RubyRequestType_ST
;
580 // To support SwapReq, we need to check isWrite() first: a SwapReq
581 // should always be treated like a write, but since a SwapReq implies
582 // both isWrite() and isRead() are true, check isWrite() first here.
584 if (pkt
->isWrite()) {
586 // Note: M5 packets do not differentiate ST from RMW_Write
588 primary_type
= secondary_type
= RubyRequestType_ST
;
589 } else if (pkt
->isRead()) {
590 if (pkt
->req
->isInstFetch()) {
591 primary_type
= secondary_type
= RubyRequestType_IFETCH
;
593 bool storeCheck
= false;
594 // only X86 need the store check
595 if (system
->getArch() == Arch::X86ISA
) {
596 uint32_t flags
= pkt
->req
->getFlags();
598 (X86ISA::StoreCheck
<< X86ISA::FlagShift
);
601 primary_type
= RubyRequestType_RMW_Read
;
602 secondary_type
= RubyRequestType_ST
;
604 primary_type
= secondary_type
= RubyRequestType_LD
;
607 } else if (pkt
->isFlush()) {
608 primary_type
= secondary_type
= RubyRequestType_FLUSH
;
610 panic("Unsupported ruby packet type\n");
614 RequestStatus status
= insertRequest(pkt
, primary_type
);
615 if (status
!= RequestStatus_Ready
)
618 issueRequest(pkt
, secondary_type
);
620 // TODO: issue hardware prefetches here
621 return RequestStatus_Issued
;
625 Sequencer::issueRequest(PacketPtr pkt
, RubyRequestType secondary_type
)
628 ContextID proc_id
= pkt
->req
->hasContextId() ?
629 pkt
->req
->contextId() : InvalidContextID
;
631 ContextID core_id
= coreId();
633 // If valid, copy the pc to the ruby request
635 if (pkt
->req
->hasPC()) {
636 pc
= pkt
->req
->getPC();
639 // check if the packet has data as for example prefetch and flush
641 std::shared_ptr
<RubyRequest
> msg
=
642 std::make_shared
<RubyRequest
>(clockEdge(), pkt
->getAddr(),
644 nullptr : pkt
->getPtr
<uint8_t>(),
645 pkt
->getSize(), pc
, secondary_type
,
646 RubyAccessMode_Supervisor
, pkt
,
647 PrefetchBit_No
, proc_id
, core_id
);
649 DPRINTFR(ProtocolTrace
, "%15s %3s %10s%20s %6s>%-6s %#x %s\n",
650 curTick(), m_version
, "Seq", "Begin", "", "",
651 printAddress(msg
->getPhysicalAddress()),
652 RubyRequestType_to_string(secondary_type
));
654 // The Sequencer currently assesses instruction and data cache hit latency
655 // for the top-level caches at the beginning of a memory access.
656 // TODO: Eventually, this latency should be moved to represent the actual
657 // cache access latency portion of the memory access. This will require
658 // changing cache controller protocol files to assess the latency on the
659 // access response path.
660 Cycles
latency(0); // Initialize to zero to catch misconfigured latency
661 if (secondary_type
== RubyRequestType_IFETCH
)
662 latency
= m_inst_cache_hit_latency
;
664 latency
= m_data_cache_hit_latency
;
666 // Send the message to the cache controller
669 assert(m_mandatory_q_ptr
!= NULL
);
670 m_mandatory_q_ptr
->enqueue(msg
, clockEdge(), cyclesToTicks(latency
));
673 template <class KEY
, class VALUE
>
675 operator<<(ostream
&out
, const std::unordered_map
<KEY
, VALUE
> &map
)
677 auto i
= map
.begin();
678 auto end
= map
.end();
681 for (; i
!= end
; ++i
)
682 out
<< " " << i
->first
<< "=" << i
->second
;
689 Sequencer::print(ostream
& out
) const
691 out
<< "[Sequencer: " << m_version
692 << ", outstanding requests: " << m_outstanding_count
693 << ", read request table: " << m_readRequestTable
694 << ", write request table: " << m_writeRequestTable
698 // this can be called from setState whenever coherence permissions are
699 // upgraded when invoked, coherence violations will be checked for the
702 Sequencer::checkCoherence(Addr addr
)
704 #ifdef CHECK_COHERENCE
705 m_ruby_system
->checkGlobalCoherenceInvariant(addr
);
710 Sequencer::recordRequestType(SequencerRequestType requestType
) {
711 DPRINTF(RubyStats
, "Recorded statistic: %s\n",
712 SequencerRequestType_to_string(requestType
));
717 Sequencer::evictionCallback(Addr address
)
719 ruby_eviction_callback(address
);
723 Sequencer::regStats()
725 RubyPort::regStats();
727 m_store_waiting_on_load
728 .name(name() + ".store_waiting_on_load")
729 .desc("Number of times a store aliased with a pending load")
730 .flags(Stats::nozero
);
731 m_store_waiting_on_store
732 .name(name() + ".store_waiting_on_store")
733 .desc("Number of times a store aliased with a pending store")
734 .flags(Stats::nozero
);
735 m_load_waiting_on_load
736 .name(name() + ".load_waiting_on_load")
737 .desc("Number of times a load aliased with a pending load")
738 .flags(Stats::nozero
);
739 m_load_waiting_on_store
740 .name(name() + ".load_waiting_on_store")
741 .desc("Number of times a load aliased with a pending store")
742 .flags(Stats::nozero
);
744 // These statistical variables are not for display.
745 // The profiler will collate these across different
746 // sequencers and display those collated statistics.
747 m_outstandReqHist
.init(10);
748 m_latencyHist
.init(10);
749 m_hitLatencyHist
.init(10);
750 m_missLatencyHist
.init(10);
752 for (int i
= 0; i
< RubyRequestType_NUM
; i
++) {
753 m_typeLatencyHist
.push_back(new Stats::Histogram());
754 m_typeLatencyHist
[i
]->init(10);
756 m_hitTypeLatencyHist
.push_back(new Stats::Histogram());
757 m_hitTypeLatencyHist
[i
]->init(10);
759 m_missTypeLatencyHist
.push_back(new Stats::Histogram());
760 m_missTypeLatencyHist
[i
]->init(10);
763 for (int i
= 0; i
< MachineType_NUM
; i
++) {
764 m_hitMachLatencyHist
.push_back(new Stats::Histogram());
765 m_hitMachLatencyHist
[i
]->init(10);
767 m_missMachLatencyHist
.push_back(new Stats::Histogram());
768 m_missMachLatencyHist
[i
]->init(10);
770 m_IssueToInitialDelayHist
.push_back(new Stats::Histogram());
771 m_IssueToInitialDelayHist
[i
]->init(10);
773 m_InitialToForwardDelayHist
.push_back(new Stats::Histogram());
774 m_InitialToForwardDelayHist
[i
]->init(10);
776 m_ForwardToFirstResponseDelayHist
.push_back(new Stats::Histogram());
777 m_ForwardToFirstResponseDelayHist
[i
]->init(10);
779 m_FirstResponseToCompletionDelayHist
.push_back(new Stats::Histogram());
780 m_FirstResponseToCompletionDelayHist
[i
]->init(10);
783 for (int i
= 0; i
< RubyRequestType_NUM
; i
++) {
784 m_hitTypeMachLatencyHist
.push_back(std::vector
<Stats::Histogram
*>());
785 m_missTypeMachLatencyHist
.push_back(std::vector
<Stats::Histogram
*>());
787 for (int j
= 0; j
< MachineType_NUM
; j
++) {
788 m_hitTypeMachLatencyHist
[i
].push_back(new Stats::Histogram());
789 m_hitTypeMachLatencyHist
[i
][j
]->init(10);
791 m_missTypeMachLatencyHist
[i
].push_back(new Stats::Histogram());
792 m_missTypeMachLatencyHist
[i
][j
]->init(10);