-
Notifications
You must be signed in to change notification settings - Fork 54
/
ssd.h
1765 lines (1562 loc) · 61.6 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
/* ssd.h
* 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 <stack>
#include <queue>
#include <deque>
#include <map>
#include <unordered_map>
#include <unordered_set>
#include <set>
#include <algorithm>
#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>
#include <boost/serialization/vector.hpp>
#include <boost/serialization/set.hpp>
#include <boost/serialization/map.hpp>
#include <boost/serialization/deque.hpp>
#include <boost/serialization/utility.hpp>
#include <boost/serialization/base_object.hpp>
#include <sstream>
#include <initializer_list>
#include <boost/archive/xml_iarchive.hpp>
#include <boost/archive/xml_oarchive.hpp>
#include <iostream>
#include <boost/serialization/export.hpp>
/*#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>*/
#include "bloom_filter.hpp"
#include <sys/types.h>
//#include "mtrand.h" // Marsenne Twister random number generator
#include <fstream>
#include "block_management.h"
#include "scheduler.h"
#include "Operating_System.h"
#ifndef _SSD_H
#define _SSD_H
using namespace std;
namespace ssd {
/* define exit codes for errors */
#define MEM_ERR -1
#define FILE_ERR -2
/* Uncomment to disable asserts for production */
#define NDEBUG
/* 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(const char * const file_name);
void set_big_SSD_config();
void set_small_SSD_config();
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;
extern int OS_SCHEDULER;
/* 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 double BUS_CTRL_DELAY;
extern 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 uint SSD_SIZE;
/* Package class:
* number of Dies per Package (size) */
extern uint PACKAGE_SIZE;
/* Die class:
* number of Planes per Die (size) */
extern 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 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 uint BLOCK_SIZE;
extern const uint BLOCK_ERASES;
extern double BLOCK_ERASE_DELAY;
/* Page class:
* delay for Page reads
* delay for Page writes */
extern double PAGE_READ_DELAY;
extern double PAGE_WRITE_DELAY;
extern const uint PAGE_SIZE;
extern const bool PAGE_ENABLE_DATA;
// a 0-1 factor indicating the percentage of the logical address space out of the physical address space
extern double OVER_PROVISIONING_FACTOR;
/*
* Mapping directory
*/
extern const uint MAP_DIRECTORY_SIZE;
extern bool ALLOW_DEFERRING_TRANSFERS;
/*
* FTL Implementation
*/
extern const uint FTL_IMPLEMENTATION;
/* 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;
static inline uint NUMBER_OF_ADDRESSABLE_BLOCKS() {
return SSD_SIZE * PACKAGE_SIZE * DIE_SIZE * PLANE_SIZE;
}
static inline uint NUMBER_OF_ADDRESSABLE_PAGES() {
return SSD_SIZE * PACKAGE_SIZE * DIE_SIZE * PLANE_SIZE * BLOCK_SIZE;
}
/*
* Memory area to support pages with data.
*/
extern void *page_data;
extern void *global_buffer;
/*
* Controls the block manager to be used
*/
extern int BLOCK_MANAGER_ID;
extern int GARBAGE_COLLECTION_POLICY;
extern int GREED_SCALE;
extern int SEQUENTIAL_LOCALITY_THRESHOLD;
extern bool ENABLE_TAGGING;
extern int WRITE_DEADLINE;
extern int READ_DEADLINE;
extern int READ_TRANSFER_DEADLINE;
extern int FTL_DESIGN;
extern bool IS_FTL_PAGE_MAPPING;
extern int SRAM;
/*
* Controls the level of detail of output
*/
extern int PRINT_LEVEL;
extern bool PRINT_FILE_MANAGER_INFO;
/* Defines the max number of copy back operations on a page before ECC check is performed.
* Set to zero to disable copy back GC operations */
extern uint MAX_REPEATED_COPY_BACKS_ALLOWED;
/* Defines the max number of page addresses in map keeping track of each pages copy back count */
extern uint MAX_ITEMS_IN_COPY_BACK_MAP;
/* Defines the maximal length of the SSD queue */
extern int MAX_SSD_QUEUE_SIZE;
/* Defines how the sequential writes detection algorithm spreads a sequential write */
extern uint LOCALITY_PARALLEL_DEGREE;
extern bool USE_ERASE_QUEUE;
extern int SCHEDULING_SCHEME;
extern bool BALANCEING_SCHEME;
extern bool ENABLE_WEAR_LEVELING;
extern int WEAR_LEVEL_THRESHOLD;
extern int MAX_ONGOING_WL_OPS;
extern int MAX_CONCURRENT_GC_OPS;
extern int PAGE_HOTNESS_MEASURER;
/* 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, PARTIALLY_FREE, ACTIVE, INACTIVE};
/* I/O request event types
* read - read data from address. Performs both read_command and read_transfer. Kept here for legacy purposes
* read_command - the first part of a read with the command and actual read on the chip
* read_transfer - transfer read data back to the controller
* 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{NOT_VALID, READ, READ_COMMAND, READ_TRANSFER, WRITE, ERASE, MERGE, TRIM, GARBAGE_COLLECTION, COPY_BACK, MESSAGE};
/* 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};
/*
* Enumeration of page access patterns
*/
enum write_hotness {WRITE_HOT, WRITE_COLD};
enum read_hotness {READ_HOT, READ_COLD};
#define BOOST_MULTI_INDEX_ENABLE_SAFE_MODE 1
enum age {YOUNG, OLD};
/* 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 Flexible_Read_Event;
class Page;
class Block;
class Plane;
class Die;
class Package;
class FtlParent;
class FtlImpl_Page;
class DFTL;
class FAST;
class Ssd;
class event_queue;
class IOScheduler;
class Scheduling_Strategy;
class Block_manager_parent;
class Block_manager_parallel;
class Shortest_Queue_Hot_Cold_BM;
class Wearwolf;
class Sequential_Locality_BM;
class Wear_Leveling_Strategy;
class Garbage_Collector;
class flash_resident_ftl_garbage_collection;
class Migrator;
class Sequential_Pattern_Detector;
class Page_Hotness_Measurer;
class Random_Order_Iterator;
class OperatingSystem;
class Thread;
class Synchronous_Writer;
struct Address_Range;
class Flexible_Reader;
class MTRand_int32;
/* 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;
enum address_valid valid;
Address();
inline Address(const Address &address) { *this = address; }
inline Address(const Address *address) { *this = *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 compare(const Address &address) const;
void print(FILE *stream = stdout) const;
void set_linear_address(ulong address, enum address_valid valid);
void set_linear_address(ulong address);
ulong get_linear_address() const;
long get_block_id() const { return (get_linear_address() - page) / BLOCK_SIZE; }
inline Address& operator=(const Address &rhs)
{
if(this == &rhs)
return *this;
package = rhs.package;
die = rhs.die;
plane = rhs.plane;
block = rhs.block;
page = rhs.page;
valid = rhs.valid;
return *this;
}
bool operator<(const Address &rhs) const {
return this->get_linear_address() < rhs.get_linear_address();
}
friend class boost::serialization::access;
template<class Archive>
void serialize(Archive & ar, const unsigned int version)
{
ar & package;
ar & die;
ar & plane;
ar & block;
ar & page;
ar & valid;
}
};
/* Class to emulate a log block with page-level mapping. */
/*class LogPageBlock
{
public:
LogPageBlock();
~LogPageBlock();
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();
Event(Event const& event);
inline virtual ~Event() {}
inline ulong get_logical_address() const { return logical_address; }
inline void set_logical_address(ulong addr) { logical_address = addr; }
inline const Address &get_address() const { return address; }
inline const Address &get_replace_address() const { return replace_address; }
inline uint get_size() const { return size; }
inline void set_size(int new_size) { size = new_size; }
inline enum event_type get_event_type() const { return type; }
inline double get_start_time() const { assert(start_time >= 0.0); return start_time; }
inline bool is_original_application_io() const { return original_application_io; }
inline void set_original_application_io(bool val) { original_application_io = val; }
inline double get_execution_time() const { assert(execution_time >= 0.0); return execution_time; }
inline double get_accumulated_wait_time() const { assert(accumulated_wait_time >= 0.0); return accumulated_wait_time; }
inline double get_current_time() const { return start_time + os_wait_time + accumulated_wait_time + bus_wait_time + execution_time; }
inline double get_ssd_submission_time() const { return start_time + os_wait_time; }
inline uint get_application_io_id() const { return application_io_id; }
inline double get_bus_wait_time() const { assert(bus_wait_time >= 0.0); return bus_wait_time; }
inline double get_os_wait_time() const { return os_wait_time; }
inline bool get_noop() const { return noop; }
inline uint get_id() const { return id; }
inline int get_tag() const { return tag; }
inline void set_tag(int new_tag) { tag = new_tag; }
inline void set_thread_id(int new_thread_id) { thread_id = new_thread_id; }
inline void set_address(const Address &address) {
if (type == WRITE || type == READ || type == READ_COMMAND || type == READ_TRANSFER)
assert(address.valid == PAGE);
this -> address = address;
}
inline void set_start_time(double time) { start_time = time; }
inline void set_replace_address(const Address &address) { replace_address = address; }
inline void set_payload(void *payload) { this->payload = payload; }
inline void set_event_type(const enum event_type &type) { this->type = type; }
inline void set_noop(bool value) { noop = value; }
inline void set_application_io_id(uint value) { application_io_id = value; }
inline void set_garbage_collection_op(bool value) { garbage_collection_op = value; }
inline void set_mapping_op(bool value) { mapping_op = value; }
inline void set_age_class(int value) { age_class = value; }
inline void set_copyback(bool value) { copyback = value; }
inline void set_cached_write(bool value) { cached_write = value; }
inline bool is_cached_write() { return cached_write; }
inline int get_age_class() const { return age_class; }
inline bool is_garbage_collection_op() const { return garbage_collection_op; }
inline bool is_mapping_op() const { return mapping_op; }
inline void *get_payload() const { return payload; }
inline bool is_copyback() const { return copyback; }
inline void incr_bus_wait_time(double time_incr) { assert(time_incr >= 0); bus_wait_time += time_incr; incr_pure_ssd_wait_time(time_incr); }
inline void incr_pure_ssd_wait_time(double time_incr) { pure_ssd_wait_time += time_incr;}
inline void incr_os_wait_time(double time_incr) { os_wait_time += time_incr; }
inline void incr_execution_time(double time_incr) { execution_time += time_incr; incr_pure_ssd_wait_time(time_incr); }
inline void incr_accumulated_wait_time(double time_incr) { accumulated_wait_time += time_incr; }
inline double get_overall_wait_time() const { return accumulated_wait_time + bus_wait_time; }
inline double get_latency() const { return pure_ssd_wait_time; }
inline bool is_wear_leveling_op() const { return wear_leveling_op ; }
inline void set_wear_leveling_op(bool value) { wear_leveling_op = value; }
void print(FILE *stream = stdout) const;
static void reset_id_generators();
bool is_flexible_read();
inline void increment_iteration_count() { num_iterations_in_scheduler++; }
inline int get_iteration_count() { return num_iterations_in_scheduler; }
inline int get_ssd_id() { return ssd_id; }
inline void set_ssd_id(int new_ssd_id) { ssd_id = new_ssd_id; }
protected:
long double start_time;
double execution_time;
double bus_wait_time;
double os_wait_time;
enum event_type type;
double accumulated_wait_time;
ulong logical_address;
Address address;
Address replace_address;
uint size;
void *payload;
bool noop;
bool garbage_collection_op;
bool wear_leveling_op;
bool mapping_op;
bool original_application_io;
bool copyback;
bool cached_write;
// an ID for a single IO to the chip. This is not actually used for any logical purpose
static uint id_generator;
uint id;
// an ID to manage dependencies in the scheduler.
uint application_io_id;
static uint application_io_id_generator;
uint ssd_id;
int age_class;
int tag;
int thread_id;
double pure_ssd_wait_time;
int num_iterations_in_scheduler;
};
class Message : public Event {
public:
Message(double time) : Event(MESSAGE, 0, 1, time) {}
};
/* 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:
inline Page() : state(EMPTY), logical_addr(-1) {}
inline ~Page() {}
enum status _read(Event &event);
enum status _write(Event &event);
inline enum page_state get_state() const { return state; }
inline void set_state(page_state val) { state = val; }
friend class boost::serialization::access;
template<class Archive>
void serialize(Archive & ar, const unsigned int version)
{
ar & state;
}
void set_logical_addr(int l) { logical_addr = l;}
int get_logical_addr() const { return logical_addr; }
private:
enum page_state state;
int logical_addr;
};
/* The block is the data storage hardware unit where erases are implemented.
* Blocks maintain wear statistics for the FTL. */
class Block
{
public:
Block(long physical_address);
Block();
~Block() {}
enum status read(Event &event);
enum status write(Event &event);
enum status _erase(Event &event);
inline uint get_pages_valid() const { return pages_valid; }
inline uint get_pages_invalid() const { return pages_invalid; }
inline enum block_state get_state() const {
return pages_invalid == BLOCK_SIZE ? INACTIVE :
pages_valid == BLOCK_SIZE ? ACTIVE :
pages_invalid + pages_valid == BLOCK_SIZE ? ACTIVE : PARTIALLY_FREE;
}
inline ulong get_erases_remaining() const { return erases_remaining; }
void invalidate_page(uint page);
inline long get_physical_address() const { return physical_address; }
inline Block *get_pointer() { return this; }
inline Page const& get_page(int i) const { return data[i]; }
inline ulong get_age() const { return BLOCK_ERASES - erases_remaining; }
friend class boost::serialization::access;
template<class Archive>
void serialize(Archive & ar, const unsigned int version)
{
ar & pages_invalid;
ar & physical_address;
ar & data;
ar & pages_valid;
ar & erases_remaining;
}
private:
uint pages_invalid;
long physical_address;
vector<Page> data;
uint pages_valid;
ulong erases_remaining;
};
/* The plane is the data storage hardware unit that contains blocks.*/
class Plane
{
public:
Plane(long physical_address);
Plane();
~Plane() {}
enum status read(Event &event);
enum status write(Event &event);
enum status erase(Event &event);
inline Block *get_block(int i) { return &data[i]; }
friend class boost::serialization::access;
template<class Archive>
void serialize(Archive & ar, const unsigned int version)
{
ar & data;
}
private:
vector<Block> data;
};
/* 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(long physical_address);
Die();
~Die() {}
enum status read(Event &event);
enum status write(Event &event);
enum status erase(Event &event);
double get_currently_executing_io_finish_time();
inline Plane *get_plane(int i) { return &data[i]; }
void clear_register();
int get_last_read_application_io();
bool register_is_busy();
friend class boost::serialization::access;
template<class Archive>
void serialize(Archive & ar, const unsigned int version)
{
ar & data;
}
private:
vector<Plane> data;
double currently_executing_io_finish_time;
int last_read_io;
};
/* 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 (long physical_address);
Package();
~Package () {}
enum status read(Event &event);
enum status write(Event &event);
enum status erase(Event &event);
inline Die *get_die(int i) { return &data[i]; }
enum status lock(double start_time, double duration, Event &event);
inline double get_currently_executing_operation_finish_time() { return currently_executing_operation_finish_time; }
friend class boost::serialization::access;
template<class Archive>
void serialize(Archive & ar, const unsigned int version)
{
ar & data;
}
private:
vector<Die> data;
double currently_executing_operation_finish_time;
};
extern const int UNDEFINED;
extern const int INFINITE;
class Page_Hotness_Measurer {
public:
// virtual Page_Hotness_Measurer() = 0;
virtual ~Page_Hotness_Measurer() {};
virtual void register_event(Event const& event) = 0; // Inform hotness measurer about a read or write event
virtual enum write_hotness get_write_hotness(unsigned long page_address) const = 0; // Return write hotness of a given page address
virtual enum read_hotness get_read_hotness(unsigned long page_address) const = 0; // Return read hotness of a given page address
virtual Address get_best_target_die_for_WC(enum read_hotness rh) const = 0; // Return address of die with leads WC data (with chosen read hotness)
};
class Ignorant_Hotness_Measurer : public Page_Hotness_Measurer {
public:
// virtual Page_Hotness_Measurer() = 0;
Ignorant_Hotness_Measurer() {};
~Ignorant_Hotness_Measurer() {};
void register_event(Event const& event) {};
enum write_hotness get_write_hotness(unsigned long page_address) const { return WRITE_HOT; }
enum read_hotness get_read_hotness(unsigned long page_address) const { return READ_HOT; }
Address get_best_target_die_for_WC(enum read_hotness rh) const { return Address(); }
};
// Simple (naïve page hotness measurer implementation)
class Simple_Page_Hotness_Measurer : public Page_Hotness_Measurer {
public:
Simple_Page_Hotness_Measurer();
~Simple_Page_Hotness_Measurer();
void register_event(Event const& event);
enum write_hotness get_write_hotness(unsigned long page_address) const;
enum read_hotness get_read_hotness(unsigned long page_address) const;
Address get_best_target_die_for_WC(enum read_hotness rh) const;
private:
void start_new_interval_writes();
void start_new_interval_reads();
map<ulong, uint> write_current_count;
vector<double> write_moving_average;
map<ulong, uint> read_current_count;
vector<double> read_moving_average;
uint current_interval;
double average_write_hotness;
double average_read_hotness;
vector<vector<uint> > writes_per_die;
vector<vector<uint> > reads_per_die;
vector<vector<double> > average_reads_per_die;
vector<vector<uint> > current_reads_per_die;
uint writes_counter;
uint reads_counter;
const uint WINDOW_LENGTH;
const uint KICK_START;
};
// BloomFilter hotness
typedef vector< bloom_filter > hot_bloom_filter;
typedef vector< vector<uint> > lun_counters;
class Die_Stats {
public:
Die_Stats(bloom_parameters bloomfilter_parameters, uint read_window_size, uint write_window_size)
: live_pages(0),
reads(0),
reads_targeting_wc_pages(0),
reads_targeting_wc_pages_previous_window(UNDEFINED),
writes(0),
unique_wh_encountered(0),
unique_wh_encountered_previous_window(UNDEFINED),
wh_counted_already(bloomfilter_parameters),
read_counter_window_size(read_window_size),
write_counter_window_size(write_window_size)
{}
Die_Stats(const Die_Stats& object)
: live_pages(object.live_pages),
reads(object.reads),
reads_targeting_wc_pages(object.reads_targeting_wc_pages),
reads_targeting_wc_pages_previous_window(object.reads_targeting_wc_pages_previous_window),
writes(object.writes),
unique_wh_encountered(object.unique_wh_encountered),
unique_wh_encountered_previous_window(object.unique_wh_encountered_previous_window),
read_counter_window_size(object.read_counter_window_size),
write_counter_window_size(object.write_counter_window_size)
{
wh_counted_already = object.wh_counted_already;
}
// WC = live pages - WH
inline uint get_wc_pages() const {
int unique_wh = unique_wh_encountered_previous_window == UNDEFINED ? unique_wh_encountered : unique_wh_encountered;
int diff = live_pages - unique_wh;
assert(diff >= 0);
return diff;
}
inline uint get_reads_targeting_wc_pages() const {
if (reads_targeting_wc_pages_previous_window != UNDEFINED) return reads_targeting_wc_pages_previous_window;
if (reads == 0) return 0;
return (uint) reads_targeting_wc_pages * ((double) read_counter_window_size / reads); // Compensate for a partially completed 1st window
}
void print() const {
printf("live |\tr\tr->wc\tr>wc(l)\tw\tuq_wh\tuq_wh(l)\n");
printf("%u\t%u\t%u\t%d\t%u\t%d\t%d\t\n", live_pages, reads, reads_targeting_wc_pages, reads_targeting_wc_pages_previous_window,
writes, unique_wh_encountered, unique_wh_encountered_previous_window);
}
uint live_pages;
uint reads;
uint reads_targeting_wc_pages;
int reads_targeting_wc_pages_previous_window;
uint writes;
int unique_wh_encountered;
int unique_wh_encountered_previous_window;
bloom_filter wh_counted_already;
uint read_counter_window_size;
uint write_counter_window_size;
};
class BloomFilter_Page_Hotness_Measurer : public Page_Hotness_Measurer {
friend class Die_Stats;
public:
BloomFilter_Page_Hotness_Measurer(uint num_bloom_filters = 4, uint bloom_filter_size = 2048, uint IOs_before_decay = 512, bool preheat = true);
~BloomFilter_Page_Hotness_Measurer();
void register_event(Event const& event);
enum write_hotness get_write_hotness(unsigned long page_address) const;
enum read_hotness get_read_hotness(unsigned long page_address) const;
Address get_best_target_die_for_WC(enum read_hotness rh) const;
void heat_all_addresses();
// Debug output
void print_die_stats() const;
private:
double get_hot_data_index(event_type type, unsigned long page_address) const;
inline double get_max_hot_data_index_value() { return num_bloom_filters + 1; } // == (2 / (double) V) * (V + 1) * (V / 2)
// Parameters
uint num_bloom_filters, bloom_filter_size, IOs_before_decay;
uint hotness_threshold, read_counter_window_size, write_counter_window_size;
// Bookkeeping variables
uint read_oldest_BF, write_oldest_BF;
uint read_counter, write_counter;
hot_bloom_filter read_bloom;
hot_bloom_filter write_bloom;
vector< vector<Die_Stats> > package_die_stats;
// vector< map<int, bool> > ReadErrorFreeCounter;
// vector< map<int, bool> > WriteErrorFreeCounter;
};
class Random_Order_Iterator {
public:
static vector<int> get_iterator(int needed_length);
private:
Random_Order_Iterator() {}
static void shuffle(vector<int>&);
static MTRand_int32 random_number_generator;
};
class FtlParent
{
public:
FtlParent(Ssd *ssd, Block_manager_parent* bm);
FtlParent() : ssd(NULL), scheduler(NULL), bm(NULL), normal_stats("normal_stats", 50000) {};
virtual void set_scheduler(IOScheduler* sched) { scheduler = sched; }
virtual ~FtlParent ();
virtual void read(Event *event) = 0;
virtual void write(Event *event) = 0;
virtual void trim(Event *event) = 0;
virtual void register_write_completion(Event const& event, enum status result) = 0;
virtual void register_read_completion(Event const& event, enum status result) = 0;
virtual void register_trim_completion(Event & event) = 0;
virtual long get_logical_address(uint physical_address) const = 0;
virtual Address get_physical_address(uint logical_address) const = 0;
virtual void set_replace_address(Event& event) const = 0;
virtual void set_read_address(Event& event) const = 0;
virtual void register_erase_completion(Event & event) {};
virtual void print() const {};
void set_block_manager(Block_manager_parent* b) { bm = b; }
Block_manager_parent* get_block_manager() { return bm; }
friend class boost::serialization::access;
template<class Archive>
void serialize(Archive & ar, const unsigned int version)
{
ar & ssd;
ar & scheduler;
ar & bm;
}
protected:
Ssd *ssd;
IOScheduler *scheduler;
Block_manager_parent* bm;
void collect_stats(Event const& event);
struct stats {
stats(string name, long counter_limit);
string file_name;
long num_noop_reads_per_interval;
long num_noop_writes_per_interval;
long num_mapping_writes;
long num_mapping_reads;
long mapping_reads_per_interval;
long mapping_writes_per_interval;
long gc_reads_per_interval;
long gc_writes_per_interval;
long gc_mapping_writes_per_interval;
long gc_mapping_reads_per_interval;
long app_reads_per_interval;
long app_writes_per_interval;
long num_noop_reads;
long num_noop_writes;
long counter;
const long COUNTER_LIMIT;
void print() const;
void collect_stats(Event const& event);
};
stats normal_stats;
};
class FtlImpl_Page : public FtlParent
{
public:
FtlImpl_Page(Ssd *ssd, Block_manager_parent* bm);
FtlImpl_Page();
~FtlImpl_Page();
void read(Event *event);
void write(Event *event);
void trim(Event *event);
void register_write_completion(Event const& event, enum status result);
void register_read_completion(Event const& event, enum status result);
void register_trim_completion(Event & event);
long get_logical_address(uint physical_address) const;
Address get_physical_address(uint logical_address) const;
void set_replace_address(Event& event) const;
void set_read_address(Event& event) const;
friend class boost::serialization::access;
template<class Archive>
void serialize(Archive & ar, const unsigned int version)
{
ar & boost::serialization::base_object<FtlParent>(*this);
ar & logical_to_physical_map;
ar & physical_to_logical_map;
}
private:
vector<long> logical_to_physical_map;
vector<long> physical_to_logical_map;
};
class ftl_cache {
public:
void register_write_arrival(Event const& app_write);
bool register_read_arrival(Event* app_read);
void register_write_completion(Event const& app_write);
void handle_read_dependency(Event* event);
void clear_clean_entries(double time);
int choose_dirty_victim(double time);
int get_num_dirty_entries() const;
bool mark_clean(int key, double time);
int erase_victim(double time, bool allow_flushing_dirty);
bool contains(int key) const;
void set_synchronized(int key);
static int CACHED_ENTRIES_THRESHOLD;
struct entry {
entry() : dirty(false), synch_flag(false), fixed(false), hotness(0), timestamp(numeric_limits<double>::infinity()) {}
bool dirty;
bool synch_flag;
int fixed;
short hotness;
double timestamp; // when was the entry added to the cache
};
unordered_map<long, entry> cached_mapping_table; // maps logical addresses to physical addresses
queue<long> eviction_queue_dirty;
queue<long> eviction_queue_clean;
private:
void iterate(long& victim_key, entry& victim_entry, bool allow_choosing_dirty);
};
class flash_resident_page_ftl : public FtlParent {
public:
flash_resident_page_ftl(Ssd *ssd, Block_manager_parent* bm) :
FtlParent(ssd, bm), cache(new ftl_cache()), page_mapping(new FtlImpl_Page(ssd, bm)), gc(NULL) {}
flash_resident_page_ftl() : FtlParent(), gc(NULL), cache(new ftl_cache()), page_mapping(NULL) {}
ftl_cache* get_cache() { return cache; }
void set_gc(flash_resident_ftl_garbage_collection* new_gc) { gc = new_gc; }
FtlImpl_Page* get_page_mapping() { return page_mapping; }
void update_bitmap(vector<bool>& bitmap, Address block_addr);
void set_synchronized(int logical_address);
protected:
ftl_cache* cache;
FtlImpl_Page* page_mapping;
flash_resident_ftl_garbage_collection* gc;
};
class DFTL : public flash_resident_page_ftl {
public:
DFTL(Ssd *ssd, Block_manager_parent* bm);
DFTL();
~DFTL();
void read(Event *event);
void write(Event *event);
void trim(Event *event);
void register_write_completion(Event const& event, enum status result);
void register_read_completion(Event const& event, enum status result);
void register_trim_completion(Event & event);
long get_logical_address(uint physical_address) const;
Address get_physical_address(uint logical_address) const;
void set_replace_address(Event& event) const;
void set_read_address(Event& event) const;
void print() const;
void print_short() const;
static int ENTRIES_PER_TRANSLATION_PAGE;
static bool SEPERATE_MAPPING_PAGES;
private:
void notify_garbage_collector(int translation_page_id, double time);
//bool flush_mapping(double time, bool allow_flushing_dirty);
//void iterate(long& victim_key, ftl_cache::entry& victim_entry, bool allow_choosing_dirty);
void create_mapping_read(long translation_page_id, double time, Event* dependant);
void mark_clean(long translation_page_id, Event const& event);
void try_clear_space_in_mapping_cache(double time);
set<long> ongoing_mapping_operations; // contains the logical addresses of ongoing mapping IOs
unordered_map<long, vector<Event*> > application_ios_waiting_for_translation; // maps translation page ids to application IOs awaiting translation
struct mapping_page {
map<int, Address> entries;
};
vector<mapping_page> mapping_pages;
struct dftl_statistics {
map<int, int> cleans_histogram;
map<int, int> address_hits;
};
dftl_statistics dftl_stats;
};
class FAST : public FtlParent {
public:
FAST(Ssd *ssd, Block_manager_parent* bm, Migrator* migrator);
FAST();
~FAST();
void read(Event *event);