gem5 [DEVELOP-FOR-25.1]
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
52
54
55#include "base/trace.hh"
56#include "debug/Drain.hh"
57#include "params/FlashDevice.hh"
58
59namespace gem5
60{
61
65
66FlashDevice::FlashDevice(const FlashDeviceParams &p):
68 diskSize(0),
69 blockSize(p.blk_size),
70 pageSize(p.page_size),
71 GCActivePercentage(p.GC_active),
72 readLatency(p.read_lat),
73 writeLatency(p.write_lat),
74 eraseLatency(p.erase_lat),
75 dataDistribution(p.data_distribution),
76 numPlanes(p.num_planes),
77 stats(this),
79 pagesPerDisk(0),
83 planeEvent([this]{ actionComplete(); }, name())
84{
85
86 /*
87 * Let 'a' be a power of two of n bits, written such that a-n is the msb
88 * and a-0 is the lsb. Since it is a power of two, only one bit (a-x,
89 * with 0 <= x <= n) is set. If we subtract one from this number the bits
90 * a-(x-1) to a-0 are set and all the other bits are cleared. Hence a
91 * bitwise AND with those two numbers results in an integer with all bits
92 * cleared.
93 */
94 if (numPlanes & planeMask)
95 fatal("Number of planes is not a power of 2 in flash device.\n");
96}
97
103void
104FlashDevice::initializeFlash(uint64_t disk_size, uint32_t sector_size)
105{
106 diskSize = disk_size * sector_size;
110
112 DPRINTF(FlashDevice, "diskSize: %d Bytes; %d pages per block, %d pages "
113 "per disk\n", diskSize, pagesPerBlock, pagesPerDisk);
114
116
120
130 unknownPages.resize((pagesPerDisk >> 5) + 1, 0xFFFFFFFF);
131
132 for (uint32_t count = 0; count < pagesPerDisk; count++) {
133 //setup lookup table + physical aspects
134
135 if (dataDistribution == enums::stripe) {
138
139 } else {
142 }
143 }
144}
145
147{
148 DPRINTF(FlashDevice, "Remove FlashDevice\n");
149}
150
156void
157FlashDevice::accessDevice(uint64_t address, uint32_t amount,
158 const std::function<void()> &event, Actions action)
159{
160 DPRINTF(FlashDevice, "Flash calculation for %d bytes in %d pages\n"
161 , amount, pageSize);
162
164 uint64_t logic_page_addr = address / pageSize;
165 uint32_t plane_address = 0;
166
174 for (uint32_t count = 0; amount > (count * pageSize); count++) {
175 uint32_t index = (locationTable[logic_page_addr].block *
176 pagesPerBlock) + (logic_page_addr % pagesPerBlock);
177
178 DPRINTF(FlashDevice, "Index 0x%8x, Block 0x%8x, pages/block %d,"
179 " logic address 0x%8x\n", index,
180 locationTable[logic_page_addr].block, pagesPerBlock,
181 logic_page_addr);
182 DPRINTF(FlashDevice, "Page %d; %d bytes up to this point\n", count,
183 (count * pageSize));
184
185 plane_address = locationTable[logic_page_addr].block & planeMask;
186
187 if (action == ActionRead) {
188 //lookup
189 //call accessTimes
190 time[plane_address] += accessTimes(locationTable[logic_page_addr]
191 .block, ActionRead);
192
193 /*stats*/
194 stats.readAccess.sample(logic_page_addr);
195 stats.readLatency.sample(time[plane_address]);
196 } else { //write
197 //lookup
198 //call accessTimes if appropriate, page may be unknown, so lets
199 //give it the benefit of the doubt
200
202 time[plane_address] += accessTimes
203 (locationTable[logic_page_addr].block, ActionWrite);
204
205 else //A remap is needed
206 time[plane_address] += remap(logic_page_addr);
207
208 /*stats*/
209 stats.writeAccess.sample(logic_page_addr);
210 stats.writeLatency.sample(time[plane_address]);
211 }
212
220 if (getUnknownPages(index)) {
222 --blockEmptyEntries[locationTable[logic_page_addr].block];
223 ++blockValidEntries[locationTable[logic_page_addr].block];
224 }
225
226 stats.fileSystemAccess.sample(address);
227 ++logic_page_addr;
228 }
229
234 for (uint32_t count = 0; count < numPlanes; count++){
235 plane_address = (time[plane_address] > time[count]) ? plane_address
236 : count;
237
238 DPRINTF(FlashDevice, "Plane %d is busy for %d ticks\n", count,
239 time[count]);
240
241 if (time[count] != 0) {
242
243 struct CallBackEntry cbe;
250 if (planeEventQueue[count].empty())
251 cbe.time = time[count] + curTick();
252 else
253 cbe.time = time[count] +
254 planeEventQueue[count].back().time;
255 planeEventQueue[count].push_back(cbe);
256
257 DPRINTF(FlashDevice, "scheduled at: %ld\n", cbe.time);
258
259 if (!planeEvent.scheduled())
261 else if (planeEventQueue[count].back().time < planeEvent.when())
263 planeEventQueue[plane_address].back().time, true);
264 }
265 }
266
267 //worst case two plane finish at the same time, each triggers an event
268 //and this callback will be called once. Maybe before the other plane
269 //could execute its event, but in the same tick.
270 planeEventQueue[plane_address].back().function = event;
271 DPRINTF(FlashDevice, "Callback queued for plane %d; %d in queue\n",
272 plane_address, planeEventQueue[plane_address].size());
273 DPRINTF(FlashDevice, "first event @ %d\n", planeEvent.when());
274}
275
280
281void
283{
284 DPRINTF(FlashDevice, "Plane action completed\n");
285 uint8_t plane_address = 0;
286
287 uint8_t next_event = 0;
288
290 for (plane_address = 0; plane_address < numPlanes; plane_address++) {
291 if (!planeEventQueue[plane_address].empty()) {
296 assert(planeEventQueue[plane_address].front().time >= curTick());
297
298 if (planeEventQueue[plane_address].front().time == curTick()) {
304 auto temp = planeEventQueue[plane_address].front().function;
305 planeEventQueue[plane_address].pop_front();
306
308 if (temp) {
309 DPRINTF(FlashDevice, "Callback, %d\n", plane_address);
310 temp();
311 }
312 }
313 }
314 }
315
317 for (plane_address = 0; plane_address < numPlanes; plane_address++) {
318 if (!planeEventQueue[plane_address].empty())
319 if (planeEventQueue[next_event].empty() ||
320 (planeEventQueue[plane_address].front().time <
321 planeEventQueue[next_event].front().time))
322 next_event = plane_address;
323 }
324
326 if (!planeEventQueue[next_event].empty()) {
327 DPRINTF(FlashDevice, "Schedule plane: %d\n", plane_address);
328 reschedule(planeEvent, planeEventQueue[next_event].front().time, true);
329 }
330
331 checkDrain();
332
333 DPRINTF(FlashDevice, "returing from flash event\n");
334 DPRINTF(FlashDevice, "first event @ %d\n", planeEvent.when());
335}
336
342Tick
343FlashDevice::remap(uint64_t logic_page_addr)
344{
348 if (blockEmptyEntries[locationTable[logic_page_addr].block] > 0) {
349 //just a remap
350 //update tables
351 --blockEmptyEntries[locationTable[logic_page_addr].block];
352 //access to this table won't be sequential anymore
353 locationTable[logic_page_addr].page = pagesPerBlock + 2;
354 //access new block
355 Tick time = accessTimes(locationTable[logic_page_addr].block,
357
358 DPRINTF(FlashDevice, "Remap returns %d ticks\n", time);
359 return time;
360
361 } else {
362 //calculate how much time GC would have taken
363 uint32_t block = locationTable[logic_page_addr].block;
364 Tick time = ((GCActivePercentage *
365 (accessTimes(block, ActionCopy) +
366 accessTimes(block, ActionErase)))
367 / 100);
368
369 //use block as the logical start address of the block
370 block = locationTable[logic_page_addr].block * pagesPerBlock;
371
372 //assumption: clean will improve locality
373 for (uint32_t count = 0; count < pagesPerBlock; count++) {
374 assert(block + count < pagesPerDisk);
375 locationTable[block + count].page = (block + count) %
377 }
378
379 blockEmptyEntries[locationTable[logic_page_addr].block] =
381 /*stats*/
382 ++stats.totalGCActivations;
383
384 DPRINTF(FlashDevice, "Remap with erase action returns %d ticks\n",
385 time);
386
387 return time;
388 }
389
390}
391
395Tick
396FlashDevice::accessTimes(uint64_t block, Actions action)
397{
398 Tick time = 0;
399
400 switch(action) {
401 case ActionRead: {
403 time = readLatency;
404 } break;
405
406 case ActionWrite: {
408 time = writeLatency + readLatency;
409 } break;
410
411 case ActionErase: {
413 time = eraseLatency + readLatency;
414 } break;
415
416 case ActionCopy: {
418 uint32_t validpages = blockValidEntries[block];
419 time = validpages * (readLatency + writeLatency);
420 } break;
421
422 default: break;
423 }
424
425 //Used to determine sequential action.
426 DPRINTF(FlashDevice, "Access returns %d ticks\n", time);
427 return time;
428}
429
443
444inline
445void
447{
448 unknownPages[index >> 5] &= ~(0x01 << (index % 32));
449}
450
454
455inline
456bool
458{
459 return unknownPages[index >> 5] & (0x01 << (index % 32));
460}
461
463 : statistics::Group(parent, "FlashDevice"),
465 "Number of Garbage collector activations"),
466 ADD_STAT(writeAccess, statistics::units::Count::get(),
467 "Histogram of write addresses"),
468 ADD_STAT(readAccess, statistics::units::Count::get(),
469 "Histogram of read addresses"),
471 "Histogram of file system accesses"),
473 "Histogram of write latency"),
475 "Histogram of read latency")
476{
477 using namespace statistics;
478
481 .flags(none);
482
485 .init(2)
486 .flags(pdf);
488 .init(2)
489 .flags(pdf);
491 .init(100)
492 .flags(pdf);
493
496 .init(100)
497 .flags(pdf);
499 .init(100)
500 .flags(pdf);
501}
502
506
507void
509{
511
515
516 int location_table_size = locationTable.size();
517 SERIALIZE_SCALAR(location_table_size);
518 for (uint32_t count = 0; count < location_table_size; count++) {
519 paramOut(cp, csprintf("locationTable[%d].page", count),
520 locationTable[count].page);
521 paramOut(cp, csprintf("locationTable[%d].block", count),
522 locationTable[count].block);
523 }
524};
525
529
530void
532{
534
538
539 int location_table_size;
540 UNSERIALIZE_SCALAR(location_table_size);
541 locationTable.resize(location_table_size);
542 for (uint32_t count = 0; count < location_table_size; count++) {
543 paramIn(cp, csprintf("locationTable[%d].page", count),
544 locationTable[count].page);
545 paramIn(cp, csprintf("locationTable[%d].block", count),
546 locationTable[count].block);
547 }
548};
549
553
556{
557 if (planeEvent.scheduled()) {
558 DPRINTF(Drain, "Flash device is draining...\n");
560 } else {
561 DPRINTF(Drain, "Flash device in drained state\n");
562 return DrainState::Drained;
563 }
564}
565
569
570void
572{
574 return;
575
576 if (planeEvent.when() > curTick()) {
577 DPRINTF(Drain, "Flash device is still draining\n");
578 } else {
579 DPRINTF(Drain, "Flash device is done draining\n");
581 }
582}
583
584} // namespace gem5
#define DPRINTF(x,...)
Definition trace.hh:209
AbstractNVM(const AbstractNVMParams &p)
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.
Statistics container.
Definition group.hh:93
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:310
DrainState drainState() const
Return the current drain state of an object.
Definition drain.hh:329
DrainState
Object drain/handover states.
Definition drain.hh:76
@ Draining
Draining buffers pending serialization/handover.
Definition drain.hh:78
@ Drained
Buffers drained, ready for serialization/handover.
Definition drain.hh:79
void schedule(Event &event, Tick when)
Definition eventq.hh:1012
void reschedule(Event &event, Tick when, bool always=false)
Definition eventq.hh:1030
#define fatal(...)
This implements a cprintf based fatal() function.
Definition logging.hh:232
#define UNSERIALIZE_CONTAINER(member)
Definition serialize.hh:651
#define SERIALIZE_CONTAINER(member)
Definition serialize.hh:643
Bitfield< 10, 5 > event
Bitfield< 30, 0 > index
Bitfield< 0 > p
int amount
Definition qarma.hh:70
Units for Stats.
Definition units.hh:113
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 Arm Limited 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 Mon Oct 27 2025 04:13:01 for gem5 by doxygen 1.14.0