flash_device.cc revision 11321:02e930db812d
111723Sar4jc@virginia.edu/* 211723Sar4jc@virginia.edu * Copyright (c) 2013-2015 ARM Limited 311723Sar4jc@virginia.edu * All rights reserved 412808Srobert.scheffel1@tu-dresden.de * 511723Sar4jc@virginia.edu * The license below extends only to copyright in the software and shall 611723Sar4jc@virginia.edu * not be construed as granting a license to any other intellectual 711723Sar4jc@virginia.edu * property including but not limited to intellectual property relating 811723Sar4jc@virginia.edu * to a hardware implementation of the functionality of the software 911723Sar4jc@virginia.edu * licensed hereunder. You may use the software subject to the license 1011723Sar4jc@virginia.edu * terms below provided that you ensure that this notice is replicated 1111723Sar4jc@virginia.edu * unmodified and in its entirety in all distributions of the software, 1211723Sar4jc@virginia.edu * modified or unmodified, in source code or in binary form. 1311723Sar4jc@virginia.edu * 1411723Sar4jc@virginia.edu * Redistribution and use in source and binary forms, with or without 1511723Sar4jc@virginia.edu * modification, are permitted provided that the following conditions are 1611723Sar4jc@virginia.edu * met: redistributions of source code must retain the above copyright 1711723Sar4jc@virginia.edu * notice, this list of conditions and the following disclaimer; 1811723Sar4jc@virginia.edu * redistributions in binary form must reproduce the above copyright 1911723Sar4jc@virginia.edu * notice, this list of conditions and the following disclaimer in the 2011723Sar4jc@virginia.edu * documentation and/or other materials provided with the distribution; 2111723Sar4jc@virginia.edu * neither the name of the copyright holders nor the names of its 2211723Sar4jc@virginia.edu * contributors may be used to endorse or promote products derived from 2311723Sar4jc@virginia.edu * this software without specific prior written permission. 2411723Sar4jc@virginia.edu * 2511723Sar4jc@virginia.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 2611723Sar4jc@virginia.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 2711723Sar4jc@virginia.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 2811723Sar4jc@virginia.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 2911723Sar4jc@virginia.edu * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 3011723Sar4jc@virginia.edu * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 3112808Srobert.scheffel1@tu-dresden.de * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 3211723Sar4jc@virginia.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 3311723Sar4jc@virginia.edu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 3411723Sar4jc@virginia.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 3512848Sar4jc@virginia.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 3612848Sar4jc@virginia.edu * 3712808Srobert.scheffel1@tu-dresden.de * Authors: Rene de Jong 3811723Sar4jc@virginia.edu */ 3912808Srobert.scheffel1@tu-dresden.de 4011723Sar4jc@virginia.edu/** @file 4111723Sar4jc@virginia.edu * This simplistic flash model is designed to model managed SLC NAND flash. 4211723Sar4jc@virginia.edu * This device will need an interface module (such as NVMe or UFS); Note that 4311723Sar4jc@virginia.edu * this model only calculates the delay and does not perform the actual 4412848Sar4jc@virginia.edu * transaction. 4512848Sar4jc@virginia.edu * 4611723Sar4jc@virginia.edu * To access the memory, use either readMemory or writeMemory. This will 4711723Sar4jc@virginia.edu * schedule an event at the tick where the action will finish. If a callback 4812848Sar4jc@virginia.edu * has been given as argument then that function will be called on completion 4911723Sar4jc@virginia.edu * of that event. Note that this does not guarantee that there are no other 5011723Sar4jc@virginia.edu * actions pending in the flash device. 5111723Sar4jc@virginia.edu * 5211723Sar4jc@virginia.edu * IMPORTANT: number of planes should be a power of 2. 5311723Sar4jc@virginia.edu */ 5411723Sar4jc@virginia.edu 5511723Sar4jc@virginia.edu#include "dev/arm/flash_device.hh" 5612848Sar4jc@virginia.edu 5712848Sar4jc@virginia.edu#include "debug/Drain.hh" 5811723Sar4jc@virginia.edu 5912848Sar4jc@virginia.edu/** 6012848Sar4jc@virginia.edu * Create this device 6112848Sar4jc@virginia.edu */ 6212848Sar4jc@virginia.edu 6312848Sar4jc@virginia.eduFlashDevice* 6413548Salec.roelke@gmail.comFlashDeviceParams::create() 6513548Salec.roelke@gmail.com{ 6613548Salec.roelke@gmail.com return new FlashDevice(this); 6713548Salec.roelke@gmail.com} 6813548Salec.roelke@gmail.com 6913548Salec.roelke@gmail.com 7013548Salec.roelke@gmail.com/** 7113548Salec.roelke@gmail.com * Flash Device constructor and destructor 7213548Salec.roelke@gmail.com */ 7313548Salec.roelke@gmail.com 7413548Salec.roelke@gmail.comFlashDevice::FlashDevice(const FlashDeviceParams* p): 7513548Salec.roelke@gmail.com AbstractNVM(p), 7613548Salec.roelke@gmail.com diskSize(0), 7713548Salec.roelke@gmail.com blockSize(p->blk_size), 7813548Salec.roelke@gmail.com pageSize(p->page_size), 7913548Salec.roelke@gmail.com GCActivePercentage(p->GC_active), 8013548Salec.roelke@gmail.com readLatency(p->read_lat), 8113548Salec.roelke@gmail.com writeLatency(p->write_lat), 8212848Sar4jc@virginia.edu eraseLatency(p->erase_lat), 8312848Sar4jc@virginia.edu dataDistribution(p->data_distribution), 8412848Sar4jc@virginia.edu numPlanes(p->num_planes), 8512849Sar4jc@virginia.edu pagesPerBlock(0), 8612848Sar4jc@virginia.edu pagesPerDisk(0), 8712848Sar4jc@virginia.edu blocksPerDisk(0), 8812848Sar4jc@virginia.edu planeMask(numPlanes - 1), 8912848Sar4jc@virginia.edu planeEventQueue(numPlanes), 9012848Sar4jc@virginia.edu planeEvent(this) 9112849Sar4jc@virginia.edu{ 9212848Sar4jc@virginia.edu 9312848Sar4jc@virginia.edu /* 9412848Sar4jc@virginia.edu * Let 'a' be a power of two of n bits, written such that a-n is the msb 9512848Sar4jc@virginia.edu * and a-0 is the lsb. Since it is a power of two, only one bit (a-x, 9612848Sar4jc@virginia.edu * with 0 <= x <= n) is set. If we subtract one from this number the bits 9712848Sar4jc@virginia.edu * a-(x-1) to a-0 are set and all the other bits are cleared. Hence a 9812848Sar4jc@virginia.edu * bitwise AND with those two numbers results in an integer with all bits 9912848Sar4jc@virginia.edu * cleared. 10012849Sar4jc@virginia.edu */ 10112848Sar4jc@virginia.edu if (numPlanes & planeMask) 10212848Sar4jc@virginia.edu fatal("Number of planes is not a power of 2 in flash device.\n"); 10312848Sar4jc@virginia.edu} 10412848Sar4jc@virginia.edu 10512848Sar4jc@virginia.edu/** 10612848Sar4jc@virginia.edu * Initiates all the flash functions: initializes the lookup tables, age of 10712848Sar4jc@virginia.edu * the device, etc. This can only be done once the disk image is known. 10812848Sar4jc@virginia.edu * Thats why it can't be done in the constructor. 10912848Sar4jc@virginia.edu */ 11012849Sar4jc@virginia.eduvoid 11112848Sar4jc@virginia.eduFlashDevice::initializeFlash(uint64_t disk_size, uint32_t sector_size) 11212848Sar4jc@virginia.edu{ 11312848Sar4jc@virginia.edu diskSize = disk_size * sector_size; 11412848Sar4jc@virginia.edu pagesPerBlock = blockSize / pageSize; 11512848Sar4jc@virginia.edu pagesPerDisk = diskSize / pageSize; 11612848Sar4jc@virginia.edu blocksPerDisk = diskSize / blockSize; 11712848Sar4jc@virginia.edu 11812848Sar4jc@virginia.edu /** Sanity information: check flash configuration */ 11912848Sar4jc@virginia.edu DPRINTF(FlashDevice, "diskSize: %d Bytes; %d pages per block, %d pages " 12012848Sar4jc@virginia.edu "per disk\n", diskSize, pagesPerBlock, pagesPerDisk); 12112848Sar4jc@virginia.edu 12212848Sar4jc@virginia.edu locationTable.resize(pagesPerDisk); 12313612Sgabeblack@google.com 12412848Sar4jc@virginia.edu /**Garbage collection related*/ 12512849Sar4jc@virginia.edu blockValidEntries.resize(blocksPerDisk, 0); 12612848Sar4jc@virginia.edu blockEmptyEntries.resize(blocksPerDisk, pagesPerBlock); 12712848Sar4jc@virginia.edu 12812848Sar4jc@virginia.edu /** 12912848Sar4jc@virginia.edu * This is a bitmap. Every bit is a page 13013548Salec.roelke@gmail.com * unknownPages is a vector of 32 bit integers. If every page was an 13113548Salec.roelke@gmail.com * integer, the total size would be pagesPerDisk; since we can map one 13213548Salec.roelke@gmail.com * page per bit we need ceil(pagesPerDisk/32) entries. 32 = 1 << 5 hence 13313548Salec.roelke@gmail.com * it will do to just shift pagesPerDisk five positions and add one. This 13411723Sar4jc@virginia.edu * will allocate one integer to many for this data structure in the worst 13512848Sar4jc@virginia.edu * case. 13611723Sar4jc@virginia.edu */ 13711723Sar4jc@virginia.edu unknownPages.resize((pagesPerDisk >> 5) + 1, 0xFFFFFFFF); 13812848Sar4jc@virginia.edu 13911723Sar4jc@virginia.edu for (uint32_t count = 0; count < pagesPerDisk; count++) { 14011723Sar4jc@virginia.edu //setup lookup table + physical aspects 14112808Srobert.scheffel1@tu-dresden.de 14212808Srobert.scheffel1@tu-dresden.de if (dataDistribution == Enums::stripe) { 14313547Sar4jc@virginia.edu locationTable[count].page = count / blocksPerDisk; 14413547Sar4jc@virginia.edu locationTable[count].block = count % blocksPerDisk; 14513547Sar4jc@virginia.edu 14613547Sar4jc@virginia.edu } else { 14713547Sar4jc@virginia.edu locationTable[count].page = count % pagesPerBlock; 14813547Sar4jc@virginia.edu locationTable[count].block = count / pagesPerBlock; 14913547Sar4jc@virginia.edu } 15012808Srobert.scheffel1@tu-dresden.de } 15112808Srobert.scheffel1@tu-dresden.de} 15212808Srobert.scheffel1@tu-dresden.de 15312808Srobert.scheffel1@tu-dresden.deFlashDevice::~FlashDevice() 15412808Srobert.scheffel1@tu-dresden.de{ 15511723Sar4jc@virginia.edu DPRINTF(FlashDevice, "Remove FlashDevice\n"); 15612848Sar4jc@virginia.edu} 15711723Sar4jc@virginia.edu 15811723Sar4jc@virginia.edu/** 15911723Sar4jc@virginia.edu * Handles the accesses to the device. 16011723Sar4jc@virginia.edu * The function determines when certain actions are scheduled and schedules 16111723Sar4jc@virginia.edu * an event that uses the callback function on completion of the action. 16211723Sar4jc@virginia.edu */ 16312848Sar4jc@virginia.eduvoid 16412136Sar4jc@virginia.eduFlashDevice::accessDevice(uint64_t address, uint32_t amount, Callback *event, 16512136Sar4jc@virginia.edu Actions action) 16612136Sar4jc@virginia.edu{ 16712136Sar4jc@virginia.edu DPRINTF(FlashDevice, "Flash calculation for %d bytes in %d pages\n" 16812136Sar4jc@virginia.edu , amount, pageSize); 16912136Sar4jc@virginia.edu 17012848Sar4jc@virginia.edu std::vector<Tick> time(numPlanes, 0); 17111723Sar4jc@virginia.edu uint64_t logic_page_addr = address / pageSize; 17211723Sar4jc@virginia.edu uint32_t plane_address = 0; 17311723Sar4jc@virginia.edu 17411723Sar4jc@virginia.edu /** 17511723Sar4jc@virginia.edu * The access will be broken up in a number of page accesses. The number 17611723Sar4jc@virginia.edu * of page accesses depends on the amount that needs to be transfered. 17711723Sar4jc@virginia.edu * The assumption here is that the interface is completely ignorant of 17812848Sar4jc@virginia.edu * the page size and that this model has to figure out all of the 17911725Sar4jc@virginia.edu * transaction characteristics. 18011725Sar4jc@virginia.edu */ 18111725Sar4jc@virginia.edu for (uint32_t count = 0; amount > (count * pageSize); count++) { 18211725Sar4jc@virginia.edu uint32_t index = (locationTable[logic_page_addr].block * 18311725Sar4jc@virginia.edu pagesPerBlock) + (logic_page_addr % pagesPerBlock); 18411725Sar4jc@virginia.edu 18512848Sar4jc@virginia.edu DPRINTF(FlashDevice, "Index 0x%8x, Block 0x%8x, pages/block %d," 18611723Sar4jc@virginia.edu " logic address 0x%8x\n", index, 18711723Sar4jc@virginia.edu locationTable[logic_page_addr].block, pagesPerBlock, 18811723Sar4jc@virginia.edu logic_page_addr); 18911723Sar4jc@virginia.edu DPRINTF(FlashDevice, "Page %d; %d bytes up to this point\n", count, 19011723Sar4jc@virginia.edu (count * pageSize)); 19112848Sar4jc@virginia.edu 19211723Sar4jc@virginia.edu plane_address = locationTable[logic_page_addr].block & planeMask; 19311877Sbrandon.potter@amd.com 19411877Sbrandon.potter@amd.com if (action == ActionRead) { 19511723Sar4jc@virginia.edu //lookup 19612848Sar4jc@virginia.edu //call accessTimes 19713612Sgabeblack@google.com time[plane_address] += accessTimes(locationTable[logic_page_addr] 198 .block, ActionRead); 199 200 /*stats*/ 201 stats.readAccess.sample(logic_page_addr); 202 stats.readLatency.sample(time[plane_address]); 203 } else { //write 204 //lookup 205 //call accessTimes if appropriate, page may be unknown, so lets 206 //give it the benefit of the doubt 207 208 if (getUnknownPages(index)) 209 time[plane_address] += accessTimes 210 (locationTable[logic_page_addr].block, ActionWrite); 211 212 else //A remap is needed 213 time[plane_address] += remap(logic_page_addr); 214 215 /*stats*/ 216 stats.writeAccess.sample(logic_page_addr); 217 stats.writeLatency.sample(time[plane_address]); 218 } 219 220 /** 221 * Check if the page is known and used. unknownPages is a bitmap of 222 * all the pages. It tracks wether we can be sure that the 223 * information of this page is taken into acount in the model (is it 224 * considered in blockValidEntries and blockEmptyEntries?). If it has 225 * been used in the past, then it is known. 226 */ 227 if (getUnknownPages(index)) { 228 clearUnknownPages(index); 229 --blockEmptyEntries[locationTable[logic_page_addr].block]; 230 ++blockValidEntries[locationTable[logic_page_addr].block]; 231 } 232 233 stats.fileSystemAccess.sample(address); 234 ++logic_page_addr; 235 } 236 237 /** 238 * previous part of the function found the times spend in different 239 * planes, now lets find the maximum to know when to callback the disk 240 */ 241 for (uint32_t count = 0; count < numPlanes; count++){ 242 plane_address = (time[plane_address] > time[count]) ? plane_address 243 : count; 244 245 DPRINTF(FlashDevice, "Plane %d is busy for %d ticks\n", count, 246 time[count]); 247 248 if (time[count] != 0) { 249 250 struct CallBackEntry cbe; 251 /** 252 * If there are no events for this plane, then add the current 253 * time to the occupation time; otherwise, plan it after the 254 * last event. If by chance that event is handled in this tick, 255 * then we would still end up with the same result. 256 */ 257 if (planeEventQueue[count].empty()) 258 cbe.time = time[count] + curTick(); 259 else 260 cbe.time = time[count] + 261 planeEventQueue[count].back().time; 262 cbe.function = NULL; 263 planeEventQueue[count].push_back(cbe); 264 265 DPRINTF(FlashDevice, "scheduled at: %ld\n", cbe.time); 266 267 if (!planeEvent.scheduled()) 268 schedule(planeEvent, planeEventQueue[count].back().time); 269 else if (planeEventQueue[count].back().time < planeEvent.when()) 270 reschedule(planeEvent, 271 planeEventQueue[plane_address].back().time, true); 272 } 273 } 274 275 //worst case two plane finish at the same time, each triggers an event 276 //and this callback will be called once. Maybe before the other plane 277 //could execute its event, but in the same tick. 278 planeEventQueue[plane_address].back().function = event; 279 DPRINTF(FlashDevice, "Callback queued for plane %d; %d in queue\n", 280 plane_address, planeEventQueue[plane_address].size()); 281 DPRINTF(FlashDevice, "first event @ %d\n", planeEvent.when()); 282} 283 284/** 285 * When a plane completes its action, this event is triggered. When a 286 * callback function was associated with that event, it will be called. 287 */ 288 289void 290FlashDevice::actionComplete() 291{ 292 DPRINTF(FlashDevice, "Plane action completed\n"); 293 uint8_t plane_address = 0; 294 295 uint8_t next_event = 0; 296 297 /**Search for a callback that is supposed to happen in this Tick*/ 298 for (plane_address = 0; plane_address < numPlanes; plane_address++) { 299 if (!planeEventQueue[plane_address].empty()) { 300 /** 301 * Invariant: All queued events are scheduled in the present 302 * or future. 303 */ 304 assert(planeEventQueue[plane_address].front().time >= curTick()); 305 306 if (planeEventQueue[plane_address].front().time == curTick()) { 307 /** 308 * To ensure that the follow-up action is executed correctly, 309 * the callback entry first need to be cleared before it can 310 * be called. 311 */ 312 Callback *temp = planeEventQueue[plane_address].front(). 313 function; 314 planeEventQueue[plane_address].pop_front(); 315 316 /**Found a callback, lets make it happen*/ 317 if (temp != NULL) { 318 DPRINTF(FlashDevice, "Callback, %d\n", plane_address); 319 temp->process(); 320 } 321 } 322 } 323 } 324 325 /** Find when to schedule the planeEvent next */ 326 for (plane_address = 0; plane_address < numPlanes; plane_address++) { 327 if (!planeEventQueue[plane_address].empty()) 328 if (planeEventQueue[next_event].empty() || 329 (planeEventQueue[plane_address].front().time < 330 planeEventQueue[next_event].front().time)) 331 next_event = plane_address; 332 } 333 334 /**Schedule the next plane that will be ready (if any)*/ 335 if (!planeEventQueue[next_event].empty()) { 336 DPRINTF(FlashDevice, "Schedule plane: %d\n", plane_address); 337 reschedule(planeEvent, planeEventQueue[next_event].front().time, true); 338 } 339 340 checkDrain(); 341 342 DPRINTF(FlashDevice, "returing from flash event\n"); 343 DPRINTF(FlashDevice, "first event @ %d\n", planeEvent.when()); 344} 345 346/** 347 * Handles the remapping of the pages. It is a (I hope) sensible statistic 348 * approach. asumption: garbage collection happens when a clean is needed 349 * (may become stochastic function). 350 */ 351Tick 352FlashDevice::remap(uint64_t logic_page_addr) 353{ 354 /** 355 * Are there any empty left in this Block, or do we need to do an erase 356 */ 357 if (blockEmptyEntries[locationTable[logic_page_addr].block] > 0) { 358 //just a remap 359 //update tables 360 --blockEmptyEntries[locationTable[logic_page_addr].block]; 361 //access to this table won't be sequential anymore 362 locationTable[logic_page_addr].page = pagesPerBlock + 2; 363 //access new block 364 Tick time = accessTimes(locationTable[logic_page_addr].block, 365 ActionWrite); 366 367 DPRINTF(FlashDevice, "Remap returns %d ticks\n", time); 368 return time; 369 370 } else { 371 //calculate how much time GC would have taken 372 uint32_t block = locationTable[logic_page_addr].block; 373 Tick time = ((GCActivePercentage * 374 (accessTimes(block, ActionCopy) + 375 accessTimes(block, ActionErase))) 376 / 100); 377 378 //use block as the logical start address of the block 379 block = locationTable[logic_page_addr].block * pagesPerBlock; 380 381 //assumption: clean will improve locality 382 for (uint32_t count = 0; count < pagesPerBlock; count++) { 383 assert(block + count < pagesPerDisk); 384 locationTable[block + count].page = (block + count) % 385 pagesPerBlock; 386 ++count; 387 } 388 389 blockEmptyEntries[locationTable[logic_page_addr].block] = 390 pagesPerBlock; 391 /*stats*/ 392 ++stats.totalGCActivations; 393 394 DPRINTF(FlashDevice, "Remap with erase action returns %d ticks\n", 395 time); 396 397 return time; 398 } 399 400} 401 402/** 403 * Calculates the accesstime per operation needed 404 */ 405Tick 406FlashDevice::accessTimes(uint64_t block, Actions action) 407{ 408 Tick time = 0; 409 410 switch(action) { 411 case ActionRead: { 412 /**Just read the page*/ 413 time = readLatency; 414 } break; 415 416 case ActionWrite: { 417 /**Write the page, and read the result*/ 418 time = writeLatency + readLatency; 419 } break; 420 421 case ActionErase: { 422 /**Erase and check wether it was successfull*/ 423 time = eraseLatency + readLatency; 424 } break; 425 426 case ActionCopy: { 427 /**Copy every valid page*/ 428 uint32_t validpages = blockValidEntries[block]; 429 time = validpages * (readLatency + writeLatency); 430 } break; 431 432 default: break; 433 } 434 435 //Used to determine sequential action. 436 DPRINTF(FlashDevice, "Access returns %d ticks\n", time); 437 return time; 438} 439 440/** 441 * clearUnknownPages. defines that a page is known and used 442 * unknownPages is a bitmap of all the pages. It tracks wether we can be sure 443 * that the information of this page is taken into acount in the model (is it 444 * considered in blockValidEntries and blockEmptyEntries?). If it has been 445 * used in the past, then it is known. But it needs to be tracked to make 446 * decisions about write accesses, and indirectly about copy actions. one 447 * unknownPage entry is a 32 bit integer. So if we have a page index, then 448 * that means that we need entry floor(index/32) (index >> 5) and we need to 449 * select the bit which number is equal to the remainder of index/32 450 * (index%32). The bit is cleared to make sure that we see it as considered 451 * in the future. 452 */ 453 454inline 455void 456FlashDevice::clearUnknownPages(uint32_t index) 457{ 458 unknownPages[index >> 5] &= ~(0x01 << (index % 32)); 459} 460 461/** 462 * getUnknownPages. Verify wether a page is known 463 */ 464 465inline 466bool 467FlashDevice::getUnknownPages(uint32_t index) 468{ 469 return unknownPages[index >> 5] & (0x01 << (index % 32)); 470} 471 472void 473FlashDevice::regStats() 474{ 475 using namespace Stats; 476 477 std::string fd_name = name() + ".FlashDevice"; 478 479 // Register the stats 480 /** Amount of GC activations*/ 481 stats.totalGCActivations 482 .name(fd_name + ".totalGCActivations") 483 .desc("Number of Garbage collector activations") 484 .flags(none); 485 486 /** Histogram of address accesses*/ 487 stats.writeAccess 488 .init(2) 489 .name(fd_name + ".writeAccessHist") 490 .desc("Histogram of write addresses") 491 .flags(pdf); 492 stats.readAccess 493 .init(2) 494 .name(fd_name + ".readAccessHist") 495 .desc("Histogram of read addresses") 496 .flags(pdf); 497 stats.fileSystemAccess 498 .init(100) 499 .name(fd_name + ".fileSystemAccessHist") 500 .desc("Histogram of file system accesses") 501 .flags(pdf); 502 503 /** Histogram of access latencies*/ 504 stats.writeLatency 505 .init(100) 506 .name(fd_name + ".writeLatencyHist") 507 .desc("Histogram of write latency") 508 .flags(pdf); 509 stats.readLatency 510 .init(100) 511 .name(fd_name + ".readLatencyHist") 512 .desc("Histogram of read latency") 513 .flags(pdf); 514} 515 516/** 517 * Serialize; needed to create checkpoints 518 */ 519 520void 521FlashDevice::serialize(CheckpointOut &cp) const 522{ 523 SERIALIZE_SCALAR(planeMask); 524 525 SERIALIZE_CONTAINER(unknownPages); 526 SERIALIZE_CONTAINER(blockValidEntries); 527 SERIALIZE_CONTAINER(blockEmptyEntries); 528 529 int location_table_size = locationTable.size(); 530 SERIALIZE_SCALAR(location_table_size); 531 for (uint32_t count = 0; count < location_table_size; count++) { 532 paramOut(cp, csprintf("locationTable[%d].page", count), 533 locationTable[count].page); 534 paramOut(cp, csprintf("locationTable[%d].block", count), 535 locationTable[count].block); 536 } 537}; 538 539/** 540 * Unserialize; needed to restore from checkpoints 541 */ 542 543void 544FlashDevice::unserialize(CheckpointIn &cp) 545{ 546 UNSERIALIZE_SCALAR(planeMask); 547 548 UNSERIALIZE_CONTAINER(unknownPages); 549 UNSERIALIZE_CONTAINER(blockValidEntries); 550 UNSERIALIZE_CONTAINER(blockEmptyEntries); 551 552 int location_table_size; 553 UNSERIALIZE_SCALAR(location_table_size); 554 locationTable.resize(location_table_size); 555 for (uint32_t count = 0; count < location_table_size; count++) { 556 paramIn(cp, csprintf("locationTable[%d].page", count), 557 locationTable[count].page); 558 paramIn(cp, csprintf("locationTable[%d].block", count), 559 locationTable[count].block); 560 } 561}; 562 563/** 564 * Drain; needed to enable checkpoints 565 */ 566 567DrainState 568FlashDevice::drain() 569{ 570 if (planeEvent.scheduled()) { 571 DPRINTF(Drain, "Flash device is draining...\n"); 572 return DrainState::Draining; 573 } else { 574 DPRINTF(Drain, "Flash device in drained state\n"); 575 return DrainState::Drained; 576 } 577} 578 579/** 580 * Checkdrain; needed to enable checkpoints 581 */ 582 583void 584FlashDevice::checkDrain() 585{ 586 if (drainState() != DrainState::Draining) 587 return; 588 589 if (planeEvent.when() > curTick()) { 590 DPRINTF(Drain, "Flash device is still draining\n"); 591 } else { 592 DPRINTF(Drain, "Flash device is done draining\n"); 593 signalDrainDone(); 594 } 595} 596