gem5
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
flash_device.cc
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2013-2015 ARM Limited
3  * All rights reserved
4  *
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.
13  *
14  * Redistribution and use in source and binary forms, with or without
15  * modification, are permitted provided that the following conditions are
16  * met: redistributions of source code must retain the above copyright
17  * notice, this list of conditions and the following disclaimer;
18  * redistributions in binary form must reproduce the above copyright
19  * notice, this list of conditions and the following disclaimer in the
20  * documentation and/or other materials provided with the distribution;
21  * neither the name of the copyright holders nor the names of its
22  * contributors may be used to endorse or promote products derived from
23  * this software without specific prior written permission.
24  *
25  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
26  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
27  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
28  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
29  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
30  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
31  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
32  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
33  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
34  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
35  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36  *
37  * Authors: Rene de Jong
38  */
39 
55 #include "dev/arm/flash_device.hh"
56 
57 #include "base/trace.hh"
58 #include "debug/Drain.hh"
59 
65 FlashDeviceParams::create()
66 {
67  return new FlashDevice(this);
68 }
69 
70 
75 FlashDevice::FlashDevice(const FlashDeviceParams* p):
76  AbstractNVM(p),
77  diskSize(0),
78  blockSize(p->blk_size),
79  pageSize(p->page_size),
80  GCActivePercentage(p->GC_active),
81  readLatency(p->read_lat),
82  writeLatency(p->write_lat),
83  eraseLatency(p->erase_lat),
84  dataDistribution(p->data_distribution),
85  numPlanes(p->num_planes),
86  pagesPerBlock(0),
87  pagesPerDisk(0),
88  blocksPerDisk(0),
89  planeMask(numPlanes - 1),
90  planeEventQueue(numPlanes),
91  planeEvent(this)
92 {
93 
94  /*
95  * Let 'a' be a power of two of n bits, written such that a-n is the msb
96  * and a-0 is the lsb. Since it is a power of two, only one bit (a-x,
97  * with 0 <= x <= n) is set. If we subtract one from this number the bits
98  * a-(x-1) to a-0 are set and all the other bits are cleared. Hence a
99  * bitwise AND with those two numbers results in an integer with all bits
100  * cleared.
101  */
102  if (numPlanes & planeMask)
103  fatal("Number of planes is not a power of 2 in flash device.\n");
104 }
105 
111 void
112 FlashDevice::initializeFlash(uint64_t disk_size, uint32_t sector_size)
113 {
114  diskSize = disk_size * sector_size;
118 
120  DPRINTF(FlashDevice, "diskSize: %d Bytes; %d pages per block, %d pages "
121  "per disk\n", diskSize, pagesPerBlock, pagesPerDisk);
122 
123  locationTable.resize(pagesPerDisk);
124 
126  blockValidEntries.resize(blocksPerDisk, 0);
128 
138  unknownPages.resize((pagesPerDisk >> 5) + 1, 0xFFFFFFFF);
139 
140  for (uint32_t count = 0; count < pagesPerDisk; count++) {
141  //setup lookup table + physical aspects
142 
143  if (dataDistribution == Enums::stripe) {
146 
147  } else {
150  }
151  }
152 }
153 
155 {
156  DPRINTF(FlashDevice, "Remove FlashDevice\n");
157 }
158 
164 void
165 FlashDevice::accessDevice(uint64_t address, uint32_t amount, Callback *event,
166  Actions action)
167 {
168  DPRINTF(FlashDevice, "Flash calculation for %d bytes in %d pages\n"
169  , amount, pageSize);
170 
171  std::vector<Tick> time(numPlanes, 0);
172  uint64_t logic_page_addr = address / pageSize;
173  uint32_t plane_address = 0;
174 
182  for (uint32_t count = 0; amount > (count * pageSize); count++) {
183  uint32_t index = (locationTable[logic_page_addr].block *
184  pagesPerBlock) + (logic_page_addr % pagesPerBlock);
185 
186  DPRINTF(FlashDevice, "Index 0x%8x, Block 0x%8x, pages/block %d,"
187  " logic address 0x%8x\n", index,
188  locationTable[logic_page_addr].block, pagesPerBlock,
189  logic_page_addr);
190  DPRINTF(FlashDevice, "Page %d; %d bytes up to this point\n", count,
191  (count * pageSize));
192 
193  plane_address = locationTable[logic_page_addr].block & planeMask;
194 
195  if (action == ActionRead) {
196  //lookup
197  //call accessTimes
198  time[plane_address] += accessTimes(locationTable[logic_page_addr]
199  .block, ActionRead);
200 
201  /*stats*/
202  stats.readAccess.sample(logic_page_addr);
203  stats.readLatency.sample(time[plane_address]);
204  } else { //write
205  //lookup
206  //call accessTimes if appropriate, page may be unknown, so lets
207  //give it the benefit of the doubt
208 
209  if (getUnknownPages(index))
210  time[plane_address] += accessTimes
211  (locationTable[logic_page_addr].block, ActionWrite);
212 
213  else //A remap is needed
214  time[plane_address] += remap(logic_page_addr);
215 
216  /*stats*/
217  stats.writeAccess.sample(logic_page_addr);
218  stats.writeLatency.sample(time[plane_address]);
219  }
220 
228  if (getUnknownPages(index)) {
229  clearUnknownPages(index);
230  --blockEmptyEntries[locationTable[logic_page_addr].block];
231  ++blockValidEntries[locationTable[logic_page_addr].block];
232  }
233 
234  stats.fileSystemAccess.sample(address);
235  ++logic_page_addr;
236  }
237 
242  for (uint32_t count = 0; count < numPlanes; count++){
243  plane_address = (time[plane_address] > time[count]) ? plane_address
244  : count;
245 
246  DPRINTF(FlashDevice, "Plane %d is busy for %d ticks\n", count,
247  time[count]);
248 
249  if (time[count] != 0) {
250 
251  struct CallBackEntry cbe;
258  if (planeEventQueue[count].empty())
259  cbe.time = time[count] + curTick();
260  else
261  cbe.time = time[count] +
262  planeEventQueue[count].back().time;
263  cbe.function = NULL;
264  planeEventQueue[count].push_back(cbe);
265 
266  DPRINTF(FlashDevice, "scheduled at: %ld\n", cbe.time);
267 
268  if (!planeEvent.scheduled())
269  schedule(planeEvent, planeEventQueue[count].back().time);
270  else if (planeEventQueue[count].back().time < planeEvent.when())
272  planeEventQueue[plane_address].back().time, true);
273  }
274  }
275 
276  //worst case two plane finish at the same time, each triggers an event
277  //and this callback will be called once. Maybe before the other plane
278  //could execute its event, but in the same tick.
279  planeEventQueue[plane_address].back().function = event;
280  DPRINTF(FlashDevice, "Callback queued for plane %d; %d in queue\n",
281  plane_address, planeEventQueue[plane_address].size());
282  DPRINTF(FlashDevice, "first event @ %d\n", planeEvent.when());
283 }
284 
290 void
292 {
293  DPRINTF(FlashDevice, "Plane action completed\n");
294  uint8_t plane_address = 0;
295 
296  uint8_t next_event = 0;
297 
299  for (plane_address = 0; plane_address < numPlanes; plane_address++) {
300  if (!planeEventQueue[plane_address].empty()) {
305  assert(planeEventQueue[plane_address].front().time >= curTick());
306 
307  if (planeEventQueue[plane_address].front().time == curTick()) {
313  Callback *temp = planeEventQueue[plane_address].front().
314  function;
315  planeEventQueue[plane_address].pop_front();
316 
318  if (temp != NULL) {
319  DPRINTF(FlashDevice, "Callback, %d\n", plane_address);
320  temp->process();
321  }
322  }
323  }
324  }
325 
327  for (plane_address = 0; plane_address < numPlanes; plane_address++) {
328  if (!planeEventQueue[plane_address].empty())
329  if (planeEventQueue[next_event].empty() ||
330  (planeEventQueue[plane_address].front().time <
331  planeEventQueue[next_event].front().time))
332  next_event = plane_address;
333  }
334 
336  if (!planeEventQueue[next_event].empty()) {
337  DPRINTF(FlashDevice, "Schedule plane: %d\n", plane_address);
338  reschedule(planeEvent, planeEventQueue[next_event].front().time, true);
339  }
340 
341  checkDrain();
342 
343  DPRINTF(FlashDevice, "returing from flash event\n");
344  DPRINTF(FlashDevice, "first event @ %d\n", planeEvent.when());
345 }
346 
352 Tick
353 FlashDevice::remap(uint64_t logic_page_addr)
354 {
358  if (blockEmptyEntries[locationTable[logic_page_addr].block] > 0) {
359  //just a remap
360  //update tables
361  --blockEmptyEntries[locationTable[logic_page_addr].block];
362  //access to this table won't be sequential anymore
363  locationTable[logic_page_addr].page = pagesPerBlock + 2;
364  //access new block
365  Tick time = accessTimes(locationTable[logic_page_addr].block,
366  ActionWrite);
367 
368  DPRINTF(FlashDevice, "Remap returns %d ticks\n", time);
369  return time;
370 
371  } else {
372  //calculate how much time GC would have taken
373  uint32_t block = locationTable[logic_page_addr].block;
374  Tick time = ((GCActivePercentage *
375  (accessTimes(block, ActionCopy) +
376  accessTimes(block, ActionErase)))
377  / 100);
378 
379  //use block as the logical start address of the block
380  block = locationTable[logic_page_addr].block * pagesPerBlock;
381 
382  //assumption: clean will improve locality
383  for (uint32_t count = 0; count < pagesPerBlock; count++) {
384  assert(block + count < pagesPerDisk);
385  locationTable[block + count].page = (block + count) %
386  pagesPerBlock;
387  }
388 
389  blockEmptyEntries[locationTable[logic_page_addr].block] =
391  /*stats*/
393 
394  DPRINTF(FlashDevice, "Remap with erase action returns %d ticks\n",
395  time);
396 
397  return time;
398  }
399 
400 }
401 
405 Tick
406 FlashDevice::accessTimes(uint64_t block, Actions action)
407 {
408  Tick time = 0;
409 
410  switch(action) {
411  case ActionRead: {
413  time = readLatency;
414  } break;
415 
416  case ActionWrite: {
418  time = writeLatency + readLatency;
419  } break;
420 
421  case ActionErase: {
423  time = eraseLatency + readLatency;
424  } break;
425 
426  case ActionCopy: {
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 
454 inline
455 void
457 {
458  unknownPages[index >> 5] &= ~(0x01 << (index % 32));
459 }
460 
465 inline
466 bool
468 {
469  return unknownPages[index >> 5] & (0x01 << (index % 32));
470 }
471 
472 void
474 {
476 
477  using namespace Stats;
478 
479  std::string fd_name = name() + ".FlashDevice";
480 
481  // Register the stats
484  .name(fd_name + ".totalGCActivations")
485  .desc("Number of Garbage collector activations")
486  .flags(none);
487 
490  .init(2)
491  .name(fd_name + ".writeAccessHist")
492  .desc("Histogram of write addresses")
493  .flags(pdf);
495  .init(2)
496  .name(fd_name + ".readAccessHist")
497  .desc("Histogram of read addresses")
498  .flags(pdf);
500  .init(100)
501  .name(fd_name + ".fileSystemAccessHist")
502  .desc("Histogram of file system accesses")
503  .flags(pdf);
504 
507  .init(100)
508  .name(fd_name + ".writeLatencyHist")
509  .desc("Histogram of write latency")
510  .flags(pdf);
512  .init(100)
513  .name(fd_name + ".readLatencyHist")
514  .desc("Histogram of read latency")
515  .flags(pdf);
516 }
517 
522 void
524 {
526 
530 
531  int location_table_size = locationTable.size();
532  SERIALIZE_SCALAR(location_table_size);
533  for (uint32_t count = 0; count < location_table_size; count++) {
534  paramOut(cp, csprintf("locationTable[%d].page", count),
535  locationTable[count].page);
536  paramOut(cp, csprintf("locationTable[%d].block", count),
537  locationTable[count].block);
538  }
539 };
540 
545 void
547 {
549 
553 
554  int location_table_size;
555  UNSERIALIZE_SCALAR(location_table_size);
556  locationTable.resize(location_table_size);
557  for (uint32_t count = 0; count < location_table_size; count++) {
558  paramIn(cp, csprintf("locationTable[%d].page", count),
559  locationTable[count].page);
560  paramIn(cp, csprintf("locationTable[%d].block", count),
561  locationTable[count].block);
562  }
563 };
564 
571 {
572  if (planeEvent.scheduled()) {
573  DPRINTF(Drain, "Flash device is draining...\n");
574  return DrainState::Draining;
575  } else {
576  DPRINTF(Drain, "Flash device in drained state\n");
577  return DrainState::Drained;
578  }
579 }
580 
585 void
587 {
589  return;
590 
591  if (planeEvent.when() > curTick()) {
592  DPRINTF(Drain, "Flash device is still draining\n");
593  } else {
594  DPRINTF(Drain, "Flash device is done draining\n");
595  signalDrainDone();
596  }
597 }
count
Definition: misc.hh:704
uint32_t planeMask
uint32_t pagesPerBlock
Disk dimensions in pages and blocks.
#define DPRINTF(x,...)
Definition: trace.hh:212
void serialize(CheckpointOut &cp) const override
Serialize; needed to create checkpoints.
const FlagsType pdf
Print the percent of the total that this entry represents.
Definition: info.hh:51
void actionComplete()
Event rescheduler.
const uint32_t blockSize
Bitfield< 30, 0 > index
virtual void process()=0
virtual process function that is invoked when the callback queue is executed.
void regStats() override
Stats register function.
std::vector< uint32_t > blockEmptyEntries
number of empty entries
const uint32_t numPlanes
Stats::Scalar totalGCActivations
Amount of GC activations.
Definition: flash_device.hh:97
Generic callback class.
Definition: callback.hh:41
const Tick eraseLatency
DrainState
Object drain/handover states.
Definition: drain.hh:71
Stats::Histogram writeAccess
Histogram of address accesses.
Running normally.
std::vector< struct PageMapEntry > locationTable
address to logic place has a block and a page field
std::vector< uint32_t > unknownPages
when the disk is first started we are unsure of the number of used pages, this variable will help det...
Stats::Histogram fileSystemAccess
Stats::Histogram writeLatency
Histogram of access latencies.
bool scheduled() const
Determine if the current event is scheduled.
Definition: eventq.hh:381
void unserialize(CheckpointIn &cp) override
Unserialize; needed to restore from checkpoints.
Tick accessTimes(uint64_t address, Actions accesstype)
Access time calculator.
Histogram & init(size_type size)
Set the parameters of this histogram.
Definition: statistics.hh:2560
const Enums::DataDistribution dataDistribution
Flash organization.
virtual void regStats()
Register statistics for this object.
Definition: sim_object.cc:105
void clearUnknownPages(uint32_t index)
Function to indicate that a page is known.
Derived & flags(Flags _flags)
Set the flags and marks this stat to print at the end of simulation.
Definition: statistics.hh:311
DrainState drain() override
Checkpoint functions.
EventWrapper< FlashDevice,&FlashDevice::actionComplete > planeEvent
Completion event.
void checkDrain()
Checkdrain; needed to enable checkpoints.
#define UNSERIALIZE_SCALAR(scalar)
Definition: serialize.hh:145
#define SERIALIZE_CONTAINER(member)
Definition: serialize.hh:164
void accessDevice(uint64_t address, uint32_t amount, Callback *event, Actions action)
Flash action function.
Tick curTick()
The current simulated tick.
Definition: core.hh:47
FlashDevice(const FlashDeviceParams *)
Initialize functions.
Definition: flash_device.cc:75
std::string csprintf(const char *format, const Args &...args)
Definition: cprintf.hh:161
struct FlashDeviceStats stats
RequestHandler stats.
Tick when() const
Get the time that the event is scheduled.
Definition: eventq.hh:397
uint64_t Tick
Tick count type.
Definition: types.hh:63
A copy involves taking all the used pages from a block and store it in another.
Definition: flash_device.hh:81
void paramOut(CheckpointOut &cp, const string &name, ExtMachInst const &machInst)
Definition: types.cc:40
const Tick readLatency
Access latencies.
#define fatal(...)
Definition: misc.hh:163
#define UNSERIALIZE_CONTAINER(member)
Definition: serialize.hh:167
const FlagsType none
Nothing extra to print.
Definition: info.hh:43
std::vector< uint32_t > blockValidEntries
number of valid entries per block
Draining buffers pending serialization/handover.
Bitfield< 10, 5 > event
Flash Device model The Flash Device model is a timing model for a NAND flash device.
Definition: flash_device.hh:56
#define SERIALIZE_SCALAR(scalar)
Definition: serialize.hh:143
std::vector< std::deque< struct CallBackEntry > > planeEventQueue
This vector of queues keeps track of all the callbacks per plane.
Derived & name(const std::string &name)
Set the name and marks this stat to print at the end of simulation.
Definition: statistics.hh:254
void reschedule(Event &event, Tick when, bool always=false)
Definition: eventq.hh:740
int size()
Definition: pagetable.hh:146
virtual const std::string name() const
Definition: sim_object.hh:117
std::ostream CheckpointOut
Definition: serialize.hh:67
Actions
Defines the possible actions to the flash.
Definition: flash_device.hh:73
void signalDrainDone() const
Signal that an object is drained.
Definition: drain.hh:267
Tick remap(uint64_t logic_page_addr)
FTL functionality.
void schedule(Event &event, Tick when)
Definition: eventq.hh:728
const uint32_t pageSize
void paramIn(CheckpointIn &cp, const string &name, ExtMachInst &machInst)
Definition: types.cc:71
DrainState drainState() const
Return the current drain state of an object.
Definition: drain.hh:282
This is an interface between the disk interface (which will handle the disk data transactions) and th...
Definition: abstract_nvm.hh:55
uint32_t blocksPerDisk
Derived & desc(const std::string &_desc)
Set the description and marks this stat to print at the end of simulation.
Definition: statistics.hh:287
bool getUnknownPages(uint32_t index)
Function to test if a page is known.
uint64_t diskSize
Disk sizes in bytes.
const uint32_t GCActivePercentage
Garbage collection algorithm emulator.
Bitfield< 0 > p
uint32_t pagesPerDisk
void sample(const U &v, int n=1)
Add a value to the distribtion n times.
Definition: statistics.hh:1869
const Tick writeLatency
void initializeFlash(uint64_t disk_size, uint32_t sector_size)
Initialization function; called when all disk specifics are known.

Generated on Fri Jun 9 2017 13:03:45 for gem5 by doxygen 1.8.6