-
Notifications
You must be signed in to change notification settings - Fork 0
/
ssd.h
570 lines (519 loc) · 18.9 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
/* 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>
#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;
/* 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};
/* 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};
/* 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 Event;
class Channel;
class Bus;
class Page;
class Block;
class Plane;
class Die;
class Package;
class Garbage_Collector;
class Wear_Leveler;
class Ftl;
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;
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();
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);
Address &operator=(const Address &rhs);
};
/* 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;
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;
Event *get_next(void) const;
void set_address(const Address &address);
void set_merge_address(const Address &address);
void set_next(Event &next);
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;
uint size;
Event *next;
};
/* Quicksort for Channel class
* Supply base pointer to array to be sorted along with inclusive range of
* indices to sort. The move operations for sorting the first array will also
* be performed on the second array, or the second array can be NULL. The
* second array is useful for the channel scheduling table where we want to
* sort by one row and keep data pairs in columns together. */
/* extern "C" void quicksort(double *array1, double *array2, long left, long right); */
void quicksort(double *array1, double *array2, long left, long right);
/* internal quicksort functions listed for documentation purposes
* long partition(double *array1, double *array2, long left, long right);
* void swap(double *x, double *y); */
/* 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);
private:
void unlock(double current_time);
uint table_size;
double * const lock_time;
double * const unlock_time;
uint table_entries;
uint selected_entry;
uint num_connected;
uint max_connections;
double ctrl_delay;
double data_delay;
};
/* 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);
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;
/* Address next_page; */
};
/* The block is the data storage hardware unit where erases are implemented.
* Blocks maintain wear statistics for the FTL. */
class Block
{
public:
Block(const Plane &parent, uint size = BLOCK_SIZE, ulong erases_remaining = BLOCK_ERASES, double erase_delay = BLOCK_ERASE_DELAY);
~Block(void);
enum status read(Event &event);
enum status write(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;
ulong get_erases_remaining(void) const;
uint get_size(void) const;
enum status get_next_page(Address &address) const;
void invalidate_page(uint page);
private:
uint size;
Page * const data;
const Plane &parent;
uint pages_valid;
uint pages_invalid;
enum block_state state;
ulong erases_remaining;
double last_erase_time;
double erase_delay;
};
/* 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);
~Plane(void);
enum status read(Event &event);
enum status write(Event &event);
enum status erase(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;
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;
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);
~Die(void);
enum status read(Event &event);
enum status write(Event &event);
enum status erase(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;
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;
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);
~Package ();
enum status read(Event &event);
enum status write(Event &event);
enum status erase(Event &event);
enum status merge(Event &event);
const Ssd &get_parent(void);
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;
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;
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(Ftl &FTL);
~Garbage_collector(void);
enum status collect(Event &event);
};
class Wear_leveler
{
public:
Wear_leveler(Ftl &FTL);
~Wear_leveler(void);
enum status insert(const Address &address);
};
/* Ftl class has some completed functions that get info from lower-level
* hardware. The other functions are in place as suggestions and can
* be changed as you wish. */
class Ftl
{
public:
Ftl(Controller &controller);
~Ftl(void);
enum status read(Event &event);
enum status write(Event &event);
private:
enum status erase(Event &event);
enum status merge(Event &event);
void garbage_collect(Event &event);
ulong get_erases_remaining(const Address &address) const;
void get_least_worn(Address &address) const;
enum page_state get_state(const Address &address) const;
Controller &controller;
Garbage_collector garbage;
Wear_leveler wear;
Address *free_list;
Address *valid_list;
Address *invalid_list;
long *map;
};
/* 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 Ftl;
private:
enum status issue(Event &event_list);
ssd::ulong get_erases_remaining(const Address &address) const;
void get_least_worn(Address &address) const;
double get_last_erase_time(const Address &address) const;
enum page_state get_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 &ssd;
Ftl ftl;
};
/* The SSD is the single main object that will be created to simulate a real
* SSD. Creating a SSD causes all other objects in the SSD to be created. The
* event_arrive method is where events will arrive from DiskSim. */
class Ssd
{
public:
Ssd (uint ssd_size = SSD_SIZE);
~Ssd(void);
double event_arrive(enum event_type type, ulong logical_address, uint size, double start_time);
friend class Controller;
private:
enum status read(Event &event);
enum status write(Event &event);
enum status erase(Event &event);
enum status merge(Event &event);
ulong get_erases_remaining(const Address &address) const;
void update_wear_stats(const Address &address);
void get_least_worn(Address &address) const;
double get_last_erase_time(const Address &address) const;
Package &get_data(void);
enum page_state get_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;
uint size;
Controller controller;
Ram ram;
Bus bus;
Package * const data;
ulong erases_remaining;
ulong least_worn;
double last_erase_time;
};
} /* end namespace ssd */
#endif