2 * Copyright (c) 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-2012 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/structures/CacheMemory.hh"
44 #include "base/intmath.hh"
45 #include "base/logging.hh"
46 #include "debug/HtmMem.hh"
47 #include "debug/RubyCache.hh"
48 #include "debug/RubyCacheTrace.hh"
49 #include "debug/RubyResourceStalls.hh"
50 #include "debug/RubyStats.hh"
51 #include "mem/cache/replacement_policies/weighted_lru_rp.hh"
52 #include "mem/ruby/protocol/AccessPermission.hh"
53 #include "mem/ruby/system/RubySystem.hh"
58 operator<<(ostream
& out
, const CacheMemory
& obj
)
65 CacheMemory::CacheMemory(const Params
&p
)
67 dataArray(p
.dataArrayBanks
, p
.dataAccessLatency
,
68 p
.start_index_bit
, p
.ruby_system
),
69 tagArray(p
.tagArrayBanks
, p
.tagAccessLatency
,
70 p
.start_index_bit
, p
.ruby_system
),
71 cacheMemoryStats(this),
72 ADD_STAT(m_demand_hits
, "Number of cache demand hits"),
73 ADD_STAT(m_demand_misses
, "Number of cache demand misses"),
74 ADD_STAT(m_demand_accesses
, "Number of cache demand accesses",
75 m_demand_hits
+ m_demand_misses
),
76 ADD_STAT(m_sw_prefetches
, "Number of software prefetches"),
77 ADD_STAT(m_hw_prefetches
, "Number of hardware prefetches"),
78 ADD_STAT(m_prefetches
, "Number of prefetches",
79 m_sw_prefetches
+ m_hw_prefetches
),
80 ADD_STAT(m_accessModeType
, "")
82 m_cache_size
= p
.size
;
83 m_cache_assoc
= p
.assoc
;
84 m_replacementPolicy_ptr
= p
.replacement_policy
;
85 m_start_index_bit
= p
.start_index_bit
;
86 m_is_instruction_only_cache
= p
.is_icache
;
87 m_resource_stalls
= p
.resourceStalls
;
88 m_block_size
= p
.block_size
; // may be 0 at this point. Updated in init()
89 m_use_occupancy
= dynamic_cast<ReplacementPolicy::WeightedLRU
*>(
90 m_replacementPolicy_ptr
) ? true : false;
93 .flags(Stats::nozero
);
96 .flags(Stats::nozero
);
99 .flags(Stats::nozero
);
102 .init(RubyRequestType_NUM
)
103 .flags(Stats::pdf
| Stats::total
);
105 for (int i
= 0; i
< RubyAccessMode_NUM
; i
++) {
107 .subname(i
, RubyAccessMode_to_string(RubyAccessMode(i
)))
108 .flags(Stats::nozero
)
116 if (m_block_size
== 0) {
117 m_block_size
= RubySystem::getBlockSizeBytes();
119 m_cache_num_sets
= (m_cache_size
/ m_cache_assoc
) / m_block_size
;
120 assert(m_cache_num_sets
> 1);
121 m_cache_num_set_bits
= floorLog2(m_cache_num_sets
);
122 assert(m_cache_num_set_bits
> 0);
124 m_cache
.resize(m_cache_num_sets
,
125 std::vector
<AbstractCacheEntry
*>(m_cache_assoc
, nullptr));
126 replacement_data
.resize(m_cache_num_sets
,
127 std::vector
<ReplData
>(m_cache_assoc
, nullptr));
128 // instantiate all the replacement_data here
129 for (int i
= 0; i
< m_cache_num_sets
; i
++) {
130 for ( int j
= 0; j
< m_cache_assoc
; j
++) {
131 replacement_data
[i
][j
] =
132 m_replacementPolicy_ptr
->instantiateEntry();
137 CacheMemory::~CacheMemory()
139 if (m_replacementPolicy_ptr
)
140 delete m_replacementPolicy_ptr
;
141 for (int i
= 0; i
< m_cache_num_sets
; i
++) {
142 for (int j
= 0; j
< m_cache_assoc
; j
++) {
143 delete m_cache
[i
][j
];
148 // convert a Address to its location in the cache
150 CacheMemory::addressToCacheSet(Addr address
) const
152 assert(address
== makeLineAddress(address
));
153 return bitSelect(address
, m_start_index_bit
,
154 m_start_index_bit
+ m_cache_num_set_bits
- 1);
157 // Given a cache index: returns the index of the tag in a set.
158 // returns -1 if the tag is not found.
160 CacheMemory::findTagInSet(int64_t cacheSet
, Addr tag
) const
162 assert(tag
== makeLineAddress(tag
));
163 // search the set for the tags
164 auto it
= m_tag_index
.find(tag
);
165 if (it
!= m_tag_index
.end())
166 if (m_cache
[cacheSet
][it
->second
]->m_Permission
!=
167 AccessPermission_NotPresent
)
169 return -1; // Not found
172 // Given a cache index: returns the index of the tag in a set.
173 // returns -1 if the tag is not found.
175 CacheMemory::findTagInSetIgnorePermissions(int64_t cacheSet
,
178 assert(tag
== makeLineAddress(tag
));
179 // search the set for the tags
180 auto it
= m_tag_index
.find(tag
);
181 if (it
!= m_tag_index
.end())
183 return -1; // Not found
186 // Given an unique cache block identifier (idx): return the valid address
187 // stored by the cache block. If the block is invalid/notpresent, the
188 // function returns the 0 address
190 CacheMemory::getAddressAtIdx(int idx
) const
194 int set
= idx
/ m_cache_assoc
;
195 assert(set
< m_cache_num_sets
);
197 int way
= idx
- set
* m_cache_assoc
;
198 assert (way
< m_cache_assoc
);
200 AbstractCacheEntry
* entry
= m_cache
[set
][way
];
202 entry
->m_Permission
== AccessPermission_Invalid
||
203 entry
->m_Permission
== AccessPermission_NotPresent
) {
206 return entry
->m_Address
;
210 CacheMemory::tryCacheAccess(Addr address
, RubyRequestType type
,
211 DataBlock
*& data_ptr
)
213 DPRINTF(RubyCache
, "address: %#x\n", address
);
214 AbstractCacheEntry
* entry
= lookup(address
);
215 if (entry
!= nullptr) {
216 // Do we even have a tag match?
217 m_replacementPolicy_ptr
->touch(entry
->replacementData
);
218 entry
->setLastAccess(curTick());
219 data_ptr
= &(entry
->getDataBlk());
221 if (entry
->m_Permission
== AccessPermission_Read_Write
) {
224 if ((entry
->m_Permission
== AccessPermission_Read_Only
) &&
225 (type
== RubyRequestType_LD
|| type
== RubyRequestType_IFETCH
)) {
228 // The line must not be accessible
235 CacheMemory::testCacheAccess(Addr address
, RubyRequestType type
,
236 DataBlock
*& data_ptr
)
238 DPRINTF(RubyCache
, "address: %#x\n", address
);
239 AbstractCacheEntry
* entry
= lookup(address
);
240 if (entry
!= nullptr) {
241 // Do we even have a tag match?
242 m_replacementPolicy_ptr
->touch(entry
->replacementData
);
243 entry
->setLastAccess(curTick());
244 data_ptr
= &(entry
->getDataBlk());
246 return entry
->m_Permission
!= AccessPermission_NotPresent
;
253 // tests to see if an address is present in the cache
255 CacheMemory::isTagPresent(Addr address
) const
257 const AbstractCacheEntry
* const entry
= lookup(address
);
258 if (entry
== nullptr) {
259 // We didn't find the tag
260 DPRINTF(RubyCache
, "No tag match for address: %#x\n", address
);
263 DPRINTF(RubyCache
, "address: %#x found\n", address
);
267 // Returns true if there is:
268 // a) a tag match on this address or there is
269 // b) an unused line in the same cache "way"
271 CacheMemory::cacheAvail(Addr address
) const
273 assert(address
== makeLineAddress(address
));
275 int64_t cacheSet
= addressToCacheSet(address
);
277 for (int i
= 0; i
< m_cache_assoc
; i
++) {
278 AbstractCacheEntry
* entry
= m_cache
[cacheSet
][i
];
280 if (entry
->m_Address
== address
||
281 entry
->m_Permission
== AccessPermission_NotPresent
) {
282 // Already in the cache or we found an empty entry
293 CacheMemory::allocate(Addr address
, AbstractCacheEntry
*entry
)
295 assert(address
== makeLineAddress(address
));
296 assert(!isTagPresent(address
));
297 assert(cacheAvail(address
));
298 DPRINTF(RubyCache
, "address: %#x\n", address
);
300 // Find the first open slot
301 int64_t cacheSet
= addressToCacheSet(address
);
302 std::vector
<AbstractCacheEntry
*> &set
= m_cache
[cacheSet
];
303 for (int i
= 0; i
< m_cache_assoc
; i
++) {
304 if (!set
[i
] || set
[i
]->m_Permission
== AccessPermission_NotPresent
) {
305 if (set
[i
] && (set
[i
] != entry
)) {
306 warn_once("This protocol contains a cache entry handling bug: "
307 "Entries in the cache should never be NotPresent! If\n"
308 "this entry (%#x) is not tracked elsewhere, it will memory "
309 "leak here. Fix your protocol to eliminate these!",
312 set
[i
] = entry
; // Init entry
313 set
[i
]->m_Address
= address
;
314 set
[i
]->m_Permission
= AccessPermission_Invalid
;
315 DPRINTF(RubyCache
, "Allocate clearing lock for addr: %x\n",
317 set
[i
]->m_locked
= -1;
318 m_tag_index
[address
] = i
;
319 set
[i
]->setPosition(cacheSet
, i
);
320 set
[i
]->replacementData
= replacement_data
[cacheSet
][i
];
321 set
[i
]->setLastAccess(curTick());
323 // Call reset function here to set initial value for different
324 // replacement policies.
325 m_replacementPolicy_ptr
->reset(entry
->replacementData
);
330 panic("Allocate didn't find an available entry");
334 CacheMemory::deallocate(Addr address
)
336 DPRINTF(RubyCache
, "address: %#x\n", address
);
337 AbstractCacheEntry
* entry
= lookup(address
);
338 assert(entry
!= nullptr);
339 m_replacementPolicy_ptr
->invalidate(entry
->replacementData
);
340 uint32_t cache_set
= entry
->getSet();
341 uint32_t way
= entry
->getWay();
343 m_cache
[cache_set
][way
] = NULL
;
344 m_tag_index
.erase(address
);
347 // Returns with the physical address of the conflicting cache line
349 CacheMemory::cacheProbe(Addr address
) const
351 assert(address
== makeLineAddress(address
));
352 assert(!cacheAvail(address
));
354 int64_t cacheSet
= addressToCacheSet(address
);
355 std::vector
<ReplaceableEntry
*> candidates
;
356 for (int i
= 0; i
< m_cache_assoc
; i
++) {
357 candidates
.push_back(static_cast<ReplaceableEntry
*>(
358 m_cache
[cacheSet
][i
]));
360 return m_cache
[cacheSet
][m_replacementPolicy_ptr
->
361 getVictim(candidates
)->getWay()]->m_Address
;
364 // looks an address up in the cache
366 CacheMemory::lookup(Addr address
)
368 assert(address
== makeLineAddress(address
));
369 int64_t cacheSet
= addressToCacheSet(address
);
370 int loc
= findTagInSet(cacheSet
, address
);
371 if (loc
== -1) return NULL
;
372 return m_cache
[cacheSet
][loc
];
375 // looks an address up in the cache
376 const AbstractCacheEntry
*
377 CacheMemory::lookup(Addr address
) const
379 assert(address
== makeLineAddress(address
));
380 int64_t cacheSet
= addressToCacheSet(address
);
381 int loc
= findTagInSet(cacheSet
, address
);
382 if (loc
== -1) return NULL
;
383 return m_cache
[cacheSet
][loc
];
386 // Sets the most recently used bit for a cache block
388 CacheMemory::setMRU(Addr address
)
390 AbstractCacheEntry
* entry
= lookup(makeLineAddress(address
));
391 if (entry
!= nullptr) {
392 m_replacementPolicy_ptr
->touch(entry
->replacementData
);
393 entry
->setLastAccess(curTick());
398 CacheMemory::setMRU(AbstractCacheEntry
*entry
)
400 assert(entry
!= nullptr);
401 m_replacementPolicy_ptr
->touch(entry
->replacementData
);
402 entry
->setLastAccess(curTick());
406 CacheMemory::setMRU(Addr address
, int occupancy
)
408 AbstractCacheEntry
* entry
= lookup(makeLineAddress(address
));
409 if (entry
!= nullptr) {
410 // m_use_occupancy can decide whether we are using WeightedLRU
411 // replacement policy. Depending on different replacement policies,
412 // use different touch() function.
413 if (m_use_occupancy
) {
414 static_cast<ReplacementPolicy::WeightedLRU
*>(
415 m_replacementPolicy_ptr
)->touch(
416 entry
->replacementData
, occupancy
);
418 m_replacementPolicy_ptr
->touch(entry
->replacementData
);
420 entry
->setLastAccess(curTick());
425 CacheMemory::getReplacementWeight(int64_t set
, int64_t loc
)
427 assert(set
< m_cache_num_sets
);
428 assert(loc
< m_cache_assoc
);
430 if (m_cache
[set
][loc
] != NULL
) {
431 ret
= m_cache
[set
][loc
]->getNumValidBlocks();
439 CacheMemory::recordCacheContents(int cntrl
, CacheRecorder
* tr
) const
441 uint64_t warmedUpBlocks
= 0;
442 M5_VAR_USED
uint64_t totalBlocks
= (uint64_t)m_cache_num_sets
*
443 (uint64_t)m_cache_assoc
;
445 for (int i
= 0; i
< m_cache_num_sets
; i
++) {
446 for (int j
= 0; j
< m_cache_assoc
; j
++) {
447 if (m_cache
[i
][j
] != NULL
) {
448 AccessPermission perm
= m_cache
[i
][j
]->m_Permission
;
449 RubyRequestType request_type
= RubyRequestType_NULL
;
450 if (perm
== AccessPermission_Read_Only
) {
451 if (m_is_instruction_only_cache
) {
452 request_type
= RubyRequestType_IFETCH
;
454 request_type
= RubyRequestType_LD
;
456 } else if (perm
== AccessPermission_Read_Write
) {
457 request_type
= RubyRequestType_ST
;
460 if (request_type
!= RubyRequestType_NULL
) {
462 lastAccessTick
= m_cache
[i
][j
]->getLastAccess();
463 tr
->addRecord(cntrl
, m_cache
[i
][j
]->m_Address
,
464 0, request_type
, lastAccessTick
,
465 m_cache
[i
][j
]->getDataBlk());
472 DPRINTF(RubyCacheTrace
, "%s: %lli blocks of %lli total blocks"
473 "recorded %.2f%% \n", name().c_str(), warmedUpBlocks
,
474 totalBlocks
, (float(warmedUpBlocks
) / float(totalBlocks
)) * 100.0);
478 CacheMemory::print(ostream
& out
) const
480 out
<< "Cache dump: " << name() << endl
;
481 for (int i
= 0; i
< m_cache_num_sets
; i
++) {
482 for (int j
= 0; j
< m_cache_assoc
; j
++) {
483 if (m_cache
[i
][j
] != NULL
) {
484 out
<< " Index: " << i
486 << " entry: " << *m_cache
[i
][j
] << endl
;
488 out
<< " Index: " << i
490 << " entry: NULL" << endl
;
497 CacheMemory::printData(ostream
& out
) const
499 out
<< "printData() not supported" << endl
;
503 CacheMemory::setLocked(Addr address
, int context
)
505 DPRINTF(RubyCache
, "Setting Lock for addr: %#x to %d\n", address
, context
);
506 AbstractCacheEntry
* entry
= lookup(address
);
507 assert(entry
!= nullptr);
508 entry
->setLocked(context
);
512 CacheMemory::clearLocked(Addr address
)
514 DPRINTF(RubyCache
, "Clear Lock for addr: %#x\n", address
);
515 AbstractCacheEntry
* entry
= lookup(address
);
516 assert(entry
!= nullptr);
517 entry
->clearLocked();
521 CacheMemory::clearLockedAll(int context
)
523 // iterate through every set and way to get a cache line
524 for (auto i
= m_cache
.begin(); i
!= m_cache
.end(); ++i
) {
525 std::vector
<AbstractCacheEntry
*> set
= *i
;
526 for (auto j
= set
.begin(); j
!= set
.end(); ++j
) {
527 AbstractCacheEntry
*line
= *j
;
528 if (line
&& line
->isLocked(context
)) {
529 DPRINTF(RubyCache
, "Clear Lock for addr: %#x\n",
538 CacheMemory::isLocked(Addr address
, int context
)
540 AbstractCacheEntry
* entry
= lookup(address
);
541 assert(entry
!= nullptr);
542 DPRINTF(RubyCache
, "Testing Lock for addr: %#llx cur %d con %d\n",
543 address
, entry
->m_locked
, context
);
544 return entry
->isLocked(context
);
548 CacheMemoryStats::CacheMemoryStats(Stats::Group
*parent
)
549 : Stats::Group(parent
),
550 ADD_STAT(numDataArrayReads
, "Number of data array reads"),
551 ADD_STAT(numDataArrayWrites
, "Number of data array writes"),
552 ADD_STAT(numTagArrayReads
, "Number of tag array reads"),
553 ADD_STAT(numTagArrayWrites
, "Number of tag array writes"),
554 ADD_STAT(numTagArrayStalls
, "Number of stalls caused by tag array"),
555 ADD_STAT(numDataArrayStalls
, "Number of stalls caused by data array"),
556 ADD_STAT(htmTransCommitReadSet
, "Read set size of a committed "
558 ADD_STAT(htmTransCommitWriteSet
, "Write set size of a committed "
560 ADD_STAT(htmTransAbortReadSet
, "Read set size of a aborted transaction"),
561 ADD_STAT(htmTransAbortWriteSet
, "Write set size of a aborted "
565 .flags(Stats::nozero
);
568 .flags(Stats::nozero
);
571 .flags(Stats::nozero
);
574 .flags(Stats::nozero
);
577 .flags(Stats::nozero
);
580 .flags(Stats::nozero
);
582 htmTransCommitReadSet
584 .flags(Stats::pdf
| Stats::dist
| Stats::nozero
| Stats::nonan
);
586 htmTransCommitWriteSet
588 .flags(Stats::pdf
| Stats::dist
| Stats::nozero
| Stats::nonan
);
592 .flags(Stats::pdf
| Stats::dist
| Stats::nozero
| Stats::nonan
);
594 htmTransAbortWriteSet
596 .flags(Stats::pdf
| Stats::dist
| Stats::nozero
| Stats::nonan
);
600 // assumption: SLICC generated files will only call this function
601 // once **all** resources are granted
603 CacheMemory::recordRequestType(CacheRequestType requestType
, Addr addr
)
605 DPRINTF(RubyStats
, "Recorded statistic: %s\n",
606 CacheRequestType_to_string(requestType
));
607 switch(requestType
) {
608 case CacheRequestType_DataArrayRead
:
609 if (m_resource_stalls
)
610 dataArray
.reserve(addressToCacheSet(addr
));
611 cacheMemoryStats
.numDataArrayReads
++;
613 case CacheRequestType_DataArrayWrite
:
614 if (m_resource_stalls
)
615 dataArray
.reserve(addressToCacheSet(addr
));
616 cacheMemoryStats
.numDataArrayWrites
++;
618 case CacheRequestType_TagArrayRead
:
619 if (m_resource_stalls
)
620 tagArray
.reserve(addressToCacheSet(addr
));
621 cacheMemoryStats
.numTagArrayReads
++;
623 case CacheRequestType_TagArrayWrite
:
624 if (m_resource_stalls
)
625 tagArray
.reserve(addressToCacheSet(addr
));
626 cacheMemoryStats
.numTagArrayWrites
++;
629 warn("CacheMemory access_type not found: %s",
630 CacheRequestType_to_string(requestType
));
635 CacheMemory::checkResourceAvailable(CacheResourceType res
, Addr addr
)
637 if (!m_resource_stalls
) {
641 if (res
== CacheResourceType_TagArray
) {
642 if (tagArray
.tryAccess(addressToCacheSet(addr
))) return true;
644 DPRINTF(RubyResourceStalls
,
645 "Tag array stall on addr %#x in set %d\n",
646 addr
, addressToCacheSet(addr
));
647 cacheMemoryStats
.numTagArrayStalls
++;
650 } else if (res
== CacheResourceType_DataArray
) {
651 if (dataArray
.tryAccess(addressToCacheSet(addr
))) return true;
653 DPRINTF(RubyResourceStalls
,
654 "Data array stall on addr %#x in set %d\n",
655 addr
, addressToCacheSet(addr
));
656 cacheMemoryStats
.numDataArrayStalls
++;
660 panic("Unrecognized cache resource type.");
665 CacheMemory::isBlockInvalid(int64_t cache_set
, int64_t loc
)
667 return (m_cache
[cache_set
][loc
]->m_Permission
== AccessPermission_Invalid
);
671 CacheMemory::isBlockNotBusy(int64_t cache_set
, int64_t loc
)
673 return (m_cache
[cache_set
][loc
]->m_Permission
!= AccessPermission_Busy
);
676 /* hardware transactional memory */
679 CacheMemory::htmAbortTransaction()
681 uint64_t htmReadSetSize
= 0;
682 uint64_t htmWriteSetSize
= 0;
684 // iterate through every set and way to get a cache line
685 for (auto i
= m_cache
.begin(); i
!= m_cache
.end(); ++i
)
687 std::vector
<AbstractCacheEntry
*> set
= *i
;
689 for (auto j
= set
.begin(); j
!= set
.end(); ++j
)
691 AbstractCacheEntry
*line
= *j
;
693 if (line
!= nullptr) {
694 htmReadSetSize
+= (line
->getInHtmReadSet() ? 1 : 0);
695 htmWriteSetSize
+= (line
->getInHtmWriteSet() ? 1 : 0);
696 if (line
->getInHtmWriteSet()) {
697 line
->invalidateEntry();
699 line
->setInHtmWriteSet(false);
700 line
->setInHtmReadSet(false);
706 cacheMemoryStats
.htmTransAbortReadSet
.sample(htmReadSetSize
);
707 cacheMemoryStats
.htmTransAbortWriteSet
.sample(htmWriteSetSize
);
708 DPRINTF(HtmMem
, "htmAbortTransaction: read set=%u write set=%u\n",
709 htmReadSetSize
, htmWriteSetSize
);
713 CacheMemory::htmCommitTransaction()
715 uint64_t htmReadSetSize
= 0;
716 uint64_t htmWriteSetSize
= 0;
718 // iterate through every set and way to get a cache line
719 for (auto i
= m_cache
.begin(); i
!= m_cache
.end(); ++i
)
721 std::vector
<AbstractCacheEntry
*> set
= *i
;
723 for (auto j
= set
.begin(); j
!= set
.end(); ++j
)
725 AbstractCacheEntry
*line
= *j
;
726 if (line
!= nullptr) {
727 htmReadSetSize
+= (line
->getInHtmReadSet() ? 1 : 0);
728 htmWriteSetSize
+= (line
->getInHtmWriteSet() ? 1 : 0);
729 line
->setInHtmWriteSet(false);
730 line
->setInHtmReadSet(false);
736 cacheMemoryStats
.htmTransCommitReadSet
.sample(htmReadSetSize
);
737 cacheMemoryStats
.htmTransCommitWriteSet
.sample(htmWriteSetSize
);
738 DPRINTF(HtmMem
, "htmCommitTransaction: read set=%u write set=%u\n",
739 htmReadSetSize
, htmWriteSetSize
);