gem5 v24.0.0.0
Loading...
Searching...
No Matches
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
54
55#include "base/trace.hh"
56#include "debug/Drain.hh"
57
58namespace gem5
59{
60
65FlashDevice::FlashDevice(const FlashDeviceParams &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
102void
103FlashDevice::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
115
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
155void
156FlashDevice::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
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
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
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())
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
280void
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
341Tick
342FlashDevice::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,
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
394Tick
395FlashDevice::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
443inline
444void
446{
447 unknownPages[index >> 5] &= ~(0x01 << (index % 32));
448}
449
454inline
455bool
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);
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
506void
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
529void
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");
559 } else {
560 DPRINTF(Drain, "Flash device in drained state\n");
561 return DrainState::Drained;
562 }
563}
564
569void
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");
580 }
581}
582
583} // namespace gem5
#define DPRINTF(x,...)
Definition trace.hh:210
This is an interface between the disk interface (which will handle the disk data transactions) and th...
Flash Device model The Flash Device model is a timing model for a NAND flash device.
void checkDrain()
Checkdrain; needed to enable checkpoints.
EventFunctionWrapper planeEvent
Completion event.
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.
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.
@ ActionCopy
A copy involves taking all the used pages from a block and store it in another.
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.
void sample(const U &v, int n=1)
Add a value to the distribtion n times.
Statistics container.
Definition group.hh:93
Histogram & init(size_type size)
Set the parameters of this histogram.
STL vector class.
Definition stl.hh:37
#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:458
void schedule(Event &event, Tick when)
Definition eventq.hh:1012
void reschedule(Event &event, Tick when, bool always=false)
Definition eventq.hh:1030
Tick when() const
Get the time that the event is scheduled.
Definition eventq.hh:501
#define fatal(...)
This implements a cprintf based fatal() function.
Definition logging.hh:200
#define UNSERIALIZE_CONTAINER(member)
Definition serialize.hh:634
#define SERIALIZE_CONTAINER(member)
Definition serialize.hh:626
Bitfield< 10, 5 > event
Bitfield< 30, 0 > index
Bitfield< 0 > p
int amount
Definition qarma.hh:70
const FlagsType pdf
Print the percent of the total that this entry represents.
Definition info.hh:61
const FlagsType none
Nothing extra to print.
Definition info.hh:53
Copyright (c) 2024 - Pranith Kumar Copyright (c) 2020 Inria All rights reserved.
Definition binary32.hh:36
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 writeAccess
Histogram of address accesses.
statistics::Histogram writeLatency
Histogram of access latencies.
const std::string & name()
Definition trace.cc:48

Generated on Tue Jun 18 2024 16:24:02 for gem5 by doxygen 1.11.0