simple_cache.cc revision 13841
12623SN/A/* 22623SN/A * Copyright (c) 2017 Jason Lowe-Power 32623SN/A * All rights reserved. 42623SN/A * 52623SN/A * Redistribution and use in source and binary forms, with or without 62623SN/A * modification, are permitted provided that the following conditions are 72623SN/A * met: redistributions of source code must retain the above copyright 82623SN/A * notice, this list of conditions and the following disclaimer; 92623SN/A * redistributions in binary form must reproduce the above copyright 102623SN/A * notice, this list of conditions and the following disclaimer in the 112623SN/A * documentation and/or other materials provided with the distribution; 122623SN/A * neither the name of the copyright holders nor the names of its 132623SN/A * contributors may be used to endorse or promote products derived from 142623SN/A * this software without specific prior written permission. 152623SN/A * 162623SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 172623SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 182623SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 192623SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 202623SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 212623SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 222623SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 232623SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 242623SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 252623SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 262623SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 272665Ssaidi@eecs.umich.edu * 282665Ssaidi@eecs.umich.edu * Authors: Jason Lowe-Power 292623SN/A */ 302623SN/A 312623SN/A#include "learning_gem5/part2/simple_cache.hh" 322623SN/A 332623SN/A#include "base/random.hh" 342623SN/A#include "debug/SimpleCache.hh" 356973Stjones1@inf.ed.ac.uk#include "sim/system.hh" 365529Snate@binkert.org 375529Snate@binkert.orgSimpleCache::SimpleCache(SimpleCacheParams *params) : 382623SN/A MemObject(params), 392623SN/A latency(params->latency), 402623SN/A blockSize(params->system->cacheLineSize()), 412623SN/A capacity(params->size / blockSize), 425529Snate@binkert.org memPort(params->name + ".mem_side", this), 432623SN/A blocked(false), originalPacket(nullptr), waitingPortId(-1) 442623SN/A{ 452623SN/A // Since the CPU side ports are a vector of ports, create an instance of 462623SN/A // the CPUSidePort for each connection. This member of params is 472623SN/A // automatically created depending on the name of the vector port and 482839Sktlim@umich.edu // holds the number of connections to this port name 492798Sktlim@umich.edu for (int i = 0; i < params->port_cpu_side_connection_count; ++i) { 502623SN/A cpuPorts.emplace_back(name() + csprintf(".cpu_side[%d]", i), i, this); 512623SN/A } 525728Sgblack@eecs.umich.edu} 535728Sgblack@eecs.umich.edu 545728Sgblack@eecs.umich.eduPort & 555728Sgblack@eecs.umich.eduSimpleCache::getPort(const std::string &if_name, PortID idx) 565728Sgblack@eecs.umich.edu{ 575728Sgblack@eecs.umich.edu // This is the name from the Python SimObject declaration in SimpleCache.py 585728Sgblack@eecs.umich.edu if (if_name == "mem_side") { 595728Sgblack@eecs.umich.edu panic_if(idx != InvalidPortID, 605728Sgblack@eecs.umich.edu "Mem side of simple cache not a vector port"); 615728Sgblack@eecs.umich.edu return memPort; 625728Sgblack@eecs.umich.edu } else if (if_name == "cpu_side" && idx < cpuPorts.size()) { 635728Sgblack@eecs.umich.edu // We should have already created all of the ports in the constructor 645728Sgblack@eecs.umich.edu return cpuPorts[idx]; 655728Sgblack@eecs.umich.edu } else { 665728Sgblack@eecs.umich.edu // pass it along to our super class 675728Sgblack@eecs.umich.edu return MemObject::getPort(if_name, idx); 685728Sgblack@eecs.umich.edu } 695728Sgblack@eecs.umich.edu} 705728Sgblack@eecs.umich.edu 715728Sgblack@eecs.umich.eduvoid 725728Sgblack@eecs.umich.eduSimpleCache::CPUSidePort::sendPacket(PacketPtr pkt) 735728Sgblack@eecs.umich.edu{ 745728Sgblack@eecs.umich.edu // Note: This flow control is very simple since the cache is blocking. 755728Sgblack@eecs.umich.edu 765728Sgblack@eecs.umich.edu panic_if(blockedPacket != nullptr, "Should never try to send if blocked!"); 775728Sgblack@eecs.umich.edu 785728Sgblack@eecs.umich.edu // If we can't send the packet across the port, store it for later. 795728Sgblack@eecs.umich.edu DPRINTF(SimpleCache, "Sending %s to CPU\n", pkt->print()); 805728Sgblack@eecs.umich.edu if (!sendTimingResp(pkt)) { 815728Sgblack@eecs.umich.edu DPRINTF(SimpleCache, "failed!\n"); 825728Sgblack@eecs.umich.edu blockedPacket = pkt; 835728Sgblack@eecs.umich.edu } 845728Sgblack@eecs.umich.edu} 855728Sgblack@eecs.umich.edu 865728Sgblack@eecs.umich.eduAddrRangeList 875728Sgblack@eecs.umich.eduSimpleCache::CPUSidePort::getAddrRanges() const 885728Sgblack@eecs.umich.edu{ 895728Sgblack@eecs.umich.edu return owner->getAddrRanges(); 905728Sgblack@eecs.umich.edu} 915728Sgblack@eecs.umich.edu 925728Sgblack@eecs.umich.eduvoid 935728Sgblack@eecs.umich.eduSimpleCache::CPUSidePort::trySendRetry() 945728Sgblack@eecs.umich.edu{ 955728Sgblack@eecs.umich.edu if (needRetry && blockedPacket == nullptr) { 965728Sgblack@eecs.umich.edu // Only send a retry if the port is now completely free 975728Sgblack@eecs.umich.edu needRetry = false; 985728Sgblack@eecs.umich.edu DPRINTF(SimpleCache, "Sending retry req.\n"); 995894Sgblack@eecs.umich.edu sendRetryReq(); 1005894Sgblack@eecs.umich.edu } 1015894Sgblack@eecs.umich.edu} 1025894Sgblack@eecs.umich.edu 1035894Sgblack@eecs.umich.eduvoid 1045894Sgblack@eecs.umich.eduSimpleCache::CPUSidePort::recvFunctional(PacketPtr pkt) 1056023Snate@binkert.org{ 1066023Snate@binkert.org // Just forward to the cache. 1075894Sgblack@eecs.umich.edu return owner->handleFunctional(pkt); 1085894Sgblack@eecs.umich.edu} 1096023Snate@binkert.org 1107944SGiacomo.Gabrielli@arm.combool 1117945SAli.Saidi@ARM.comSimpleCache::CPUSidePort::recvTimingReq(PacketPtr pkt) 1127945SAli.Saidi@ARM.com{ 1137945SAli.Saidi@ARM.com DPRINTF(SimpleCache, "Got request %s\n", pkt->print()); 1147945SAli.Saidi@ARM.com 1157944SGiacomo.Gabrielli@arm.com if (blockedPacket || needRetry) { 1167944SGiacomo.Gabrielli@arm.com // The cache may not be able to send a reply if this is blocked 1176023Snate@binkert.org DPRINTF(SimpleCache, "Request blocked\n"); 1186023Snate@binkert.org needRetry = true; 1195894Sgblack@eecs.umich.edu return false; 1205894Sgblack@eecs.umich.edu } 1215894Sgblack@eecs.umich.edu // Just forward to the cache. 1225894Sgblack@eecs.umich.edu if (!owner->handleRequest(pkt, id)) { 1235894Sgblack@eecs.umich.edu DPRINTF(SimpleCache, "Request failed\n"); 1245894Sgblack@eecs.umich.edu // stalling 1256973Stjones1@inf.ed.ac.uk needRetry = true; 1266973Stjones1@inf.ed.ac.uk return false; 1276973Stjones1@inf.ed.ac.uk } else { 1285894Sgblack@eecs.umich.edu DPRINTF(SimpleCache, "Request succeeded\n"); 1295894Sgblack@eecs.umich.edu return true; 1305894Sgblack@eecs.umich.edu } 1315894Sgblack@eecs.umich.edu} 1325894Sgblack@eecs.umich.edu 1335894Sgblack@eecs.umich.eduvoid 1345894Sgblack@eecs.umich.eduSimpleCache::CPUSidePort::recvRespRetry() 1355744Sgblack@eecs.umich.edu{ 1365728Sgblack@eecs.umich.edu // We should have a blocked packet if this function is called. 1375728Sgblack@eecs.umich.edu assert(blockedPacket != nullptr); 1385728Sgblack@eecs.umich.edu 1395728Sgblack@eecs.umich.edu // Grab the blocked packet. 1408707Sandreas.hansson@arm.com PacketPtr pkt = blockedPacket; 1418707Sandreas.hansson@arm.com blockedPacket = nullptr; 1428707Sandreas.hansson@arm.com 1438707Sandreas.hansson@arm.com DPRINTF(SimpleCache, "Retrying response pkt %s\n", pkt->print()); 1448707Sandreas.hansson@arm.com // Try to resend it. It's possible that it fails again. 1458707Sandreas.hansson@arm.com sendPacket(pkt); 1468707Sandreas.hansson@arm.com 1472623SN/A // We may now be able to accept new packets 1482623SN/A trySendRetry(); 1492623SN/A} 1508707Sandreas.hansson@arm.com 1518707Sandreas.hansson@arm.comvoid 1522623SN/ASimpleCache::MemSidePort::sendPacket(PacketPtr pkt) 1532623SN/A{ 1542623SN/A // Note: This flow control is very simple since the cache is blocking. 1552623SN/A 1568948Sandreas.hansson@arm.com panic_if(blockedPacket != nullptr, "Should never try to send if blocked!"); 1578948Sandreas.hansson@arm.com 1588948Sandreas.hansson@arm.com // If we can't send the packet across the port, store it for later. 1598948Sandreas.hansson@arm.com if (!sendTimingReq(pkt)) { 1608948Sandreas.hansson@arm.com blockedPacket = pkt; 1618707Sandreas.hansson@arm.com } 1622948Ssaidi@eecs.umich.edu} 1632948Ssaidi@eecs.umich.edu 1642948Ssaidi@eecs.umich.edubool 1653349Sbinkertn@umich.eduSimpleCache::MemSidePort::recvTimingResp(PacketPtr pkt) 1662948Ssaidi@eecs.umich.edu{ 1677745SAli.Saidi@ARM.com // Just forward to the cache. 1682948Ssaidi@eecs.umich.edu return owner->handleResponse(pkt); 1698707Sandreas.hansson@arm.com} 1705336Shines@cs.fsu.edu 1713349Sbinkertn@umich.eduvoid 1722948Ssaidi@eecs.umich.eduSimpleCache::MemSidePort::recvReqRetry() 1732948Ssaidi@eecs.umich.edu{ 1747745SAli.Saidi@ARM.com // We should have a blocked packet if this function is called. 1752623SN/A assert(blockedPacket != nullptr); 1762623SN/A 1778707Sandreas.hansson@arm.com // Grab the blocked packet. 1782623SN/A PacketPtr pkt = blockedPacket; 1792623SN/A blockedPacket = nullptr; 1802623SN/A 1818707Sandreas.hansson@arm.com // Try to resend it. It's possible that it fails again. 1828707Sandreas.hansson@arm.com sendPacket(pkt); 1838707Sandreas.hansson@arm.com} 1842623SN/A 1852623SN/Avoid 1862623SN/ASimpleCache::MemSidePort::recvRangeChange() 1872623SN/A{ 1883349Sbinkertn@umich.edu owner->sendRangeChange(); 1892623SN/A} 1902657Ssaidi@eecs.umich.edu 1912948Ssaidi@eecs.umich.edubool 1922948Ssaidi@eecs.umich.eduSimpleCache::handleRequest(PacketPtr pkt, int port_id) 1932948Ssaidi@eecs.umich.edu{ 1942948Ssaidi@eecs.umich.edu if (blocked) { 1952948Ssaidi@eecs.umich.edu // There is currently an outstanding request so we can't respond. Stall 1962948Ssaidi@eecs.umich.edu return false; 1972948Ssaidi@eecs.umich.edu } 1985336Shines@cs.fsu.edu 1992948Ssaidi@eecs.umich.edu DPRINTF(SimpleCache, "Got request for addr %#x\n", pkt->getAddr()); 2002948Ssaidi@eecs.umich.edu 2012948Ssaidi@eecs.umich.edu // This cache is now blocked waiting for the response to this packet. 2022948Ssaidi@eecs.umich.edu blocked = true; 2032623SN/A 2042623SN/A // Store the port for when we get the response 2058707Sandreas.hansson@arm.com assert(waitingPortId == -1); 2062623SN/A waitingPortId = port_id; 2072623SN/A 2082623SN/A // Schedule an event after cache access latency to actually access 2098707Sandreas.hansson@arm.com schedule(new EventFunctionWrapper([this, pkt]{ accessTiming(pkt); }, 2108707Sandreas.hansson@arm.com name() + ".accessEvent", true), 2112623SN/A clockEdge(latency)); 2122623SN/A 2132623SN/A return true; 2142623SN/A} 2153349Sbinkertn@umich.edu 2162623SN/Abool 2172657Ssaidi@eecs.umich.eduSimpleCache::handleResponse(PacketPtr pkt) 2182948Ssaidi@eecs.umich.edu{ 2192948Ssaidi@eecs.umich.edu assert(blocked); 2202948Ssaidi@eecs.umich.edu DPRINTF(SimpleCache, "Got response for addr %#x\n", pkt->getAddr()); 2212948Ssaidi@eecs.umich.edu 2222948Ssaidi@eecs.umich.edu // For now assume that inserts are off of the critical path and don't count 2232948Ssaidi@eecs.umich.edu // for any added latency. 2245336Shines@cs.fsu.edu insert(pkt); 2252948Ssaidi@eecs.umich.edu 2262948Ssaidi@eecs.umich.edu missLatency.sample(curTick() - missTime); 2272948Ssaidi@eecs.umich.edu 2282948Ssaidi@eecs.umich.edu // If we had to upgrade the request packet to a full cache line, now we 2292623SN/A // can use that packet to construct the response. 2302623SN/A if (originalPacket != nullptr) { 2312623SN/A DPRINTF(SimpleCache, "Copying data from new packet to old\n"); 2322623SN/A // We had to upgrade a previous packet. We can functionally deal with 2332623SN/A // the cache access now. It better be a hit. 2343349Sbinkertn@umich.edu bool hit M5_VAR_USED = accessFunctional(originalPacket); 2353349Sbinkertn@umich.edu panic_if(!hit, "Should always hit after inserting"); 2362623SN/A originalPacket->makeResponse(); 2373222Sktlim@umich.edu delete pkt; // We may need to delay this, I'm not sure. 2383170Sstever@eecs.umich.edu pkt = originalPacket; 2398850Sandreas.hansson@arm.com originalPacket = nullptr; 2408850Sandreas.hansson@arm.com } // else, pkt contains the data it needs 2418850Sandreas.hansson@arm.com 2428850Sandreas.hansson@arm.com sendResponse(pkt); 2438850Sandreas.hansson@arm.com 2448850Sandreas.hansson@arm.com return true; 2458850Sandreas.hansson@arm.com} 2468850Sandreas.hansson@arm.com 2472623SN/Avoid SimpleCache::sendResponse(PacketPtr pkt) 2482623SN/A{ 2492623SN/A assert(blocked); 2502623SN/A DPRINTF(SimpleCache, "Sending resp for addr %#x\n", pkt->getAddr()); 2512623SN/A 2522901Ssaidi@eecs.umich.edu int port = waitingPortId; 2532798Sktlim@umich.edu 2542798Sktlim@umich.edu // The packet is now done. We're about to put it in the port, no need for 2552798Sktlim@umich.edu // this object to continue to stall. 2562623SN/A // We need to free the resource before sending the packet in case the CPU 2572623SN/A // tries to send another request immediately (e.g., in the same callchain). 2588737Skoansin.tan@gmail.com blocked = false; 2598737Skoansin.tan@gmail.com waitingPortId = -1; 2602623SN/A 2618444Sgblack@eecs.umich.edu // Simply forward to the memory port 2627520Sgblack@eecs.umich.edu cpuPorts[port].sendPacket(pkt); 2638444Sgblack@eecs.umich.edu 2648444Sgblack@eecs.umich.edu // For each of the cpu ports, if it needs to send a retry, it should do it 2657520Sgblack@eecs.umich.edu // now since this memory object may be unblocked now. 2662623SN/A for (auto& port : cpuPorts) { 2675894Sgblack@eecs.umich.edu port.trySendRetry(); 2683349Sbinkertn@umich.edu } 2695894Sgblack@eecs.umich.edu} 2702644Sstever@eecs.umich.edu 2714471Sstever@eecs.umich.eduvoid 2725315Sstever@gmail.comSimpleCache::handleFunctional(PacketPtr pkt) 2735315Sstever@gmail.com{ 2745315Sstever@gmail.com if (accessFunctional(pkt)) { 2755315Sstever@gmail.com pkt->makeResponse(); 2765315Sstever@gmail.com } else { 2775315Sstever@gmail.com memPort.sendFunctional(pkt); 2786973Stjones1@inf.ed.ac.uk } 2796973Stjones1@inf.ed.ac.uk} 2806973Stjones1@inf.ed.ac.uk 2816973Stjones1@inf.ed.ac.ukvoid 2826973Stjones1@inf.ed.ac.ukSimpleCache::accessTiming(PacketPtr pkt) 2836973Stjones1@inf.ed.ac.uk{ 2842798Sktlim@umich.edu bool hit = accessFunctional(pkt); 2854471Sstever@eecs.umich.edu 2864471Sstever@eecs.umich.edu DPRINTF(SimpleCache, "%s for packet: %s\n", hit ? "Hit" : "Miss", 2875710Scws3k@cs.virginia.edu pkt->print()); 2884471Sstever@eecs.umich.edu 2895103Ssaidi@eecs.umich.edu if (hit) { 2905103Ssaidi@eecs.umich.edu // Respond to the CPU side 2915103Ssaidi@eecs.umich.edu hits++; // update stats 2925103Ssaidi@eecs.umich.edu DDUMP(SimpleCache, pkt->getConstPtr<uint8_t>(), pkt->getSize()); 2935103Ssaidi@eecs.umich.edu pkt->makeResponse(); 2945336Shines@cs.fsu.edu sendResponse(pkt); 2955103Ssaidi@eecs.umich.edu } else { 2965103Ssaidi@eecs.umich.edu misses++; // update stats 2972839Sktlim@umich.edu missTime = curTick(); 2982623SN/A // Forward to the memory side. 2992623SN/A // We can't directly forward the packet unless it is exactly the size 3002623SN/A // of the cache line, and aligned. Check for that here. 301 Addr addr = pkt->getAddr(); 302 Addr block_addr = pkt->getBlockAddr(blockSize); 303 unsigned size = pkt->getSize(); 304 if (addr == block_addr && size == blockSize) { 305 // Aligned and block size. We can just forward. 306 DPRINTF(SimpleCache, "forwarding packet\n"); 307 memPort.sendPacket(pkt); 308 } else { 309 DPRINTF(SimpleCache, "Upgrading packet to block size\n"); 310 panic_if(addr - block_addr + size > blockSize, 311 "Cannot handle accesses that span multiple cache lines"); 312 // Unaligned access to one cache block 313 assert(pkt->needsResponse()); 314 MemCmd cmd; 315 if (pkt->isWrite() || pkt->isRead()) { 316 // Read the data from memory to write into the block. 317 // We'll write the data in the cache (i.e., a writeback cache) 318 cmd = MemCmd::ReadReq; 319 } else { 320 panic("Unknown packet type in upgrade size"); 321 } 322 323 // Create a new packet that is blockSize 324 PacketPtr new_pkt = new Packet(pkt->req, cmd, blockSize); 325 new_pkt->allocate(); 326 327 // Should now be block aligned 328 assert(new_pkt->getAddr() == new_pkt->getBlockAddr(blockSize)); 329 330 // Save the old packet 331 originalPacket = pkt; 332 333 DPRINTF(SimpleCache, "forwarding packet\n"); 334 memPort.sendPacket(new_pkt); 335 } 336 } 337} 338 339bool 340SimpleCache::accessFunctional(PacketPtr pkt) 341{ 342 Addr block_addr = pkt->getBlockAddr(blockSize); 343 auto it = cacheStore.find(block_addr); 344 if (it != cacheStore.end()) { 345 if (pkt->isWrite()) { 346 // Write the data into the block in the cache 347 pkt->writeDataToBlock(it->second, blockSize); 348 } else if (pkt->isRead()) { 349 // Read the data out of the cache block into the packet 350 pkt->setDataFromBlock(it->second, blockSize); 351 } else { 352 panic("Unknown packet type!"); 353 } 354 return true; 355 } 356 return false; 357} 358 359void 360SimpleCache::insert(PacketPtr pkt) 361{ 362 // The packet should be aligned. 363 assert(pkt->getAddr() == pkt->getBlockAddr(blockSize)); 364 // The address should not be in the cache 365 assert(cacheStore.find(pkt->getAddr()) == cacheStore.end()); 366 // The pkt should be a response 367 assert(pkt->isResponse()); 368 369 if (cacheStore.size() >= capacity) { 370 // Select random thing to evict. This is a little convoluted since we 371 // are using a std::unordered_map. See http://bit.ly/2hrnLP2 372 int bucket, bucket_size; 373 do { 374 bucket = random_mt.random(0, (int)cacheStore.bucket_count() - 1); 375 } while ( (bucket_size = cacheStore.bucket_size(bucket)) == 0 ); 376 auto block = std::next(cacheStore.begin(bucket), 377 random_mt.random(0, bucket_size - 1)); 378 379 DPRINTF(SimpleCache, "Removing addr %#x\n", block->first); 380 381 // Write back the data. 382 // Create a new request-packet pair 383 RequestPtr req = std::make_shared<Request>( 384 block->first, blockSize, 0, 0); 385 386 PacketPtr new_pkt = new Packet(req, MemCmd::WritebackDirty, blockSize); 387 new_pkt->dataDynamic(block->second); // This will be deleted later 388 389 DPRINTF(SimpleCache, "Writing packet back %s\n", pkt->print()); 390 // Send the write to memory 391 memPort.sendPacket(new_pkt); 392 393 // Delete this entry 394 cacheStore.erase(block->first); 395 } 396 397 DPRINTF(SimpleCache, "Inserting %s\n", pkt->print()); 398 DDUMP(SimpleCache, pkt->getConstPtr<uint8_t>(), blockSize); 399 400 // Allocate space for the cache block data 401 uint8_t *data = new uint8_t[blockSize]; 402 403 // Insert the data and address into the cache store 404 cacheStore[pkt->getAddr()] = data; 405 406 // Write the data into the cache 407 pkt->writeDataToBlock(data, blockSize); 408} 409 410AddrRangeList 411SimpleCache::getAddrRanges() const 412{ 413 DPRINTF(SimpleCache, "Sending new ranges\n"); 414 // Just use the same ranges as whatever is on the memory side. 415 return memPort.getAddrRanges(); 416} 417 418void 419SimpleCache::sendRangeChange() const 420{ 421 for (auto& port : cpuPorts) { 422 port.sendRangeChange(); 423 } 424} 425 426void 427SimpleCache::regStats() 428{ 429 // If you don't do this you get errors about uninitialized stats. 430 MemObject::regStats(); 431 432 hits.name(name() + ".hits") 433 .desc("Number of hits") 434 ; 435 436 misses.name(name() + ".misses") 437 .desc("Number of misses") 438 ; 439 440 missLatency.name(name() + ".missLatency") 441 .desc("Ticks for misses to the cache") 442 .init(16) // number of buckets 443 ; 444 445 hitRatio.name(name() + ".hitRatio") 446 .desc("The ratio of hits to the total accesses to the cache") 447 ; 448 449 hitRatio = hits / (hits + misses); 450 451} 452 453 454SimpleCache* 455SimpleCacheParams::create() 456{ 457 return new SimpleCache(this); 458} 459