gem5  v22.1.0.0
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 
53 #include "dev/arm/flash_device.hh"
54 
55 #include "base/trace.hh"
56 #include "debug/Drain.hh"
57 
58 namespace gem5
59 {
60 
65 FlashDevice::FlashDevice(const FlashDeviceParams &p):
66  AbstractNVM(p),
67  diskSize(0),
68  blockSize(p.blk_size),
69  pageSize(p.page_size),
70  GCActivePercentage(p.GC_active),
71  readLatency(p.read_lat),
72  writeLatency(p.write_lat),
73  eraseLatency(p.erase_lat),
74  dataDistribution(p.data_distribution),
75  numPlanes(p.num_planes),
76  stats(this),
77  pagesPerBlock(0),
78  pagesPerDisk(0),
79  blocksPerDisk(0),
80  planeMask(numPlanes - 1),
81  planeEventQueue(numPlanes),
82  planeEvent([this]{ actionComplete(); }, name())
83 {
84 
85  /*
86  * Let 'a' be a power of two of n bits, written such that a-n is the msb
87  * and a-0 is the lsb. Since it is a power of two, only one bit (a-x,
88  * with 0 <= x <= n) is set. If we subtract one from this number the bits
89  * a-(x-1) to a-0 are set and all the other bits are cleared. Hence a
90  * bitwise AND with those two numbers results in an integer with all bits
91  * cleared.
92  */
93  if (numPlanes & planeMask)
94  fatal("Number of planes is not a power of 2 in flash device.\n");
95 }
96 
102 void
103 FlashDevice::initializeFlash(uint64_t disk_size, uint32_t sector_size)
104 {
105  diskSize = disk_size * sector_size;
109 
111  DPRINTF(FlashDevice, "diskSize: %d Bytes; %d pages per block, %d pages "
112  "per disk\n", diskSize, pagesPerBlock, pagesPerDisk);
113 
114  locationTable.resize(pagesPerDisk);
115 
117  blockValidEntries.resize(blocksPerDisk, 0);
119 
129  unknownPages.resize((pagesPerDisk >> 5) + 1, 0xFFFFFFFF);
130 
131  for (uint32_t count = 0; count < pagesPerDisk; count++) {
132  //setup lookup table + physical aspects
133 
134  if (dataDistribution == enums::stripe) {
137 
138  } else {
141  }
142  }
143 }
144 
146 {
147  DPRINTF(FlashDevice, "Remove FlashDevice\n");
148 }
149 
155 void
156 FlashDevice::accessDevice(uint64_t address, uint32_t amount,
157  const std::function<void()> &event, Actions action)
158 {
159  DPRINTF(FlashDevice, "Flash calculation for %d bytes in %d pages\n"
160  , amount, pageSize);
161 
162  std::vector<Tick> time(numPlanes, 0);
163  uint64_t logic_page_addr = address / pageSize;
164  uint32_t plane_address = 0;
165 
173  for (uint32_t count = 0; amount > (count * pageSize); count++) {
174  uint32_t index = (locationTable[logic_page_addr].block *
175  pagesPerBlock) + (logic_page_addr % pagesPerBlock);
176 
177  DPRINTF(FlashDevice, "Index 0x%8x, Block 0x%8x, pages/block %d,"
178  " logic address 0x%8x\n", index,
179  locationTable[logic_page_addr].block, pagesPerBlock,
180  logic_page_addr);
181  DPRINTF(FlashDevice, "Page %d; %d bytes up to this point\n", count,
182  (count * pageSize));
183 
184  plane_address = locationTable[logic_page_addr].block & planeMask;
185 
186  if (action == ActionRead) {
187  //lookup
188  //call accessTimes
189  time[plane_address] += accessTimes(locationTable[logic_page_addr]
190  .block, ActionRead);
191 
192  /*stats*/
193  stats.readAccess.sample(logic_page_addr);
194  stats.readLatency.sample(time[plane_address]);
195  } else { //write
196  //lookup
197  //call accessTimes if appropriate, page may be unknown, so lets
198  //give it the benefit of the doubt
199 
200  if (getUnknownPages(index))
201  time[plane_address] += accessTimes
202  (locationTable[logic_page_addr].block, ActionWrite);
203 
204  else //A remap is needed
205  time[plane_address] += remap(logic_page_addr);
206 
207  /*stats*/
208  stats.writeAccess.sample(logic_page_addr);
209  stats.writeLatency.sample(time[plane_address]);
210  }
211 
219  if (getUnknownPages(index)) {
221  --blockEmptyEntries[locationTable[logic_page_addr].block];
222  ++blockValidEntries[locationTable[logic_page_addr].block];
223  }
224 
225  stats.fileSystemAccess.sample(address);
226  ++logic_page_addr;
227  }
228 
233  for (uint32_t count = 0; count < numPlanes; count++){
234  plane_address = (time[plane_address] > time[count]) ? plane_address
235  : count;
236 
237  DPRINTF(FlashDevice, "Plane %d is busy for %d ticks\n", count,
238  time[count]);
239 
240  if (time[count] != 0) {
241 
242  struct CallBackEntry cbe;
249  if (planeEventQueue[count].empty())
250  cbe.time = time[count] + curTick();
251  else
252  cbe.time = time[count] +
253  planeEventQueue[count].back().time;
254  planeEventQueue[count].push_back(cbe);
255 
256  DPRINTF(FlashDevice, "scheduled at: %ld\n", cbe.time);
257 
258  if (!planeEvent.scheduled())
259  schedule(planeEvent, planeEventQueue[count].back().time);
260  else if (planeEventQueue[count].back().time < planeEvent.when())
262  planeEventQueue[plane_address].back().time, true);
263  }
264  }
265 
266  //worst case two plane finish at the same time, each triggers an event
267  //and this callback will be called once. Maybe before the other plane
268  //could execute its event, but in the same tick.
269  planeEventQueue[plane_address].back().function = event;
270  DPRINTF(FlashDevice, "Callback queued for plane %d; %d in queue\n",
271  plane_address, planeEventQueue[plane_address].size());
272  DPRINTF(FlashDevice, "first event @ %d\n", planeEvent.when());
273 }
274 
280 void
282 {
283  DPRINTF(FlashDevice, "Plane action completed\n");
284  uint8_t plane_address = 0;
285 
286  uint8_t next_event = 0;
287 
289  for (plane_address = 0; plane_address < numPlanes; plane_address++) {
290  if (!planeEventQueue[plane_address].empty()) {
295  assert(planeEventQueue[plane_address].front().time >= curTick());
296 
297  if (planeEventQueue[plane_address].front().time == curTick()) {
303  auto temp = planeEventQueue[plane_address].front().function;
304  planeEventQueue[plane_address].pop_front();
305 
307  if (temp) {
308  DPRINTF(FlashDevice, "Callback, %d\n", plane_address);
309  temp();
310  }
311  }
312  }
313  }
314 
316  for (plane_address = 0; plane_address < numPlanes; plane_address++) {
317  if (!planeEventQueue[plane_address].empty())
318  if (planeEventQueue[next_event].empty() ||
319  (planeEventQueue[plane_address].front().time <
320  planeEventQueue[next_event].front().time))
321  next_event = plane_address;
322  }
323 
325  if (!planeEventQueue[next_event].empty()) {
326  DPRINTF(FlashDevice, "Schedule plane: %d\n", plane_address);
327  reschedule(planeEvent, planeEventQueue[next_event].front().time, true);
328  }
329 
330  checkDrain();
331 
332  DPRINTF(FlashDevice, "returing from flash event\n");
333  DPRINTF(FlashDevice, "first event @ %d\n", planeEvent.when());
334 }
335 
341 Tick
342 FlashDevice::remap(uint64_t logic_page_addr)
343 {
347  if (blockEmptyEntries[locationTable[logic_page_addr].block] > 0) {
348  //just a remap
349  //update tables
350  --blockEmptyEntries[locationTable[logic_page_addr].block];
351  //access to this table won't be sequential anymore
352  locationTable[logic_page_addr].page = pagesPerBlock + 2;
353  //access new block
354  Tick time = accessTimes(locationTable[logic_page_addr].block,
355  ActionWrite);
356 
357  DPRINTF(FlashDevice, "Remap returns %d ticks\n", time);
358  return time;
359 
360  } else {
361  //calculate how much time GC would have taken
362  uint32_t block = locationTable[logic_page_addr].block;
363  Tick time = ((GCActivePercentage *
364  (accessTimes(block, ActionCopy) +
365  accessTimes(block, ActionErase)))
366  / 100);
367 
368  //use block as the logical start address of the block
369  block = locationTable[logic_page_addr].block * pagesPerBlock;
370 
371  //assumption: clean will improve locality
372  for (uint32_t count = 0; count < pagesPerBlock; count++) {
373  assert(block + count < pagesPerDisk);
374  locationTable[block + count].page = (block + count) %
376  }
377 
378  blockEmptyEntries[locationTable[logic_page_addr].block] =
380  /*stats*/
382 
383  DPRINTF(FlashDevice, "Remap with erase action returns %d ticks\n",
384  time);
385 
386  return time;
387  }
388 
389 }
390 
394 Tick
395 FlashDevice::accessTimes(uint64_t block, Actions action)
396 {
397  Tick time = 0;
398 
399  switch(action) {
400  case ActionRead: {
402  time = readLatency;
403  } break;
404 
405  case ActionWrite: {
407  time = writeLatency + readLatency;
408  } break;
409 
410  case ActionErase: {
412  time = eraseLatency + readLatency;
413  } break;
414 
415  case ActionCopy: {
417  uint32_t validpages = blockValidEntries[block];
418  time = validpages * (readLatency + writeLatency);
419  } break;
420 
421  default: break;
422  }
423 
424  //Used to determine sequential action.
425  DPRINTF(FlashDevice, "Access returns %d ticks\n", time);
426  return time;
427 }
428 
443 inline
444 void
446 {
447  unknownPages[index >> 5] &= ~(0x01 << (index % 32));
448 }
449 
454 inline
455 bool
457 {
458  return unknownPages[index >> 5] & (0x01 << (index % 32));
459 }
460 
462  : statistics::Group(parent, "FlashDevice"),
463  ADD_STAT(totalGCActivations, statistics::units::Count::get(),
464  "Number of Garbage collector activations"),
465  ADD_STAT(writeAccess, statistics::units::Count::get(),
466  "Histogram of write addresses"),
467  ADD_STAT(readAccess, statistics::units::Count::get(),
468  "Histogram of read addresses"),
469  ADD_STAT(fileSystemAccess, statistics::units::Count::get(),
470  "Histogram of file system accesses"),
471  ADD_STAT(writeLatency, statistics::units::Tick::get(),
472  "Histogram of write latency"),
473  ADD_STAT(readLatency, statistics::units::Tick::get(),
474  "Histogram of read latency")
475 {
476  using namespace statistics;
477 
480  .flags(none);
481 
484  .init(2)
485  .flags(pdf);
486  readAccess
487  .init(2)
488  .flags(pdf);
490  .init(100)
491  .flags(pdf);
492 
495  .init(100)
496  .flags(pdf);
498  .init(100)
499  .flags(pdf);
500 }
501 
506 void
508 {
510 
514 
515  int location_table_size = locationTable.size();
516  SERIALIZE_SCALAR(location_table_size);
517  for (uint32_t count = 0; count < location_table_size; count++) {
518  paramOut(cp, csprintf("locationTable[%d].page", count),
519  locationTable[count].page);
520  paramOut(cp, csprintf("locationTable[%d].block", count),
521  locationTable[count].block);
522  }
523 };
524 
529 void
531 {
533 
537 
538  int location_table_size;
539  UNSERIALIZE_SCALAR(location_table_size);
540  locationTable.resize(location_table_size);
541  for (uint32_t count = 0; count < location_table_size; count++) {
542  paramIn(cp, csprintf("locationTable[%d].page", count),
543  locationTable[count].page);
544  paramIn(cp, csprintf("locationTable[%d].block", count),
545  locationTable[count].block);
546  }
547 };
548 
555 {
556  if (planeEvent.scheduled()) {
557  DPRINTF(Drain, "Flash device is draining...\n");
558  return DrainState::Draining;
559  } else {
560  DPRINTF(Drain, "Flash device in drained state\n");
561  return DrainState::Drained;
562  }
563 }
564 
569 void
571 {
573  return;
574 
575  if (planeEvent.when() > curTick()) {
576  DPRINTF(Drain, "Flash device is still draining\n");
577  } else {
578  DPRINTF(Drain, "Flash device is done draining\n");
579  signalDrainDone();
580  }
581 }
582 
583 } // namespace gem5
#define DPRINTF(x,...)
Definition: trace.hh:186
This is an interface between the disk interface (which will handle the disk data transactions) and th...
Definition: abstract_nvm.hh:57
Flash Device model The Flash Device model is a timing model for a NAND flash device.
Definition: flash_device.hh:58
void checkDrain()
Checkdrain; needed to enable checkpoints.
EventFunctionWrapper planeEvent
Completion event.
uint32_t blocksPerDisk
const enums::DataDistribution dataDistribution
Flash organization.
void initializeFlash(uint64_t disk_size, uint32_t sector_size)
Initialization function; called when all disk specifics are known.
void actionComplete()
Event rescheduler.
const Tick writeLatency
void serialize(CheckpointOut &cp) const override
Serialize; needed to create checkpoints.
Tick accessTimes(uint64_t address, Actions accesstype)
Access time calculator.
std::vector< struct PageMapEntry > locationTable
address to logic place has a block and a page field
void accessDevice(uint64_t address, uint32_t amount, const std::function< void()> &event, Actions action)
Flash action function.
FlashDevice(const FlashDeviceParams &)
Initialize functions.
Definition: flash_device.cc:65
const uint32_t blockSize
uint32_t pagesPerBlock
Disk dimensions in pages and blocks.
uint64_t diskSize
Disk sizes in bytes.
Tick remap(uint64_t logic_page_addr)
FTL functionality.
std::vector< uint32_t > blockEmptyEntries
number of empty entries
void unserialize(CheckpointIn &cp) override
Unserialize; needed to restore from checkpoints.
std::vector< std::deque< struct CallBackEntry > > planeEventQueue
This vector of queues keeps track of all the callbacks per plane.
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...
DrainState drain() override
Checkpoint functions.
void clearUnknownPages(uint32_t index)
Function to indicate that a page is known.
Actions
Defines the possible actions to the flash.
Definition: flash_device.hh:75
@ ActionCopy
A copy involves taking all the used pages from a block and store it in another.
Definition: flash_device.hh:83
const uint32_t pageSize
const uint32_t GCActivePercentage
Garbage collection algorithm emulator.
const uint32_t numPlanes
std::vector< uint32_t > blockValidEntries
number of valid entries per block
const Tick eraseLatency
struct FlashDeviceStats stats
RequestHandler stats.
bool getUnknownPages(uint32_t index)
Function to test if a page is known.
const Tick readLatency
Access latencies.
Derived & flags(Flags _flags)
Set the flags and marks this stat to print at the end of simulation.
Definition: statistics.hh:358
void sample(const U &v, int n=1)
Add a value to the distribtion n times.
Definition: statistics.hh:1328
Statistics container.
Definition: group.hh:94
Histogram & init(size_type size)
Set the parameters of this histogram.
Definition: statistics.hh:2154
#define ADD_STAT(n,...)
Convenience macro to add a stat to a statistics group.
Definition: group.hh:75
void signalDrainDone() const
Signal that an object is drained.
Definition: drain.hh:305
DrainState drainState() const
Return the current drain state of an object.
Definition: drain.hh:324
DrainState
Object drain/handover states.
Definition: drain.hh:75
@ Draining
Draining buffers pending serialization/handover.
@ Drained
Buffers drained, ready for serialization/handover.
bool scheduled() const
Determine if the current event is scheduled.
Definition: eventq.hh:465
void schedule(Event &event, Tick when)
Definition: eventq.hh:1019
void reschedule(Event &event, Tick when, bool always=false)
Definition: eventq.hh:1037
Tick when() const
Get the time that the event is scheduled.
Definition: eventq.hh:508
#define fatal(...)
This implements a cprintf based fatal() function.
Definition: logging.hh:190
#define UNSERIALIZE_CONTAINER(member)
Definition: serialize.hh:634
#define SERIALIZE_CONTAINER(member)
Definition: serialize.hh:626
Bitfield< 10, 5 > event
Bitfield< 30, 0 > index
int amount
Definition: qarma.hh:70
Bitfield< 54 > p
Definition: pagetable.hh:70
const FlagsType pdf
Print the percent of the total that this entry represents.
Definition: info.hh:62
const FlagsType none
Nothing extra to print.
Definition: info.hh:54
Reference material can be found at the JEDEC website: UFS standard http://www.jedec....
Tick curTick()
The universal simulation clock.
Definition: cur_tick.hh:46
std::ostream CheckpointOut
Definition: serialize.hh:66
void paramOut(CheckpointOut &cp, const std::string &name, ExtMachInst const &machInst)
Definition: types.cc:40
void paramIn(CheckpointIn &cp, const std::string &name, ExtMachInst &machInst)
Definition: types.cc:72
uint64_t Tick
Tick count type.
Definition: types.hh:58
std::string csprintf(const char *format, const Args &...args)
Definition: cprintf.hh:161
#define UNSERIALIZE_SCALAR(scalar)
Definition: serialize.hh:575
#define SERIALIZE_SCALAR(scalar)
Definition: serialize.hh:568
statistics::Scalar totalGCActivations
Amount of GC activations.
FlashDeviceStats(statistics::Group *parent)
statistics::Histogram fileSystemAccess
statistics::Histogram readAccess
statistics::Histogram readLatency
statistics::Histogram writeAccess
Histogram of address accesses.
statistics::Histogram writeLatency
Histogram of access latencies.
const std::string & name()
Definition: trace.cc:49

Generated on Wed Dec 21 2022 10:22:32 for gem5 by doxygen 1.9.1