forked from MatiasBjorling/flashsim
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathssd.h
1097 lines (928 loc) · 31 KB
/
ssd.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/* Copyright 2009, 2010 Brendan Tauras */
/* ssd.h is part of FlashSim. */
/* FlashSim is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version. */
/* FlashSim is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details. */
/* You should have received a copy of the GNU General Public License
* along with FlashSim. If not, see <http://www.gnu.org/licenses/>. */
/****************************************************************************/
/* ssd.h
* Brendan Tauras 2010-07-16
* Main SSD header file
* Lists definitions of all classes, structures,
* typedefs, and constants used in ssd namespace
* Controls options, such as debug asserts and test code insertions
*/
#include <stdlib.h>
#include <stdio.h>
#include <vector>
#include <queue>
#include <map>
#include <boost/multi_index_container.hpp>
#include <boost/multi_index/identity.hpp>
#include <boost/multi_index/ordered_index.hpp>
#include <boost/multi_index/member.hpp>
#include <boost/multi_index/global_fun.hpp>
#include <boost/multi_index/random_access_index.hpp>
#ifndef _SSD_H
#define _SSD_H
namespace ssd {
/* define exit codes for errors */
#define MEM_ERR -1
#define FILE_ERR -2
/* Uncomment to disable asserts for production */
#define NDEBUG
/* some obvious typedefs for laziness */
typedef unsigned int uint;
typedef unsigned long ulong;
/* Simulator configuration from ssd_config.cpp */
/* Configuration file parsing for extern config variables defined below */
void load_entry(char *name, double value, uint line_number);
void load_config(void);
void print_config(FILE *stream);
/* Ram class:
* delay to read from and write to the RAM for 1 page of data */
extern const double RAM_READ_DELAY;
extern const double RAM_WRITE_DELAY;
/* Bus class:
* delay to communicate over bus
* max number of connected devices allowed
* flag value to detect free table entry (keep this negative)
* number of time entries bus has to keep track of future schedule usage
* number of simultaneous communication channels - defined by SSD_SIZE */
extern const double BUS_CTRL_DELAY;
extern const double BUS_DATA_DELAY;
extern const uint BUS_MAX_CONNECT;
extern const double BUS_CHANNEL_FREE_FLAG;
extern const uint BUS_TABLE_SIZE;
/* extern const uint BUS_CHANNELS = 4; same as # of Packages, defined by SSD_SIZE */
/* Ssd class:
* number of Packages per Ssd (size) */
extern const uint SSD_SIZE;
/* Package class:
* number of Dies per Package (size) */
extern const uint PACKAGE_SIZE;
/* Die class:
* number of Planes per Die (size) */
extern const uint DIE_SIZE;
/* Plane class:
* number of Blocks per Plane (size)
* delay for reading from plane register
* delay for writing to plane register
* delay for merging is based on read, write, reg_read, reg_write
* and does not need to be explicitly defined */
extern const uint PLANE_SIZE;
extern const double PLANE_REG_READ_DELAY;
extern const double PLANE_REG_WRITE_DELAY;
/* Block class:
* number of Pages per Block (size)
* number of erases in lifetime of block
* delay for erasing block */
extern const uint BLOCK_SIZE;
extern const uint BLOCK_ERASES;
extern const double BLOCK_ERASE_DELAY;
/* Page class:
* delay for Page reads
* delay for Page writes */
extern const double PAGE_READ_DELAY;
extern const double PAGE_WRITE_DELAY;
extern const uint PAGE_SIZE;
extern const bool PAGE_ENABLE_DATA;
/*
* Mapping directory
*/
extern const uint MAP_DIRECTORY_SIZE;
/*
* FTL Implementation
*/
extern const uint FTL_IMPLEMENTATION;
/*
* LOG page limit for BAST.
*/
extern const uint BAST_LOG_PAGE_LIMIT;
/*
* LOG page limit for FAST.
*/
extern const uint FAST_LOG_PAGE_LIMIT;
/*
* Number of blocks allowed to be in DFTL Cached Mapping Table.
*/
extern const uint CACHE_DFTL_LIMIT;
/*
* Parallelism mode
*/
extern const uint PARALLELISM_MODE;
/* Virtual block size (as a multiple of the physical block size) */
extern const uint VIRTUAL_BLOCK_SIZE;
/* Virtual page size (as a multiple of the physical page size) */
extern const uint VIRTUAL_PAGE_SIZE;
extern const uint NUMBER_OF_ADDRESSABLE_BLOCKS;
/* RAISSDs: Number of physical SSDs */
extern const uint RAID_NUMBER_OF_PHYSICAL_SSDS;
/*
* Memory area to support pages with data.
*/
extern void *page_data;
extern void *global_buffer;
/* Enumerations to clarify status integers in simulation
* Do not use typedefs on enums for reader clarity */
/* Page states
* empty - page ready for writing (and contains no valid data)
* valid - page has been written to and contains valid data
* invalid - page has been written to and does not contain valid data */
enum page_state{EMPTY, VALID, INVALID};
/* Block states
* free - all pages in block are empty
* active - some pages in block are valid, others are empty or invalid
* inactive - all pages in block are invalid */
enum block_state{FREE, ACTIVE, INACTIVE};
/* I/O request event types
* read - read data from address
* write - write data to address (page state set to valid)
* erase - erase block at address (all pages in block are erased -
* page states set to empty)
* merge - move valid pages from block at address (page state set to invalid)
* to free pages in block at merge_address */
enum event_type{READ, WRITE, ERASE, MERGE, TRIM};
/* General return status
* return status for simulator operations that only need to provide general
* failure notifications */
enum status{FAILURE, SUCCESS};
/* Address valid status
* used for the valid field in the address class
* example: if valid == BLOCK, then
* the package, die, plane, and block fields are valid
* the page field is not valid */
enum address_valid{NONE, PACKAGE, DIE, PLANE, BLOCK, PAGE};
/*
* Block type status
* used for the garbage collector specify what pool
* it should work with.
* the block types are log, data and map (Directory map usually)
*/
enum block_type {LOG, DATA, LOG_SEQ};
/*
* Enumeration of the different FTL implementations.
*/
enum ftl_implementation {IMPL_PAGE, IMPL_BAST, IMPL_FAST, IMPL_DFTL, IMPL_BIMODAL};
#define BOOST_MULTI_INDEX_ENABLE_SAFE_MODE 1
/* List classes up front for classes that have references to their "parent"
* (e.g. a Package's parent is a Ssd).
*
* The order of definition below follows the order of this list to support
* cases of agregation where the agregate class should be defined first.
* Defining the agregate class first enables use of its non-default
* constructors that accept args
* (e.g. a Ssd contains a Controller, Ram, Bus, and Packages). */
class Address;
class Stats;
class Event;
class Channel;
class Bus;
class Page;
class Block;
class Plane;
class Die;
class Package;
class Garbage_Collector;
class Wear_Leveler;
class Block_manager;
class FtlParent;
class FtlImpl_Page;
class FtlImpl_Bast;
class FtlImpl_Fast;
class FtlImpl_DftlParent;
class FtlImpl_Dftl;
class FtlImpl_BDftl;
class Ram;
class Controller;
class Ssd;
/* Class to manage physical addresses for the SSD. It was designed to have
* public members like a struct for quick access but also have checking,
* printing, and assignment functionality. An instance is created for each
* physical address in the Event class. */
class Address
{
public:
uint package;
uint die;
uint plane;
uint block;
uint page;
ulong real_address;
enum address_valid valid;
Address(void);
Address(const Address &address);
Address(const Address *address);
Address(uint package, uint die, uint plane, uint block, uint page, enum address_valid valid);
Address(uint address, enum address_valid valid);
~Address();
enum address_valid check_valid(uint ssd_size = SSD_SIZE, uint package_size = PACKAGE_SIZE, uint die_size = DIE_SIZE, uint plane_size = PLANE_SIZE, uint block_size = BLOCK_SIZE);
enum address_valid compare(const Address &address) const;
void print(FILE *stream = stdout);
void operator+(int);
void operator+(uint);
Address &operator+=(const uint rhs);
Address &operator=(const Address &rhs);
void set_linear_address(ulong address, enum address_valid valid);
void set_linear_address(ulong address);
ulong get_linear_address() const;
};
class Stats
{
public:
// Flash Translation Layer
long numFTLRead;
long numFTLWrite;
long numFTLErase;
long numFTLTrim;
// Garbage Collection
long numGCRead;
long numGCWrite;
long numGCErase;
// Wear-leveling
long numWLRead;
long numWLWrite;
long numWLErase;
// Log based FTL's
long numLogMergeSwitch;
long numLogMergePartial;
long numLogMergeFull;
// Page based FTL's
long numPageBlockToPageConversion;
// Cache based FTL's
long numCacheHits;
long numCacheFaults;
// Memory consumptions (Bytes)
long numMemoryTranslation;
long numMemoryCache;
long numMemoryRead;
long numMemoryWrite;
// Advance statictics
double translation_overhead() const;
double variance_of_io() const;
double cache_hit_ratio() const;
// Constructors, maintainance, output, etc.
Stats(void);
void print_statistics();
void reset_statistics();
void write_statistics(FILE *stream);
void write_header(FILE *stream);
private:
void reset();
};
/* Class to emulate a log block with page-level mapping. */
class LogPageBlock
{
public:
LogPageBlock(void);
~LogPageBlock(void);
int *pages;
long *aPages;
Address address;
int numPages;
LogPageBlock *next;
bool operator() (const ssd::LogPageBlock& lhs, const ssd::LogPageBlock& rhs) const;
bool operator() (const ssd::LogPageBlock*& lhs, const ssd::LogPageBlock*& rhs) const;
};
/* Class to manage I/O requests as events for the SSD. It was designed to keep
* track of an I/O request by storing its type, addressing, and timing. The
* SSD class creates an instance for each I/O request it receives. */
class Event
{
public:
Event(enum event_type type, ulong logical_address, uint size, double start_time);
~Event(void);
void consolidate_metaevent(Event &list);
ulong get_logical_address(void) const;
const Address &get_address(void) const;
const Address &get_merge_address(void) const;
const Address &get_log_address(void) const;
const Address &get_replace_address(void) const;
uint get_size(void) const;
enum event_type get_event_type(void) const;
double get_start_time(void) const;
double get_time_taken(void) const;
double get_bus_wait_time(void) const;
bool get_noop(void) const;
Event *get_next(void) const;
void set_address(const Address &address);
void set_merge_address(const Address &address);
void set_log_address(const Address &address);
void set_replace_address(const Address &address);
void set_next(Event &next);
void set_payload(void *payload);
void set_event_type(const enum event_type &type);
void set_noop(bool value);
void *get_payload(void) const;
double incr_bus_wait_time(double time);
double incr_time_taken(double time_incr);
void print(FILE *stream = stdout);
private:
double start_time;
double time_taken;
double bus_wait_time;
enum event_type type;
ulong logical_address;
Address address;
Address merge_address;
Address log_address;
Address replace_address;
uint size;
void *payload;
Event *next;
bool noop;
};
/* Single bus channel
* Simulate multiple devices on 1 bus channel with variable bus transmission
* durations for data and control delays with the Channel class. Provide the
* delay times to send a control signal or 1 page of data across the bus
* channel, the bus table size for the maximum number channel transmissions that
* can be queued, and the maximum number of devices that can connect to the bus.
* To elaborate, the table size is the size of the channel scheduling table that
* holds start and finish times of events that have not yet completed in order
* to determine where the next event can be scheduled for bus utilization. */
class Channel
{
public:
Channel(double ctrl_delay = BUS_CTRL_DELAY, double data_delay = BUS_DATA_DELAY, uint table_size = BUS_TABLE_SIZE, uint max_connections = BUS_MAX_CONNECT);
~Channel(void);
enum status lock(double start_time, double duration, Event &event);
enum status connect(void);
enum status disconnect(void);
double ready_time(void);
private:
void unlock(double current_time);
struct lock_times {
double lock_time;
double unlock_time;
};
static bool timings_sorter(lock_times const& lhs, lock_times const& rhs);
std::vector<lock_times> timings;
uint table_entries;
uint selected_entry;
uint num_connected;
uint max_connections;
double ctrl_delay;
double data_delay;
// Stores the highest unlock_time in the vector timings list.
double ready_at;
};
/* Multi-channel bus comprised of Channel class objects
* Simulates control and data delays by allowing variable channel lock
* durations. The sender (controller class) should specify the delay (control,
* data, or both) for events (i.e. read = ctrl, ctrl+data; write = ctrl+data;
* erase or merge = ctrl). The hardware enable signals are implicitly
* simulated by the sender locking the appropriate bus channel through the lock
* method, then sending to multiple devices by calling the appropriate method
* in the Package class. */
class Bus
{
public:
Bus(uint num_channels = SSD_SIZE, double ctrl_delay = BUS_CTRL_DELAY, double data_delay = BUS_DATA_DELAY, uint table_size = BUS_TABLE_SIZE, uint max_connections = BUS_MAX_CONNECT);
~Bus(void);
enum status lock(uint channel, double start_time, double duration, Event &event);
enum status connect(uint channel);
enum status disconnect(uint channel);
Channel &get_channel(uint channel);
double ready_time(uint channel);
private:
uint num_channels;
Channel * const channels;
};
/* The page is the lowest level data storage unit that is the size unit of
* requests (events). Pages maintain their state as events modify them. */
class Page
{
public:
Page(const Block &parent, double read_delay = PAGE_READ_DELAY, double write_delay = PAGE_WRITE_DELAY);
~Page(void);
enum status _read(Event &event);
enum status _write(Event &event);
const Block &get_parent(void) const;
enum page_state get_state(void) const;
void set_state(enum page_state state);
private:
enum page_state state;
const Block &parent;
double read_delay;
double write_delay;
};
/* The block is the data storage hardware unit where erases are implemented.
* Blocks maintain wear statistics for the FTL. */
class Block
{
public:
long physical_address;
uint pages_invalid;
Block(const Plane &parent, uint size = BLOCK_SIZE, ulong erases_remaining = BLOCK_ERASES, double erase_delay = BLOCK_ERASE_DELAY, long physical_address = 0);
~Block(void);
enum status read(Event &event);
enum status write(Event &event);
enum status replace(Event &event);
enum status _erase(Event &event);
const Plane &get_parent(void) const;
uint get_pages_valid(void) const;
uint get_pages_invalid(void) const;
enum block_state get_state(void) const;
enum page_state get_state(uint page) const;
enum page_state get_state(const Address &address) const;
double get_last_erase_time(void) const;
double get_modification_time(void) const;
ulong get_erases_remaining(void) const;
uint get_size(void) const;
enum status get_next_page(Address &address) const;
void invalidate_page(uint page);
long get_physical_address(void) const;
Block *get_pointer(void);
block_type get_block_type(void) const;
void set_block_type(block_type value);
private:
uint size;
Page * const data;
const Plane &parent;
uint pages_valid;
enum block_state state;
ulong erases_remaining;
double last_erase_time;
double erase_delay;
double modification_time;
block_type btype;
};
/* The plane is the data storage hardware unit that contains blocks.
* Plane-level merges are implemented in the plane. Planes maintain wear
* statistics for the FTL. */
class Plane
{
public:
Plane(const Die &parent, uint plane_size = PLANE_SIZE, double reg_read_delay = PLANE_REG_READ_DELAY, double reg_write_delay = PLANE_REG_WRITE_DELAY, long physical_address = 0);
~Plane(void);
enum status read(Event &event);
enum status write(Event &event);
enum status erase(Event &event);
enum status replace(Event &event);
enum status _merge(Event &event);
const Die &get_parent(void) const;
double get_last_erase_time(const Address &address) const;
ulong get_erases_remaining(const Address &address) const;
void get_least_worn(Address &address) const;
uint get_size(void) const;
enum page_state get_state(const Address &address) const;
enum block_state get_block_state(const Address &address) const;
void get_free_page(Address &address) const;
ssd::uint get_num_free(const Address &address) const;
ssd::uint get_num_valid(const Address &address) const;
ssd::uint get_num_invalid(const Address &address) const;
Block *get_block_pointer(const Address & address);
private:
void update_wear_stats(void);
enum status get_next_page(void);
uint size;
Block * const data;
const Die &parent;
uint least_worn;
ulong erases_remaining;
double last_erase_time;
double reg_read_delay;
double reg_write_delay;
Address next_page;
uint free_blocks;
};
/* The die is the data storage hardware unit that contains planes and is a flash
* chip. Dies maintain wear statistics for the FTL. */
class Die
{
public:
Die(const Package &parent, Channel &channel, uint die_size = DIE_SIZE, long physical_address = 0);
~Die(void);
enum status read(Event &event);
enum status write(Event &event);
enum status erase(Event &event);
enum status replace(Event &event);
enum status merge(Event &event);
enum status _merge(Event &event);
const Package &get_parent(void) const;
double get_last_erase_time(const Address &address) const;
ulong get_erases_remaining(const Address &address) const;
void get_least_worn(Address &address) const;
enum page_state get_state(const Address &address) const;
enum block_state get_block_state(const Address &address) const;
void get_free_page(Address &address) const;
ssd::uint get_num_free(const Address &address) const;
ssd::uint get_num_valid(const Address &address) const;
ssd::uint get_num_invalid(const Address &address) const;
Block *get_block_pointer(const Address & address);
private:
void update_wear_stats(const Address &address);
uint size;
Plane * const data;
const Package &parent;
Channel &channel;
uint least_worn;
ulong erases_remaining;
double last_erase_time;
};
/* The package is the highest level data storage hardware unit. While the
* package is a virtual component, events are passed through the package for
* organizational reasons, including helping to simplify maintaining wear
* statistics for the FTL. */
class Package
{
public:
Package (const Ssd &parent, Channel &channel, uint package_size = PACKAGE_SIZE, long physical_address = 0);
~Package ();
enum status read(Event &event);
enum status write(Event &event);
enum status erase(Event &event);
enum status replace(Event &event);
enum status merge(Event &event);
const Ssd &get_parent(void) const;
double get_last_erase_time (const Address &address) const;
ulong get_erases_remaining (const Address &address) const;
void get_least_worn (Address &address) const;
enum page_state get_state(const Address &address) const;
enum block_state get_block_state(const Address &address) const;
void get_free_page(Address &address) const;
ssd::uint get_num_free(const Address &address) const;
ssd::uint get_num_valid(const Address &address) const;
ssd::uint get_num_invalid(const Address &address) const;
Block *get_block_pointer(const Address & address);
private:
void update_wear_stats (const Address &address);
uint size;
Die * const data;
const Ssd &parent;
uint least_worn;
ulong erases_remaining;
double last_erase_time;
};
/* place-holder definitions for GC, WL, FTL, RAM, Controller
* please make sure to keep this order when you replace with your definitions */
class Garbage_collector
{
public:
Garbage_collector(FtlParent &ftl);
~Garbage_collector(void);
private:
void clean(Address &address);
};
class Wear_leveler
{
public:
Wear_leveler(FtlParent &FTL);
~Wear_leveler(void);
enum status insert(const Address &address);
};
class Block_manager
{
public:
Block_manager(FtlParent *ftl);
~Block_manager(void);
// Usual suspects
Address get_free_block(Event &event);
Address get_free_block(block_type btype, Event &event);
void invalidate(Address address, block_type btype);
void print_statistics();
void insert_events(Event &event);
void promote_block(block_type to_type);
bool is_log_full();
void erase_and_invalidate(Event &event, Address &address, block_type btype);
int get_num_free_blocks();
// Used to update GC on used pages in blocks.
void update_block(Block * b);
// Singleton
static Block_manager *instance();
static void instance_initialize(FtlParent *ftl);
static Block_manager *inst;
void cost_insert(Block *b);
void print_cost_status();
private:
void get_page_block(Address &address, Event &event);
static bool block_comparitor_simple (Block const *x,Block const *y);
FtlParent *ftl;
ulong data_active;
ulong log_active;
ulong logseq_active;
ulong max_log_blocks;
ulong max_blocks;
ulong max_map_pages;
ulong map_space_capacity;
// Cost/Benefit priority queue.
typedef boost::multi_index_container<
Block*,
boost::multi_index::indexed_by<
boost::multi_index::random_access<>,
boost::multi_index::ordered_non_unique<BOOST_MULTI_INDEX_MEMBER(Block,uint,pages_invalid) >
>
> active_set;
typedef active_set::nth_index<0>::type ActiveBySeq;
typedef active_set::nth_index<1>::type ActiveByCost;
active_set active_cost;
// Usual block lists
std::vector<Block*> active_list;
std::vector<Block*> free_list;
std::vector<Block*> invalid_list;
// Counter for returning the next free page.
ulong directoryCurrentPage;
// Address on the current cached page in SRAM.
ulong directoryCachedPage;
ulong simpleCurrentFree;
// Counter for handling periodic sort of active_list
uint num_insert_events;
uint current_writing_block;
bool inited;
bool out_of_blocks;
};
class FtlParent
{
public:
FtlParent(Controller &controller);
virtual ~FtlParent () {};
virtual enum status read(Event &event) = 0;
virtual enum status write(Event &event) = 0;
virtual enum status trim(Event &event) = 0;
virtual void cleanup_block(Event &event, Block *block);
virtual void print_ftl_statistics();
friend class Block_manager;
ulong get_erases_remaining(const Address &address) const;
void get_least_worn(Address &address) const;
enum page_state get_state(const Address &address) const;
enum block_state get_block_state(const Address &address) const;
Block *get_block_pointer(const Address & address);
Address resolve_logical_address(unsigned int logicalAddress);
protected:
Controller &controller;
};
class FtlImpl_Page : public FtlParent
{
public:
FtlImpl_Page(Controller &controller);
~FtlImpl_Page();
enum status read(Event &event);
enum status write(Event &event);
enum status trim(Event &event);
private:
ulong currentPage;
ulong numPagesActive;
bool *trim_map;
long *map;
};
class FtlImpl_Bast : public FtlParent
{
public:
FtlImpl_Bast(Controller &controller);
~FtlImpl_Bast();
enum status read(Event &event);
enum status write(Event &event);
enum status trim(Event &event);
private:
std::map<long, LogPageBlock*> log_map;
long *data_list;
void dispose_logblock(LogPageBlock *logBlock, long lba);
void allocate_new_logblock(LogPageBlock *logBlock, long lba, Event &event);
bool is_sequential(LogPageBlock* logBlock, long lba, Event &event);
bool random_merge(LogPageBlock *logBlock, long lba, Event &event);
void update_map_block(Event &event);
void print_ftl_statistics();
int addressShift;
int addressSize;
};
class FtlImpl_Fast : public FtlParent
{
public:
FtlImpl_Fast(Controller &controller);
~FtlImpl_Fast();
enum status read(Event &event);
enum status write(Event &event);
enum status trim(Event &event);
private:
void initialize_log_pages();
std::map<long, LogPageBlock*> log_map;
long *data_list;
bool *pin_list;
bool write_to_log_block(Event &event, long logicalBlockAddress);
void switch_sequential(Event &event);
void merge_sequential(Event &event);
bool random_merge(LogPageBlock *logBlock, Event &event);
void update_map_block(Event &event);
void print_ftl_statistics();
long sequential_logicalblock_address;
Address sequential_address;
uint sequential_offset;
uint log_page_next;
LogPageBlock *log_pages;
int addressShift;
int addressSize;
};
class FtlImpl_DftlParent : public FtlParent
{
public:
FtlImpl_DftlParent(Controller &controller);
~FtlImpl_DftlParent();
virtual enum status read(Event &event) = 0;
virtual enum status write(Event &event) = 0;
virtual enum status trim(Event &event) = 0;
protected:
struct MPage {
long vpn;
long ppn;
double create_ts;
double modified_ts;
bool cached;
MPage(long vpn);
};
long int cmt;
static double mpage_modified_ts_compare(const MPage& mpage);
typedef boost::multi_index_container<
FtlImpl_DftlParent::MPage,
boost::multi_index::indexed_by<
// sort by MPage::operator<
boost::multi_index::random_access<>,
// Sort by modified ts
boost::multi_index::ordered_non_unique<boost::multi_index::global_fun<const FtlImpl_DftlParent::MPage&,double,&FtlImpl_DftlParent::mpage_modified_ts_compare> >
>
> trans_set;
typedef trans_set::nth_index<0>::type MpageByID;
typedef trans_set::nth_index<1>::type MpageByModified;
trans_set trans_map;
long *reverse_trans_map;
void consult_GTD(long dppn, Event &event);
void reset_MPage(FtlImpl_DftlParent::MPage &mpage);
void resolve_mapping(Event &event, bool isWrite);
void update_translation_map(FtlImpl_DftlParent::MPage &mpage, long ppn);
bool lookup_CMT(long dlpn, Event &event);
long get_free_data_page(Event &event);
long get_free_data_page(Event &event, bool insert_events);
void evict_page_from_cache(Event &event);
void evict_specific_page_from_cache(Event &event, long lba);
// Mapping information
int addressPerPage;
int addressSize;
uint totalCMTentries;
// Current storage
long currentDataPage;
long currentTranslationPage;
};
class FtlImpl_Dftl : public FtlImpl_DftlParent
{
public:
FtlImpl_Dftl(Controller &controller);
~FtlImpl_Dftl();
enum status read(Event &event);
enum status write(Event &event);
enum status trim(Event &event);
void cleanup_block(Event &event, Block *block);
void print_ftl_statistics();
};
class FtlImpl_BDftl : public FtlImpl_DftlParent
{
public:
FtlImpl_BDftl(Controller &controller);
~FtlImpl_BDftl();
enum status read(Event &event);
enum status write(Event &event);
enum status trim(Event &event);
void cleanup_block(Event &event, Block *block);
private:
struct BPage {
uint pbn;
unsigned char nextPage;
bool optimal;
BPage();
};
BPage *block_map;
bool *trim_map;
std::queue<Block*> blockQueue;
Block* inuseBlock;
bool block_next_new();
long get_free_biftl_page(Event &event);
void print_ftl_statistics();
};
/* This is a basic implementation that only provides delay updates to events
* based on a delay value multiplied by the size (number of pages) needed to
* be written. */
class Ram
{
public:
Ram(double read_delay = RAM_READ_DELAY, double write_delay = RAM_WRITE_DELAY);
~Ram(void);
enum status read(Event &event);
enum status write(Event &event);
private:
double read_delay;
double write_delay;
};
/* The controller accepts read/write requests through its event_arrive method
* and consults the FTL regarding what to do by calling the FTL's read/write
* methods. The FTL returns an event list for the controller through its issue
* method that the controller buffers in RAM and sends across the bus. The
* controller's issue method passes the events from the FTL to the SSD.
*
* The controller also provides an interface for the FTL to collect wear
* information to perform wear-leveling. */
class Controller
{
public:
Controller(Ssd &parent);
~Controller(void);
enum status event_arrive(Event &event);
friend class FtlParent;
friend class FtlImpl_Page;
friend class FtlImpl_Bast;
friend class FtlImpl_Fast;
friend class FtlImpl_DftlParent;
friend class FtlImpl_Dftl;
friend class FtlImpl_BDftl;