├── .gitignore
├── .travis.yml
├── CHANGELOG.md
├── COPYING
├── FTLs
├── bast_ftl.cpp
├── bdftl_ftl.cpp
├── dftl_ftl.cpp
├── dftl_parent.cpp
├── fast_ftl.cpp
└── page_ftl.cpp
├── Makefile
├── README.FLASHSIM
├── SSDSim.cpp
├── SSDSim.h
├── cscope.sh
├── ctags.sh
├── readme.md
├── run_bimodal.cpp
├── run_correctness.cpp
├── run_debug.cpp
├── run_raid.cpp
├── run_test.cpp
├── run_test2.cpp
├── run_ufliptrace.cpp
├── ssd.conf
├── ssd.conf.testing
├── ssd.h
├── ssd_address.cpp
├── ssd_block.cpp
├── ssd_bm.cpp
├── ssd_bus.cpp
├── ssd_channel.cpp
├── ssd_config.cpp
├── ssd_controller.cpp
├── ssd_die.cpp
├── ssd_event.cpp
├── ssd_ftl.cpp
├── ssd_ftlparent.cpp
├── ssd_gc.cpp
├── ssd_package.cpp
├── ssd_page.cpp
├── ssd_plane.cpp
├── ssd_raidssd.cpp
├── ssd_ram.cpp
├── ssd_ssd.cpp
├── ssd_stats.cpp
├── ssd_wl.cpp
├── uml
├── uml.dia
├── uml.pdf
└── verification.cpp
/.gitignore:
--------------------------------------------------------------------------------
1 | /Verification
2 | /Trace
3 | /RAID
4 | /Page
5 | /Correctness
6 | bimodal
7 | correctness
8 | debug
9 | dftl
10 | raid
11 | test
12 | test2
13 | ufliptrace
14 | *.o
15 | *.kdev4
16 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: cpp
2 | sudo: false
3 |
4 | os:
5 | - linux
6 | - osx
7 |
8 | cache:
9 | apt: true
10 |
11 | addons:
12 | apt:
13 | packages:
14 | - libboost-all-dev
15 |
16 | install:
17 | travis_retry make -j
18 |
19 | script:
20 | - echo Testing correctness...;
21 | echo -en travis_fold:start:correctness;
22 | ./correctness;
23 | echo -en travis_fold:end:correctness
24 | - echo Testing raid...;
25 | echo -en travis_fold:start:raid;
26 | ./raid;
27 | echo -en travis_fold:end:raid
28 | - echo Testing test...;
29 | echo -en travis_fold:start:test;
30 | ./test;
31 | echo -en travis_fold:end:test
32 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Changelog
2 |
3 | ## [Unreleased]
4 | ### Changed
5 | - Debugger expects one more field in write request, indicating the data written.
6 | - Debugger responds to read request with data read along with physical address.
7 |
--------------------------------------------------------------------------------
/FTLs/bast_ftl.cpp:
--------------------------------------------------------------------------------
1 | /* Copyright 2011 Matias Bjørling */
2 |
3 | /* bast_ftl.cpp */
4 |
5 | /* FlashSim is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published by
7 | * the Free Software Foundation, either version 3 of the License, or
8 | * any later version. */
9 |
10 | /* FlashSim is distributed in the hope that it will be useful,
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * GNU General Public License for more details. */
14 |
15 | /* You should have received a copy of the GNU General Public License
16 | * along with FlashSim. If not, see . */
17 |
18 | /****************************************************************************/
19 |
20 | /* Implementation of the BAST FTL described in the Paper
21 | * "A SPACE-EFFICIENT FLASH TRANSLATION LAYER FOR COMPACTFLASH SYSTEMS by Kim et. al."
22 | *
23 | * Notice: Startup procedures are not implemented as the drive is empty every time
24 | * the simulator is executed. i.e. OOB's is not filled with logical page address
25 | * at write and it is not read on startup to recreate mapping tables.
26 | *
27 | * Mapping table are implemented using simulation. A simulated read is performed
28 | * every time a page read is out a cache log page. A cache log page usually hold approx.
29 | * 1000 mappings.
30 | *
31 | * Second notice. Victim mappings still need to be implemented.
32 | */
33 |
34 | #include
35 | #include
36 | #include
37 | #include
38 | #include
39 | #include
40 | #include "../ssd.h"
41 |
42 | using namespace ssd;
43 |
44 | LogPageBlock::LogPageBlock()
45 | {
46 | pages = new int[BLOCK_SIZE];
47 | aPages = new long[BLOCK_SIZE];
48 |
49 | for (uint i=0;i> addressShift);
103 | Address eventAddress = Address(event.get_logical_address(), PAGE);
104 |
105 | LogPageBlock *logBlock = NULL;
106 | if (log_map.find(lookupBlock) != log_map.end())
107 | logBlock = log_map[lookupBlock];
108 |
109 | controller.stats.numMemoryRead++;
110 |
111 | // If page is in the log block
112 | if (logBlock != NULL && logBlock->pages[eventAddress.page] != -1)
113 | {
114 | Address returnAddress = Address(logBlock->address.get_linear_address()+logBlock->pages[eventAddress.page], PAGE);
115 | event.set_address(returnAddress);
116 | }
117 | else if ((data_list[lookupBlock] == -1 && logBlock != NULL && logBlock->pages[eventAddress.page] == -1) || (data_list[lookupBlock] == -1 && logBlock == NULL))
118 | {
119 | event.set_address(Address(0, PAGE));
120 | } else { // page is in the data block
121 | Address returnAddress = Address(data_list[lookupBlock]+ event.get_logical_address() % BLOCK_SIZE , PAGE);
122 | event.set_address(returnAddress);
123 | }
124 |
125 | if (controller.get_state(event.get_address()) == INVALID)
126 | event.set_address(Address(0, PAGE));
127 |
128 | // Statistics
129 | controller.stats.numFTLRead++;
130 |
131 | return controller.issue(event);
132 | }
133 |
134 | enum status FtlImpl_Bast::write(Event &event)
135 | {
136 | LogPageBlock *logBlock = NULL;
137 |
138 | long lba = (event.get_logical_address() >> addressShift);
139 |
140 | Address eventAddress = Address(event.get_logical_address(), PAGE);
141 |
142 | if (log_map.find(lba) == log_map.end())
143 | allocate_new_logblock(logBlock, lba, event);
144 |
145 | controller.stats.numMemoryRead++;
146 |
147 | logBlock = log_map[lba];
148 |
149 | // Can it fit inside the existing log block. Issue the request.
150 | uint numValid = controller.get_num_valid(&logBlock->address);
151 | if (numValid < BLOCK_SIZE)
152 | {
153 | if (logBlock->pages[eventAddress.page] != -1)
154 | {
155 | Address replace_address = Address(logBlock->address.get_linear_address()+logBlock->pages[eventAddress.page], PAGE);
156 | event.set_replace_address(replace_address);
157 | }
158 |
159 | logBlock->pages[eventAddress.page] = numValid;
160 |
161 | Address logBlockAddress = logBlock->address;
162 |
163 | controller.get_free_page(logBlockAddress);
164 | event.set_address(logBlockAddress);
165 | } else {
166 | if (!is_sequential(logBlock, lba, event))
167 | random_merge(logBlock, lba, event);
168 |
169 | allocate_new_logblock(logBlock, lba, event);
170 | logBlock = log_map[lba];
171 | // Write the current io to a new block.
172 | logBlock->pages[eventAddress.page] = 0;
173 | Address dataPage = logBlock->address;
174 | dataPage.valid = PAGE;
175 | event.set_address(dataPage);
176 |
177 | }
178 |
179 | if (data_list[lba] != -1)
180 | {
181 |
182 | int offset = event.get_logical_address() % BLOCK_SIZE;
183 | Address replace = new Address(data_list[lba]+offset, PAGE);
184 | if (controller.get_block_pointer(replace)->get_state(offset) != EMPTY)
185 | event.set_replace_address(replace);
186 | }
187 |
188 | // Statistics
189 | controller.stats.numFTLWrite++;
190 |
191 | return controller.issue(event);
192 | }
193 |
194 | enum status FtlImpl_Bast::trim(Event &event)
195 | {
196 | // Find block
197 | long lookupBlock = (event.get_logical_address() >> addressShift);
198 | Address eventAddress = Address(event.get_logical_address(), PAGE);
199 |
200 | LogPageBlock *logBlock = NULL;
201 | if (log_map.find(lookupBlock) != log_map.end())
202 | logBlock = log_map[lookupBlock];
203 |
204 | controller.stats.numMemoryRead++;
205 |
206 | Address returnAddress;
207 |
208 | if (logBlock != NULL && logBlock->pages[eventAddress.page] != -1) // If page is in the log block
209 | {
210 | returnAddress = Address(logBlock->address.get_linear_address()+logBlock->pages[eventAddress.page], PAGE);
211 | Block *lBlock = controller.get_block_pointer(returnAddress);
212 | lBlock->invalidate_page(returnAddress.page);
213 |
214 | logBlock->pages[eventAddress.page] = -1; // Reset the mapping
215 |
216 | if (lBlock->get_state() == INACTIVE) // All pages invalid, force an erase. PTRIM style.
217 | {
218 | dispose_logblock(logBlock, lookupBlock);
219 | Block_manager::instance()->erase_and_invalidate(event, returnAddress, LOG);
220 | }
221 |
222 | }
223 |
224 | if (data_list[lookupBlock] != -1) // Datablock
225 | {
226 | Address dataAddress = Address(data_list[lookupBlock]+event.get_logical_address() % BLOCK_SIZE , PAGE);
227 | Block *dBlock = controller.get_block_pointer(dataAddress);
228 | dBlock->invalidate_page(dataAddress.page);
229 |
230 | if (dBlock->get_state() == INACTIVE) // All pages invalid, force an erase. PTRIM style.
231 | {
232 | data_list[lookupBlock] = -1;
233 | Block_manager::instance()->erase_and_invalidate(event, dataAddress, DATA);
234 | }
235 |
236 | }
237 |
238 | event.set_address(returnAddress);
239 | event.set_noop(true);
240 |
241 | // Statistics
242 | controller.stats.numFTLTrim++;
243 |
244 | return controller.issue(event);
245 | }
246 |
247 |
248 | void FtlImpl_Bast::allocate_new_logblock(LogPageBlock *logBlock, long lba, Event &event)
249 | {
250 | if (log_map.size() >= BAST_LOG_BLOCK_LIMIT)
251 | {
252 | int victim = random()%log_map.size()-1;
253 | std::map::iterator it = log_map.begin();
254 |
255 | for (int i=0;iaddress = Block_manager::instance()->get_free_block(LOG, event);
269 |
270 | //printf("Using new log block with address: %lu Block: %u\n", logBlock->address.get_linear_address(), logBlock->address.block);
271 | log_map[lba] = logBlock;
272 | }
273 |
274 | void FtlImpl_Bast::dispose_logblock(LogPageBlock *logBlock, long lba)
275 | {
276 | log_map.erase(lba);
277 | delete logBlock;
278 | }
279 |
280 | bool FtlImpl_Bast::is_sequential(LogPageBlock* logBlock, long lba, Event &event)
281 | {
282 | // No page space. Merging required.
283 | /* 1. Log block merge
284 | * 2. Log block switch
285 | */
286 |
287 | // Is block switch possible? i.e. log block switch
288 | bool isSequential = true;
289 | for (uint i=0;ipages[i] != (int)i)
290 | {
291 | isSequential = false;
292 | break;
293 | }
294 |
295 | if (isSequential)
296 | {
297 | Block_manager::instance()->promote_block(DATA);
298 |
299 | // Add to empty list i.e. switch without erasing the datablock.
300 | if (data_list[lba] != -1)
301 | {
302 | Address a = Address(data_list[lba], PAGE);
303 | Block_manager::instance()->erase_and_invalidate(event, a, DATA);
304 | }
305 |
306 | data_list[lba] = logBlock->address.get_linear_address();
307 | dispose_logblock(logBlock, lba);
308 |
309 | controller.stats.numLogMergeSwitch++;
310 | update_map_block(event);
311 | }
312 |
313 | return isSequential;
314 | }
315 |
316 | bool FtlImpl_Bast::random_merge(LogPageBlock *logBlock, long lba, Event &event)
317 | {
318 | /* Do merge (n reads, n writes and 2 erases (gc'ed))
319 | * 1. Write page to new data block
320 | * 1a Promote new log block.
321 | * 2. Create BLOCK_SIZE reads
322 | * 3. Create BLOCK_SIZE writes
323 | * 4. Invalidate data block
324 | * 5. promote new block as data block
325 | * 6. put data and log block into the invalidate list.
326 | */
327 |
328 | Address eventAddress = Address(event.get_logical_address(), PAGE);
329 | Address newDataBlock = Block_manager::instance()->get_free_block(DATA, event);
330 |
331 | int t=0;
332 | for (uint i=0;ipages[i] != -1)
337 | readAddress.set_linear_address(logBlock->address.get_linear_address() + logBlock->pages[i], PAGE);
338 | else if (data_list[lba] != -1)
339 | readAddress.set_linear_address(data_list[lba] + i, PAGE);
340 | else
341 | continue; // Empty page
342 |
343 | if (controller.get_state(readAddress) == EMPTY)
344 | continue;
345 |
346 | if (controller.get_state(readAddress) == INVALID) // A page might be invalidated by trim
347 | continue;
348 |
349 | Event readEvent = Event(READ, event.get_logical_address(), 1, event.get_start_time());
350 | readEvent.set_address(readAddress);
351 | controller.issue(readEvent);
352 |
353 | Event writeEvent = Event(WRITE, event.get_logical_address(), 1, event.get_start_time()+readEvent.get_time_taken());
354 | writeEvent.set_address(Address(newDataBlock.get_linear_address() + i, PAGE));
355 | writeEvent.set_payload((char*)page_data + readAddress.get_linear_address() * PAGE_SIZE);
356 | writeEvent.set_replace_address(readAddress);
357 | controller.issue(writeEvent);
358 |
359 | //event.consolidate_metaevent(writeEvent);
360 | event.incr_time_taken(writeEvent.get_time_taken() + readEvent.get_time_taken());
361 | // Statistics
362 | controller.stats.numFTLRead++;
363 | controller.stats.numFTLWrite++;
364 | controller.stats.numWLRead++;
365 | controller.stats.numWLWrite++;
366 | t++;
367 | }
368 |
369 | // printf("t %i\n",t);
370 |
371 | // Invalidate inactive pages (LOG and DATA
372 |
373 | Block_manager::instance()->erase_and_invalidate(event, logBlock->address, LOG);
374 |
375 | if (data_list[lba] != -1)
376 | {
377 | Address a = Address(data_list[lba], PAGE);
378 | Block_manager::instance()->erase_and_invalidate(event, a, DATA);
379 | }
380 |
381 | // Update mapping
382 | data_list[lba] = newDataBlock.get_linear_address();
383 | update_map_block(event);
384 |
385 | dispose_logblock(logBlock, lba);
386 |
387 | controller.stats.numLogMergeFull++;
388 | return true;
389 | }
390 |
391 | void FtlImpl_Bast::update_map_block(Event &event)
392 | {
393 | Event writeEvent = Event(WRITE, event.get_logical_address(), 1, event.get_start_time());
394 | writeEvent.set_address(Address(0, PAGE));
395 | writeEvent.set_noop(true);
396 |
397 | controller.issue(writeEvent);
398 |
399 | event.incr_time_taken(writeEvent.get_time_taken());
400 |
401 | controller.stats.numGCWrite++;
402 | controller.stats.numFTLWrite++;
403 | }
404 |
405 |
406 | void FtlImpl_Bast::print_ftl_statistics()
407 | {
408 | Block_manager::instance()->print_statistics();
409 | }
410 |
411 |
--------------------------------------------------------------------------------
/FTLs/bdftl_ftl.cpp:
--------------------------------------------------------------------------------
1 | /* Copyright 2011 Matias Bjørling */
2 |
3 | /* bdftp_ftl.cpp */
4 |
5 | /* FlashSim is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published by
7 | * the Free Software Foundation, either version 3 of the License, or
8 | * any later version. */
9 |
10 | /* FlashSim is distributed in the hope that it will be useful,
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * GNU General Public License for more details. */
14 |
15 | /* You should have received a copy of the GNU General Public License
16 | * along with FlashSim. If not, see . */
17 |
18 | /****************************************************************************/
19 |
20 | /* Implementation of BDFTL. A block-level optimization for DFTL.
21 | *
22 | * Global Mapping Table GMT
23 | * Global Translation Directory GTD (Maintained in memory)
24 | * Cached Mapping Table CMT (Uses LRU to pick victim)
25 | *
26 | * Dlpn/Dppn Data Logical/Physical Page Number
27 | * Mlpn/Mppn Translation Logical/Physical Page Number
28 | */
29 |
30 |
31 | #include
32 | #include
33 | #include
34 | #include
35 | #include
36 | #include
37 | #include
38 | #include "../ssd.h"
39 |
40 | using namespace ssd;
41 |
42 | FtlImpl_BDftl::BPage::BPage()
43 | {
44 | this->pbn = -1;
45 | nextPage = 0;
46 | optimal = true;
47 | }
48 |
49 | FtlImpl_BDftl::FtlImpl_BDftl(Controller &controller):
50 | FtlImpl_DftlParent(controller)
51 | {
52 | block_map = new BPage[NUMBER_OF_ADDRESSABLE_BLOCKS];
53 | trim_map = new bool[NUMBER_OF_ADDRESSABLE_BLOCKS*BLOCK_SIZE];
54 |
55 | inuseBlock = NULL;
56 |
57 | printf("Using BDFTL.\n");
58 | }
59 |
60 |
61 |
62 | FtlImpl_BDftl::~FtlImpl_BDftl(void)
63 | {
64 | delete[] block_map;
65 | delete[] trim_map;
66 | return;
67 | }
68 |
69 | enum status FtlImpl_BDftl::read(Event &event)
70 | {
71 | uint dlpn = event.get_logical_address();
72 | uint dlbn = dlpn / BLOCK_SIZE;
73 |
74 | // Block-level lookup
75 | if (block_map[dlbn].optimal)
76 | {
77 | uint dppn = block_map[dlbn].pbn + (dlpn % BLOCK_SIZE);
78 |
79 | if (block_map[dlbn].pbn != (uint) -1)
80 | event.set_address(Address(dppn, PAGE));
81 | else
82 | {
83 | event.set_address(Address(0, PAGE));
84 | event.set_noop(true);
85 | }
86 | } else { // DFTL lookup
87 | resolve_mapping(event, false);
88 |
89 | MPage current = trans_map[dlpn];
90 |
91 | if (current.ppn != -1)
92 | event.set_address(Address(current.ppn, PAGE));
93 | else
94 | {
95 | event.set_address(Address(0, PAGE));
96 | event.set_noop(true);
97 | }
98 | }
99 |
100 | event.incr_time_taken(RAM_READ_DELAY*2);
101 | controller.stats.numMemoryRead += 2; // Block-level lookup + range check
102 | controller.stats.numFTLRead++; // Page read
103 |
104 | return controller.issue(event);
105 | }
106 |
107 |
108 | enum status FtlImpl_BDftl::write(Event &event)
109 | {
110 | uint dlpn = event.get_logical_address();
111 | uint dlbn = dlpn / BLOCK_SIZE;
112 | bool handled = false;
113 |
114 | // Update trim map
115 | trim_map[dlpn] = false;
116 |
117 | // Block-level lookup
118 | if (block_map[dlbn].optimal)
119 | {
120 | // Optimised case for block level lookup
121 |
122 | // Get new block if necessary
123 | if (block_map[dlbn].pbn == -1u && dlpn % BLOCK_SIZE == 0)
124 | block_map[dlbn].pbn = Block_manager::instance()->get_free_block(DATA, event).get_linear_address();
125 |
126 | if (block_map[dlbn].pbn != -1u)
127 | {
128 | unsigned char dppn = dlpn % BLOCK_SIZE;
129 | if (block_map[dlbn].nextPage == dppn)
130 | {
131 | controller.stats.numMemoryWrite++; // Update next page
132 | event.incr_time_taken(RAM_WRITE_DELAY);
133 | event.set_address(Address(block_map[dlbn].pbn + dppn, PAGE));
134 | block_map[dlbn].nextPage++;
135 | handled = true;
136 | } else {
137 | /*
138 | * Transfer the block to DFTL.
139 | * 1. Get number of pages to write
140 | * 2. Get start address for translation map
141 | * 3. Write mappings to trans_map
142 | * 4. Make block non-optimal
143 | * 5. Add the block to the block queue to be used later
144 | */
145 |
146 | // 1-3
147 | uint numPages = block_map[dlbn].nextPage;
148 | long startAdr = dlbn * BLOCK_SIZE;
149 |
150 | Block *b = controller.get_block_pointer(Address(startAdr, PAGE));
151 |
152 | for (uint i=0;iget_state(i) != INVALID);
155 |
156 | if (b->get_state(i) != VALID)
157 | continue;
158 |
159 | MPage current = trans_map[startAdr + i];
160 |
161 | if (current.ppn != -1)
162 | {
163 | update_translation_map(current, block_map[dlbn].pbn+i);
164 | current.create_ts = event.get_start_time();
165 | current.modified_ts = event.get_start_time();
166 | current.cached = true;
167 | trans_map.replace(trans_map.begin()+startAdr+i, current);
168 |
169 | cmt++;
170 |
171 | event.incr_time_taken(RAM_WRITE_DELAY);
172 | controller.stats.numMemoryWrite++;
173 | }
174 |
175 | }
176 |
177 | // 4. Set block to non optimal
178 | event.incr_time_taken(RAM_WRITE_DELAY);
179 | controller.stats.numMemoryWrite++;
180 | block_map[dlbn].optimal = false;
181 |
182 | // 5. Add it to the queue to be used later.
183 | Block *block = controller.get_block_pointer(Address(block_map[dlbn].pbn, BLOCK));
184 | if (block->get_pages_valid() != BLOCK_SIZE)
185 | {
186 | if (inuseBlock == NULL)
187 | inuseBlock = block;
188 | else
189 | blockQueue.push(block);
190 | }
191 |
192 |
193 | controller.stats.numPageBlockToPageConversion++;
194 | }
195 | } else {
196 | block_map[dlbn].optimal = false;
197 | }
198 | }
199 |
200 | if (!handled)
201 | {
202 | // Important order. As get_free_data_page might change current.
203 | long free_page = get_free_biftl_page(event);
204 | resolve_mapping(event, true);
205 |
206 | MPage current = trans_map[dlpn];
207 |
208 | Address a = Address(current.ppn, PAGE);
209 |
210 | if (current.ppn != -1)
211 | event.set_replace_address(a);
212 |
213 |
214 | update_translation_map(current, free_page);
215 | trans_map.replace(trans_map.begin()+dlpn, current);
216 |
217 | // Finish DFTL logic
218 | event.set_address(Address(current.ppn, PAGE));
219 | }
220 |
221 | controller.stats.numMemoryRead += 3; // Block-level lookup + range check + optimal check
222 | event.incr_time_taken(RAM_READ_DELAY*3);
223 | controller.stats.numFTLWrite++; // Page writes
224 |
225 | return controller.issue(event);
226 | }
227 |
228 | long FtlImpl_BDftl::get_free_biftl_page(Event &event)
229 | {
230 | // Important order. As get_free_data_page might change current.
231 | long free_page = -1;
232 |
233 | // Get next available data page
234 | if (inuseBlock == NULL)
235 | {
236 | // DFTL way
237 | free_page = get_free_data_page(event);
238 | } else {
239 | Address address;
240 | if (inuseBlock->get_next_page(address) == SUCCESS)
241 | {
242 | // Get page from biftl block space
243 | free_page = address.get_linear_address();
244 | }
245 | else if (blockQueue.size() != 0)
246 | {
247 | inuseBlock = blockQueue.front();
248 | blockQueue.pop();
249 | if (inuseBlock->get_next_page(address) == SUCCESS)
250 | {
251 | // Get page from the next block in the biftl block space
252 | free_page = address.get_linear_address();
253 | }
254 | else
255 | {
256 | assert(false);
257 | }
258 | } else {
259 | inuseBlock = NULL;
260 | // DFTL way
261 | free_page = get_free_data_page(event);
262 | }
263 | }
264 |
265 | assert(free_page != -1);
266 |
267 | return free_page;
268 |
269 | }
270 |
271 | enum status FtlImpl_BDftl::trim(Event &event)
272 | {
273 | uint dlpn = event.get_logical_address();
274 | uint dlbn = dlpn / BLOCK_SIZE;
275 |
276 | // Update trim map
277 | trim_map[dlpn] = true;
278 |
279 | // Block-level lookup
280 | if (block_map[dlbn].optimal)
281 | {
282 | Address address = Address(block_map[dlbn].pbn+event.get_logical_address()%BLOCK_SIZE, PAGE);
283 | Block *block = controller.get_block_pointer(address);
284 | block->invalidate_page(address.page);
285 |
286 | if (block->get_state() == INACTIVE) // All pages invalid, force an erase. PTRIM style.
287 | {
288 | block_map[dlbn].pbn = -1;
289 | block_map[dlbn].nextPage = 0;
290 | Block_manager::instance()->erase_and_invalidate(event, address, DATA);
291 | }
292 | } else { // DFTL lookup
293 |
294 | MPage current = trans_map[dlpn];
295 | if (current.ppn != -1)
296 | {
297 | Address address = Address(current.ppn, PAGE);
298 | Block *block = controller.get_block_pointer(address);
299 | block->invalidate_page(address.page);
300 |
301 | evict_specific_page_from_cache(event, dlpn);
302 |
303 | // Update translation map to default values.
304 | update_translation_map(current, -1);
305 | trans_map.replace(trans_map.begin()+dlpn, current);
306 |
307 | event.incr_time_taken(RAM_READ_DELAY);
308 | event.incr_time_taken(RAM_WRITE_DELAY);
309 | controller.stats.numMemoryRead++;
310 | controller.stats.numMemoryWrite++;
311 | }
312 |
313 | // Update trim map and update block map if all pages are trimmed. i.e. the state are reseted to optimal.
314 | long addressStart = dlpn - dlpn % BLOCK_SIZE;
315 | bool allTrimmed = true;
316 | for (uint i=addressStart;i invalidated_translation;
346 | /*
347 | * 1. Copy only valid pages in the victim block to the current data block
348 | * 2. Invalidate old pages
349 | * 3. mark their corresponding translation pages for update
350 | */
351 | for (uint i=0;iget_state(i) != EMPTY);
354 | // When valid, two events are create, one for read and one for write. They are chained and the controller are
355 | // called to execute them. The execution time is then added to the real event.
356 | if (block->get_state(i) == VALID)
357 | {
358 | // Set up events.
359 | Event readEvent = Event(READ, event.get_logical_address(), 1, event.get_start_time());
360 | readEvent.set_address(Address(block->get_physical_address()+i, PAGE));
361 |
362 | // Execute read event
363 | if (controller.issue(readEvent) == FAILURE)
364 | printf("Data block copy failed.");
365 |
366 | // Get new address to write to and invalidate previous
367 | Event writeEvent = Event(WRITE, event.get_logical_address(), 1, event.get_start_time()+readEvent.get_time_taken());
368 | Address dataBlockAddress = Address(get_free_data_page(event, false), PAGE);
369 | writeEvent.set_address(dataBlockAddress);
370 | writeEvent.set_replace_address(Address(block->get_physical_address()+i, PAGE));
371 |
372 | // Setup the write event to read from the right place.
373 | writeEvent.set_payload((char*)page_data + (block->get_physical_address()+i) * PAGE_SIZE);
374 |
375 | if (controller.issue(writeEvent) == FAILURE)
376 | printf("Data block copy failed.");
377 |
378 | event.incr_time_taken(writeEvent.get_time_taken() + readEvent.get_time_taken());
379 |
380 | // Update GTD
381 | long dataPpn = dataBlockAddress.get_linear_address();
382 |
383 | // vpn -> Old ppn to new ppn
384 | //printf("%li Moving %li to %li\n", reverse_trans_map[block->get_physical_address()+i], block->get_physical_address()+i, dataPpn);
385 | invalidated_translation[reverse_trans_map[block->get_physical_address()+i]] = dataPpn;
386 |
387 | // Statistics
388 | controller.stats.numFTLRead++;
389 | controller.stats.numFTLWrite++;
390 | controller.stats.numWLRead++;
391 | controller.stats.numWLWrite++;
392 | controller.stats.numMemoryRead++; // Block->get_state(i) == VALID
393 | controller.stats.numMemoryWrite =+ 3; // GTD Update (2) + translation invalidate (1)
394 | }
395 | }
396 |
397 | /*
398 | * Perform batch update on the marked translation pages
399 | * 1. Update GDT and CMT if necessary.
400 | * 2. Simulate translation page updates.
401 | */
402 |
403 | std::map dirtied_translation_pages;
404 |
405 | for (std::map::const_iterator i = invalidated_translation.begin(); i!=invalidated_translation.end(); ++i)
406 | {
407 | long real_vpn = (*i).first;
408 | long newppn = (*i).second;
409 |
410 | // Update translation map ( it also updates the CMT, as it is stored inside the GDT )
411 | MPage current = trans_map[real_vpn];
412 |
413 | update_translation_map(current, newppn);
414 |
415 | if (current.cached)
416 | current.modified_ts = event.get_start_time();
417 | else
418 | {
419 | current.modified_ts = event.get_start_time();
420 | current.create_ts = event.get_start_time();
421 | current.cached = true;
422 | cmt++;
423 | }
424 |
425 | trans_map.replace(trans_map.begin()+real_vpn, current);
426 | }
427 | }
428 |
429 | // Returns true if the next page is in a new block
430 | bool FtlImpl_BDftl::block_next_new()
431 | {
432 | return (currentDataPage == -1 || currentDataPage % BLOCK_SIZE == BLOCK_SIZE -1);
433 | }
434 |
435 | void FtlImpl_BDftl::print_ftl_statistics()
436 | {
437 | printf("FTL Stats:\n");
438 | printf(" Blocks total: %i\n", NUMBER_OF_ADDRESSABLE_BLOCKS);
439 |
440 | int numOptimal = 0;
441 | for (uint i=0;iprint_statistics();
454 | }
455 |
456 |
--------------------------------------------------------------------------------
/FTLs/dftl_ftl.cpp:
--------------------------------------------------------------------------------
1 | /* Copyright 2011 Matias Bjørling */
2 |
3 | /* dftp_ftl.cpp */
4 |
5 | /* FlashSim is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published by
7 | * the Free Software Foundation, either version 3 of the License, or
8 | * any later version. */
9 |
10 | /* FlashSim is distributed in the hope that it will be useful,
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * GNU General Public License for more details. */
14 |
15 | /* You should have received a copy of the GNU General Public License
16 | * along with FlashSim. If not, see . */
17 |
18 | /****************************************************************************/
19 |
20 | /* Implementation of the DFTL described in the paper
21 | * "DFTL: A Flasg Translation Layer Employing Demand-based Selective Caching og Page-level Address Mappings"
22 | *
23 | * Global Mapping Table GMT
24 | * Global Translation Directory GTD (Maintained in memory)
25 | * Cached Mapping Table CMT (Uses LRU to pick victim)
26 | *
27 | * Dlpn/Dppn Data Logical/Physical Page Number
28 | * Mlpn/Mppn Translation Logical/Physical Page Number
29 | */
30 |
31 |
32 | #include
33 | #include
34 | #include
35 | #include
36 | #include
37 | #include
38 | #include
39 | #include "../ssd.h"
40 |
41 | using namespace ssd;
42 |
43 | FtlImpl_Dftl::FtlImpl_Dftl(Controller &controller):
44 | FtlImpl_DftlParent(controller)
45 | {
46 | uint ssdSize = NUMBER_OF_ADDRESSABLE_BLOCKS * BLOCK_SIZE;
47 | printf("Total size to map: %uKB\n", ssdSize * PAGE_SIZE / 1024);
48 | printf("Using DFTL.\n");
49 | return;
50 | }
51 |
52 | FtlImpl_Dftl::~FtlImpl_Dftl(void)
53 | {
54 | return;
55 | }
56 |
57 | enum status FtlImpl_Dftl::read(Event &event)
58 | {
59 | uint dlpn = event.get_logical_address();
60 |
61 | resolve_mapping(event, false);
62 | MPage current = trans_map[dlpn];
63 | if (current.ppn == -1)
64 | {
65 | event.set_address(Address(0, PAGE));
66 | event.set_noop(true);
67 | }
68 | else
69 | event.set_address(Address(current.ppn, PAGE));
70 |
71 |
72 | controller.stats.numFTLRead++;
73 |
74 | return controller.issue(event);
75 | }
76 |
77 | enum status FtlImpl_Dftl::write(Event &event)
78 | {
79 | uint dlpn = event.get_logical_address();
80 |
81 | resolve_mapping(event, true);
82 |
83 | // Important order. As get_free_data_page might change current.
84 | long free_page = get_free_data_page(event);
85 |
86 | MPage current = trans_map[dlpn];
87 |
88 | Address a = Address(current.ppn, PAGE);
89 | if (current.ppn != -1)
90 | event.set_replace_address(a);
91 |
92 | update_translation_map(current, free_page);
93 | trans_map.replace(trans_map.begin()+dlpn, current);
94 |
95 | Address b = Address(free_page, PAGE);
96 | event.set_address(b);
97 |
98 | controller.stats.numFTLWrite++;
99 |
100 | return controller.issue(event);
101 | }
102 |
103 | enum status FtlImpl_Dftl::trim(Event &event)
104 | {
105 | uint dlpn = event.get_logical_address();
106 |
107 | event.set_address(Address(0, PAGE));
108 |
109 | MPage current = trans_map[dlpn];
110 |
111 | if (current.ppn != -1)
112 | {
113 | Address address = Address(current.ppn, PAGE);
114 | Block *block = controller.get_block_pointer(address);
115 | block->invalidate_page(address.page);
116 |
117 | evict_specific_page_from_cache(event, dlpn);
118 |
119 | update_translation_map(current, -1);
120 |
121 | trans_map.replace(trans_map.begin()+dlpn, current);
122 | }
123 |
124 | controller.stats.numFTLTrim++;
125 |
126 | return controller.issue(event);
127 | }
128 |
129 | void FtlImpl_Dftl::cleanup_block(Event &event, Block *block)
130 | {
131 | std::map invalidated_translation;
132 | /*
133 | * 1. Copy only valid pages in the victim block to the current data block
134 | * 2. Invalidate old pages
135 | * 3. mark their corresponding translation pages for update
136 | */
137 | for (uint i=0;iget_state(i) != EMPTY);
140 | // When valid, two events are create, one for read and one for write. They are chained and the controller are
141 | // called to execute them. The execution time is then added to the real event.
142 | if (block->get_state(i) == VALID)
143 | {
144 | // Set up events.
145 | Event readEvent = Event(READ, event.get_logical_address(), 1, event.get_start_time());
146 | readEvent.set_address(Address(block->get_physical_address()+i, PAGE));
147 |
148 | // Execute read event
149 | if (controller.issue(readEvent) == FAILURE)
150 | printf("Data block copy failed.");
151 |
152 | // Get new address to write to and invalidate previous
153 | Event writeEvent = Event(WRITE, event.get_logical_address(), 1, event.get_start_time()+readEvent.get_time_taken());
154 | Address dataBlockAddress = Address(get_free_data_page(event, false), PAGE);
155 |
156 | writeEvent.set_address(dataBlockAddress);
157 |
158 | writeEvent.set_replace_address(Address(block->get_physical_address()+i, PAGE));
159 |
160 | // Setup the write event to read from the right place.
161 | writeEvent.set_payload((char*)page_data + (block->get_physical_address()+i) * PAGE_SIZE);
162 |
163 | if (controller.issue(writeEvent) == FAILURE)
164 | printf("Data block copy failed.");
165 |
166 | event.incr_time_taken(writeEvent.get_time_taken() + readEvent.get_time_taken());
167 |
168 | // Update GTD
169 | long dataPpn = dataBlockAddress.get_linear_address();
170 |
171 | // vpn -> Old ppn to new ppn
172 | //printf("%li Moving %li to %li\n", reverse_trans_map[block->get_physical_address()+i], block->get_physical_address()+i, dataPpn);
173 | invalidated_translation[reverse_trans_map[block->get_physical_address()+i]] = dataPpn;
174 |
175 | // Statistics
176 | controller.stats.numFTLRead++;
177 | controller.stats.numFTLWrite++;
178 | controller.stats.numWLRead++;
179 | controller.stats.numWLWrite++;
180 | controller.stats.numMemoryRead++; // Block->get_state(i) == VALID
181 | controller.stats.numMemoryWrite =+ 3; // GTD Update (2) + translation invalidate (1)
182 | }
183 | }
184 |
185 | /*
186 | * Perform batch update on the marked translation pages
187 | * 1. Update GDT and CMT if necessary.
188 | * 2. Simulate translation page updates.
189 | */
190 |
191 | std::map dirtied_translation_pages;
192 |
193 | for (std::map::const_iterator i = invalidated_translation.begin(); i!=invalidated_translation.end(); ++i)
194 | {
195 | long real_vpn = (*i).first;
196 | long newppn = (*i).second;
197 |
198 | // Update translation map ( it also updates the CMT, as it is stored inside the GDT )
199 | MPage current = trans_map[real_vpn];
200 |
201 | update_translation_map(current, newppn);
202 |
203 | if (current.cached)
204 | current.modified_ts = event.get_start_time();
205 | else
206 | {
207 | current.modified_ts = event.get_start_time();
208 | current.create_ts = event.get_start_time();
209 | current.cached = true;
210 | cmt++;
211 | }
212 |
213 | trans_map.replace(trans_map.begin()+real_vpn, current);
214 | }
215 |
216 | }
217 |
218 | void FtlImpl_Dftl::print_ftl_statistics()
219 | {
220 | Block_manager::instance()->print_statistics();
221 | }
222 |
--------------------------------------------------------------------------------
/FTLs/dftl_parent.cpp:
--------------------------------------------------------------------------------
1 | /* Copyright 2011 Matias Bjørling */
2 |
3 | /* dftp_ftl.cpp */
4 |
5 | /* FlashSim is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published by
7 | * the Free Software Foundation, either version 3 of the License, or
8 | * any later version. */
9 |
10 | /* FlashSim is distributed in the hope that it will be useful,
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * GNU General Public License for more details. */
14 |
15 | /* You should have received a copy of the GNU General Public License
16 | * along with FlashSim. If not, see . */
17 |
18 | /****************************************************************************/
19 |
20 | /* Implementation of the DFTL described in the paper
21 | * "DFTL: A Flasg Translation Layer Employing Demand-based Selective Caching og Page-level Address Mappings"
22 | *
23 | * Global Mapping Table GMT
24 | * Global Translation Directory GTD (Maintained in memory)
25 | * Cached Mapping Table CMT (Uses LRU to pick victim)
26 | *
27 | * Dlpn/Dppn Data Logical/Physical Page Number
28 | * Mlpn/Mppn Translation Logical/Physical Page Number
29 | */
30 |
31 |
32 | #include
33 | #include
34 | #include
35 | #include
36 | #include
37 | #include
38 | #include
39 | #include
40 | #include "../ssd.h"
41 |
42 | using namespace ssd;
43 |
44 | FtlImpl_DftlParent::MPage::MPage(long vpn)
45 | {
46 | this->vpn = vpn;
47 | this->ppn = -1;
48 | this->create_ts = -1;
49 | this->modified_ts = -1;
50 | this->last_visited_time = -1;
51 | this->cached = false;
52 | }
53 |
54 | double FtlImpl_DftlParent::mpage_last_visited_time_compare(const FtlImpl_DftlParent::MPage& mpage)
55 | {
56 | if (!mpage.cached)
57 | return std::numeric_limits::max();
58 |
59 | return mpage.last_visited_time;
60 | }
61 |
62 | FtlImpl_DftlParent::FtlImpl_DftlParent(Controller &controller):
63 | FtlParent(controller)
64 | {
65 | addressPerPage = 0;
66 | cmt = 0;
67 | currentDataPage = -1;
68 | currentTranslationPage = -1;
69 |
70 | // Detect required number of bits for logical address size
71 | addressSize = log(NUMBER_OF_ADDRESSABLE_BLOCKS * BLOCK_SIZE)/log(2);
72 |
73 | // Find required number of bits for block size
74 | addressPerPage = (PAGE_SIZE/ceil(addressSize / 8.0)); // 8 bits per byte
75 |
76 | printf("Total required bits for representation: Address size: %i Total per page: %i \n", addressSize, addressPerPage);
77 |
78 | totalCMTentries = CACHE_DFTL_LIMIT * addressPerPage;
79 | printf("Number of elements in Cached Mapping Table (CMT): %i\n", totalCMTentries);
80 |
81 | // Initialise block mapping table.
82 | uint ssdSize = NUMBER_OF_ADDRESSABLE_BLOCKS * BLOCK_SIZE;
83 |
84 | trans_map.reserve(ssdSize);
85 | for (uint i=0;iinsert_events(event);
131 |
132 | if (currentDataPage == -1 || currentDataPage % BLOCK_SIZE == BLOCK_SIZE -1)
133 | currentDataPage = Block_manager::instance()->get_free_block(DATA, event).get_linear_address();
134 | else
135 | currentDataPage++;
136 |
137 | return currentDataPage;
138 | }
139 |
140 | FtlImpl_DftlParent::~FtlImpl_DftlParent(void)
141 | {
142 | delete[] reverse_trans_map;
143 | }
144 |
145 | void FtlImpl_DftlParent::resolve_mapping(Event &event, bool isWrite)
146 | {
147 | uint dlpn = event.get_logical_address();
148 | /* 1. Lookup in CMT if the mapping exist
149 | * 2. If, then serve
150 | * 3. If not, then goto GDT, lookup page
151 | * 4. If CMT full, evict a page
152 | * 5. Add mapping to CMT
153 | */
154 | //printf("%i\n", cmt);
155 | if (lookup_CMT(event.get_logical_address(), event))
156 | {
157 | controller.stats.numCacheHits++;
158 |
159 | MPage current = trans_map[dlpn];
160 | if (isWrite)
161 | {
162 | current.modified_ts = event.get_start_time();
163 | }
164 | current.last_visited_time = event.get_start_time();
165 | trans_map.replace(trans_map.begin()+dlpn, current);
166 |
167 | // evict_page_from_cache(event); // no need to evict page from cache
168 | } else {
169 | controller.stats.numCacheFaults++;
170 |
171 | evict_page_from_cache(event);
172 |
173 | consult_GTD(dlpn, event);
174 |
175 | MPage current = trans_map[dlpn];
176 | current.modified_ts = event.get_start_time();
177 | current.last_visited_time = event.get_start_time();
178 | if (isWrite)
179 | current.modified_ts++;
180 | current.create_ts = event.get_start_time();
181 | current.cached = true;
182 | trans_map.replace(trans_map.begin()+dlpn, current);
183 |
184 | cmt++;
185 | }
186 | }
187 |
188 | void FtlImpl_DftlParent::evict_page_from_cache(Event &event)
189 | {
190 | while (cmt >= totalCMTentries)
191 | {
192 | // Find page to evict
193 | MpageByLastVisited::iterator evictit = boost::multi_index::get<1>(trans_map).begin();
194 | MPage evictPage = *evictit;
195 |
196 | assert(evictPage.cached && evictPage.create_ts >= 0 && evictPage.modified_ts >= 0);
197 |
198 | if (evictPage.create_ts != evictPage.modified_ts)
199 | {
200 | // Evict page
201 | // Inform the ssd model that it should invalidate the previous page.
202 | // Calculate the start address of the translation page.
203 | int vpnBase = evictPage.vpn - evictPage.vpn % addressPerPage;
204 |
205 | for (int i=0;i= 0 && evictPage.modified_ts >= 0);
245 |
246 | if (evictPage.create_ts != evictPage.modified_ts)
247 | {
248 | // Evict page
249 | // Inform the ssd model that it should invalidate the previous page.
250 | // Calculate the start address of the translation page.
251 | int vpnBase = evictPage.vpn - evictPage.vpn % addressPerPage;
252 |
253 | for (int i=0;i. */
17 |
18 | /****************************************************************************/
19 |
20 | /* Implements a very simple page-level FTL without merge */
21 |
22 | #include
23 | #include
24 | #include
25 | #include
26 | #include "../ssd.h"
27 |
28 | using namespace ssd;
29 |
30 | FtlImpl_Page::FtlImpl_Page(Controller &controller):
31 | FtlParent(controller)
32 | {
33 | trim_map = new bool[NUMBER_OF_ADDRESSABLE_BLOCKS * BLOCK_SIZE];
34 |
35 | numPagesActive = 0;
36 |
37 | return;
38 | }
39 |
40 | FtlImpl_Page::~FtlImpl_Page(void)
41 | {
42 |
43 | return;
44 | }
45 |
46 | enum status FtlImpl_Page::read(Event &event)
47 | {
48 | event.set_address(Address(0, PAGE));
49 | event.set_noop(true);
50 |
51 | controller.stats.numFTLRead++;
52 |
53 | return controller.issue(event);
54 | }
55 |
56 | enum status FtlImpl_Page::write(Event &event)
57 | {
58 | event.set_address(Address(1, PAGE));
59 | event.set_noop(true);
60 |
61 | controller.stats.numFTLWrite++;
62 |
63 | if (numPagesActive == NUMBER_OF_ADDRESSABLE_BLOCKS * BLOCK_SIZE)
64 | {
65 | numPagesActive -= BLOCK_SIZE;
66 |
67 | Event eraseEvent = Event(ERASE, event.get_logical_address(), 1, event.get_start_time());
68 | eraseEvent.set_address(Address(0, PAGE));
69 |
70 | if (controller.issue(eraseEvent) == FAILURE) printf("Erase failed");
71 |
72 | event.incr_time_taken(eraseEvent.get_time_taken());
73 |
74 | controller.stats.numFTLErase++;
75 | }
76 |
77 | numPagesActive++;
78 |
79 |
80 | return controller.issue(event);
81 | }
82 |
83 | enum status FtlImpl_Page::trim(Event &event)
84 | {
85 | controller.stats.numFTLTrim++;
86 |
87 | uint dlpn = event.get_logical_address();
88 |
89 | if (!trim_map[event.get_logical_address()])
90 | trim_map[event.get_logical_address()] = true;
91 |
92 | // Update trim map and update block map if all pages are trimmed. i.e. the state are reseted to optimal.
93 | long addressStart = dlpn - dlpn % BLOCK_SIZE;
94 | bool allTrimmed = true;
95 | for (uint i=addressStart;iatgmaildot
com
3 |
4 | README is part of FlashSim.
5 |
6 | FlashSim is free software: you can redistribute it and/or modify
7 | it under the terms of the GNU General Public License as published by
8 | the Free Software Foundation, either version 3 of the License, or
9 | any later version.
10 |
11 | FlashSim is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | GNU General Public License for more details.
15 |
16 | You should have received a copy of the GNU General Public License
17 | along with FlashSim. If not, see .
18 |
19 | ##############################################################################
20 |
21 | README
22 |
23 | To use FlashSim with a main file, use the "ssd" (default) make target
24 | and link the object files with your code that contains a main function. Some
25 | examples can be found in the "test" and "trace" make targets and corresponding
26 | source files.
27 |
28 | Users must provide their FTL scheme to run FlashSim, which should include a
29 | FTL, wear-leveler, and garbage-collector class. Please note that FLASHSIM WILL
30 | NOT WORK WITHOUT PROVIDING A FTL SCHEME. The UML diagram has been provided to
31 | assist with FTL development. Many private functions of the Controller class
32 | made available to the FTL class will assist users in FTL development. Users can
33 | run the "test" and "trace" make target output binaries to perform basic
34 | testing of their FTL schemes.
35 |
36 | Before running the FlashSim module, users should update the configuration file
37 | "ssd.conf" according to their specificiations. Descriptions of configuration
38 | settings can be found in the sample configuration file.
39 |
40 | FlashSim was designed to be capable of being modularly integrated with Disksim.
41 | The Ssd::event_arrive() function signature in ssd_ssd.cpp was designed to match
42 | the event_arrive() function signature that Disksim uses to send events to disks.
43 |
44 | Any questions, comments, suggestions, or code additions are welcome.
45 |
--------------------------------------------------------------------------------
/SSDSim.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | * SSDSim.cpp
3 | *
4 | * Created on: Feb 21, 2011
5 | * Author: silverwolf
6 | */
7 |
8 | #include "SSDSim.h"
9 | #include
10 |
11 | #ifdef __cplusplus
12 | #include "ssd.h"
13 | #include
14 | using namespace ssd;
15 | #endif
16 |
17 | void SSD_Initialize()
18 | {
19 | load_config();
20 | print_config(NULL);
21 |
22 | ssdImpl = new Ssd();
23 |
24 | gettimeofday(&ssd_boot_time, NULL);
25 |
26 | printf("Booted the SSD Simulator.\n");
27 | }
28 |
29 | void SSD_Cleanup()
30 | {
31 | printf("SSD Simulator killed.\n");
32 | delete ssdImpl;
33 | }
34 |
35 | void SSD_Write(unsigned long long address, int size, void *buf)
36 | {
37 | gettimeofday(&ssd_request_time, NULL);
38 |
39 | double time = ((ssd_request_time.tv_sec - ssd_boot_time.tv_sec) * 1000 + (ssd_request_time.tv_usec - ssd_boot_time.tv_usec) / 1000.0) + 0.5;
40 |
41 | for (int i=0;ievent_arrive(WRITE, address, 1, time, NULL);
44 | printf("Write time address %llu (%i): %.20lf at %.3f\n", address, size, result, time);
45 | }
46 | }
47 |
48 | void SSD_Read(unsigned long long address, int size, void *buf)
49 | {
50 | gettimeofday(&ssd_request_time, NULL);
51 |
52 | double time = ((ssd_request_time.tv_sec - ssd_boot_time.tv_sec) * 1000 + (ssd_request_time.tv_usec - ssd_boot_time.tv_usec) / 1000.0) + 0.5;
53 |
54 | for (int i=0;ievent_arrive(READ, address, 1, time, NULL);
57 | printf("Read time %llu (%i): %.20lf at %.3f\n", address, size, result, time);
58 | }
59 | }
60 |
61 |
--------------------------------------------------------------------------------
/SSDSim.h:
--------------------------------------------------------------------------------
1 | /*
2 | * SSDSim.h
3 | *
4 | * Created on: Feb 21, 2011
5 | * Author: Matias Bjørling
6 | */
7 |
8 | #ifndef SSDSIM_H_
9 | #define SSDSIM_H_
10 |
11 |
12 | #ifdef __cplusplus
13 | #include "ssd.h"
14 |
15 | using namespace ssd;
16 |
17 | Ssd *ssdImpl;
18 | struct timeval ssd_boot_time, ssd_request_time;
19 |
20 | extern "C" {
21 | #endif
22 |
23 | void SSD_Initialize();
24 | void SSD_Cleanup();
25 | void SSD_Write(unsigned long long address, int size, void *buf);
26 | void SSD_Read(unsigned long long address, int size, void *buf);
27 |
28 | #ifdef __cplusplus
29 | } // extern "C"
30 | #endif
31 |
32 | #endif /* SSDSIM_H_ */
33 |
--------------------------------------------------------------------------------
/cscope.sh:
--------------------------------------------------------------------------------
1 | # Copyright 2009, 2010 Brendan Tauras
2 |
3 | # cscope.sh is part of FlashSim.
4 |
5 | # FlashSim is free software: you can redistribute it and/or modify
6 | # it under the terms of the GNU General Public License as published by
7 | # the Free Software Foundation, either version 3 of the License, or
8 | # any later version.
9 |
10 | # FlashSim is distributed in the hope that it will be useful,
11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | # GNU General Public License for more details.
14 |
15 | # You should have received a copy of the GNU General Public License
16 | # along with FlashSim. If not, see .
17 |
18 | ##############################################################################
19 |
20 | #!/bin/env sh
21 |
22 | export VIEWER=vim
23 | `make files | tail -1` | cscope
24 | cscope
25 |
--------------------------------------------------------------------------------
/ctags.sh:
--------------------------------------------------------------------------------
1 | # Copyright 2009, 2010 Brendan Tauras
2 |
3 | # ctags.sh is part of FlashSim.
4 |
5 | # FlashSim is free software: you can redistribute it and/or modify
6 | # it under the terms of the GNU General Public License as published by
7 | # the Free Software Foundation, either version 3 of the License, or
8 | # any later version.
9 |
10 | # FlashSim is distributed in the hope that it will be useful,
11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | # GNU General Public License for more details.
14 |
15 | # You should have received a copy of the GNU General Public License
16 | # along with FlashSim. If not, see .
17 |
18 | ##############################################################################
19 |
20 | #!/bin/env sh
21 | ctags --extra=+fq --fields=+afikKlmnsSzt -h cpp.h *.cpp *.h
22 |
--------------------------------------------------------------------------------
/readme.md:
--------------------------------------------------------------------------------
1 | # Extended FlashSim
2 | [](https://travis-ci.org/MatiasBjorling/flashsim)
3 |
4 | This project extends FlashSim with BAST, FAST and DFTL FTLs.
5 |
6 | Please reference if you use for your research.
7 |
8 | Bibtex
9 |
10 | @article{extendedflashsim,
11 | Author = {Matias Bj{\o}rling},
12 | Title = {Extended FlashSim},
13 | Url = {https://github.com/MatiasBjorling/flashsim},
14 | Year = 2011}
15 |
16 | The FTL algorihms are implemented on top of the Flash based SSD simulator implementation created by Brendan Tauras btauras, Youngjae Kim, Aayush Gupta at Pennsylvania State University.
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/run_bimodal.cpp:
--------------------------------------------------------------------------------
1 | /* FlashSim is free software: you can redistribute it and/or modify
2 | * it under the terms of the GNU General Public License as published by
3 | * the Free Software Foundation, either version 3 of the License, or
4 | * any later version. */
5 |
6 | /* FlashSim is distributed in the hope that it will be useful,
7 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
8 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 | * GNU General Public License for more details. */
10 |
11 | /* You should have received a copy of the GNU General Public License
12 | * along with FlashSim. If not, see . */
13 |
14 | /****************************************************************************/
15 |
16 | #include
17 | #include
18 | #include
19 | #include
20 | #include
21 | #include
22 | #include
23 | #include
24 | #include
25 | #include "ssd.h"
26 |
27 | using namespace ssd;
28 |
29 | /**
30 | * Benchmark plan
31 | * 1. The number of writes should be the size of the device simulated.
32 | * 2. Trim a designated area. E.g. 256MB, measure the time it takes to perform the trim with the implemented FTLs.
33 | * 3. Measure the time required to overwrite the area and compare with the other FTLs.
34 | * 4. Create a report with shows the differences in response time using CDF's.
35 | *
36 | * Test assumes a 6GB SSD, with Block-size 64 and Page size 2048 bytes.
37 | */
38 |
39 | int main(int argc, char **argv){
40 |
41 | long vaddr;
42 |
43 | double arrive_time;
44 |
45 | load_config();
46 | print_config(NULL);
47 |
48 | Ssd ssd;
49 |
50 | printf("INITIALIZING SSD Bimodal\n");
51 |
52 | srandom(1);
53 | int preIO = SSD_SIZE * PACKAGE_SIZE * DIE_SIZE * PLANE_SIZE * BLOCK_SIZE;
54 |
55 | if (FTL_IMPLEMENTATION == 0) // PAGE
56 | preIO -= 16*BLOCK_SIZE;
57 |
58 | if (FTL_IMPLEMENTATION == 1) // BAST
59 | preIO -= (BAST_LOG_BLOCK_LIMIT*BLOCK_SIZE)*2;
60 |
61 | if (FTL_IMPLEMENTATION == 2) // FAST
62 | preIO -= (FAST_LOG_BLOCK_LIMIT*BLOCK_SIZE)*1.1;
63 |
64 | if (FTL_IMPLEMENTATION > 2) // DFTL BIFTL
65 | preIO -= 512;
66 |
67 | int deviceSize = 3145216;
68 |
69 | if (preIO > deviceSize)
70 | preIO = deviceSize;
71 |
72 | printf("Writes %i pages for startup out of %i total pages.\n", preIO, SSD_SIZE * PACKAGE_SIZE * DIE_SIZE * PLANE_SIZE * BLOCK_SIZE);
73 |
74 | double start_time = 0;
75 | double timeMultiplier = 10000;
76 |
77 | double read_time = 0;
78 | double write_time = 0;
79 | double trim_time = 0;
80 |
81 | unsigned long num_reads = 0;
82 | unsigned long num_writes = 0;
83 | unsigned long num_trims = 0;
84 |
85 | std::vector avgsTrim;
86 | std::vector avgsWrite1;
87 | std::vector avgsRead1;
88 | std::vector avgsRead2;
89 | std::vector avgsRead3;
90 | std::vector avgsTrim2;
91 | std::vector avgsWrite2;
92 | std::vector avgsRead4;
93 | std::vector avgsWrite3;
94 |
95 |
96 | avgsTrim.reserve(1024*64);
97 | avgsWrite1.reserve(1024*64);
98 | avgsRead1.reserve(1024*64);
99 | avgsRead2.reserve(1024*64);
100 | avgsRead3.reserve(1024*64);
101 | avgsTrim2.reserve(1024*64);
102 | avgsWrite2.reserve(1024*64);
103 | avgsRead4.reserve(1024*64);
104 | avgsWrite3.reserve(1024*64);
105 |
106 | // Reset statistics
107 | ssd.reset_statistics();
108 |
109 | // 1. Write random to the size of the device
110 | srand(1);
111 | double afterFormatStartTime = 0;
112 | //for (int i=0; i 400)
215 | printf("Trim: %i %f\n", i, trim_time);
216 |
217 | }
218 |
219 | for (int i=startTrim; i
7 |
8 | #include
9 | #include
10 | #include
11 | #include
12 | #include
13 | #include
14 | #include
15 | #include
16 |
17 | using namespace ssd;
18 |
19 | int open_temp_file(unsigned int file_size = 10 * 1024 * 1024)
20 | {
21 | std::string out_path = "/tmp/garbage.XXXXXX";
22 | int fd = mkstemp(&*out_path.begin());
23 | if (fd != -1)
24 | {
25 | ftruncate(fd, file_size);
26 | printf("Created temporary file %s of size %u\n", out_path.c_str(), file_size);
27 | }
28 | else
29 | {
30 | printf("Failed to create temp file\n");
31 | }
32 | return fd;
33 | }
34 |
35 | double timings = 0.0;
36 |
37 | double do_seq(Ssd *ssd, event_type type, void *test, unsigned int file_size)
38 | {
39 | unsigned int adr, i = 0;
40 | double result = 0;
41 | for (adr = 0; adr < file_size;adr += PAGE_SIZE)
42 | {
43 | double iotime = ssd->event_arrive(type, i, 1, timings, (char*)test + adr);
44 | //printf("IO Execution time: %f\n", iotime);
45 | result += iotime;
46 | timings += iotime;
47 | if (type == READ)
48 | {
49 | if (ssd->get_result_buffer() == NULL)
50 | printf("Data has not been written\n");
51 | else if (memcmp(ssd->get_result_buffer(), (char*)test + adr, PAGE_SIZE) != 0)
52 | fprintf(stderr, "i: %i ", i);
53 | }
54 | i++;
55 | }
56 | fprintf(stderr,"\n");
57 | return result;
58 | }
59 |
60 | double do_seq_backward(Ssd *ssd, event_type type, void *test, unsigned int file_size)
61 | {
62 | unsigned int adr, i = BLOCK_SIZE-1, j=0;
63 | double result = 0;
64 | for (adr = file_size; adr > 0;adr -= PAGE_SIZE)
65 | {
66 | double iotime = ssd->event_arrive(type, j+i, 1, timings, (char*)test + adr - PAGE_SIZE);
67 |
68 | if (type == READ && memcmp(ssd->get_result_buffer(), (char*)test + adr - PAGE_SIZE, PAGE_SIZE) != 0)
69 | fprintf(stderr, "Err. Data does not compare. i: %i\n", j+i);
70 |
71 | result += iotime;
72 | timings += iotime;
73 |
74 | i--;
75 |
76 | if (i == -1u)
77 | {
78 | i = BLOCK_SIZE - 1;
79 | j += BLOCK_SIZE;
80 | }
81 | }
82 | return result;
83 | }
84 |
85 | double do_random(Ssd *ssd, event_type type, void *test, unsigned int file_size)
86 | {
87 | unsigned int adr, i = 0;
88 | double result = 0;
89 | for (adr = 0; adr < file_size;adr += PAGE_SIZE)
90 | {
91 | result += ssd->event_arrive(type, i, 1, (double) adr, (char*)test + adr);
92 | if (type == READ)
93 | {
94 | if (memcmp(ssd->get_result_buffer(), (char*)test + adr, PAGE_SIZE) != 0)
95 | fprintf(stderr, "Err. Data does not compare. i: %i\n", i);
96 | }
97 | i++;
98 | }
99 | return result;
100 | }
101 |
102 | int main(int argc, char** argv)
103 | {
104 | load_config();
105 | print_config(NULL);
106 | printf("\n");
107 |
108 | Ssd *ssd = new Ssd();
109 |
110 | // create memory mapping of file that we are going to check with
111 | int fd;
112 | if (argc == 1)
113 | fd = open_temp_file();
114 | else
115 | fd = open(argv[1], O_RDONLY);
116 | struct stat st;
117 | fstat(fd, &st);
118 |
119 | void *test_data = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
120 |
121 | if (test_data == MAP_FAILED)
122 | fprintf(stderr, "File not mapped.");
123 |
124 | printf("Size of testfile: %iKB\n", (int)st.st_size/1024);
125 |
126 | /*
127 | * Experiment setup
128 | * 1. Do linear write and read.
129 | * 2. Write linear again and read.
130 | * 2. Do semi-random linear
131 | * 3. Do random
132 | * 4. Do backward linear
133 | */
134 |
135 | double result = 0;
136 |
137 | printf("Test 1. Write sequential test data.\n");
138 | result += do_seq(ssd, WRITE, test_data, st.st_size);
139 |
140 | printf("Test 1. Write sequential test data.\n");
141 | result += do_seq(ssd, WRITE, test_data, st.st_size);
142 |
143 | printf("Test 1. Write sequential test data.\n");
144 | result += do_seq(ssd, WRITE, test_data, st.st_size);
145 | //
146 | // printf("Test 1. Trim data.\n");
147 | // result += do_seq(ssd, TRIM, test_data, st.st_size);
148 |
149 | printf("Test 1. Write sequential test data.\n");
150 | result += do_seq(ssd, WRITE, test_data, st.st_size);
151 |
152 | printf("Test 2. Read sequential test data.\n");
153 | result += do_seq(ssd, READ, test_data, st.st_size);
154 |
155 | // printf("Test 6. Write backward sequential test data.\n");
156 | // result += do_seq_backward(ssd, WRITE, test_data, st.st_size);
157 | //
158 | // printf("Test 9. Read backward sequential test data.\n");
159 | // result += do_seq_backward(ssd, READ, test_data, st.st_size);
160 |
161 | // printf("Test 3. Write second write.\n");
162 | // result += do_seq(ssd, WRITE, test_data, st.st_size);
163 | //
164 | // printf("Test 4. Write third write.\n");
165 | // result += do_seq_backward(ssd, WRITE, test_data, st.st_size);
166 | //
167 | // printf("Test 5. Read sequential test data.\n");
168 | // result += do_seq_backward(ssd, READ, test_data, st.st_size);
169 | //
170 | // printf("Test 6. Write backward sequential test data.\n");
171 | // result += do_seq_backward(ssd, WRITE, test_data, st.st_size);
172 | //
173 | // printf("Test 7. Read backward sequential test data.\n");
174 | // result += do_seq_backward(ssd, READ, test_data, st.st_size);
175 | //
176 | // printf("Test 8. Write backward sequential test data again.\n");
177 | // result += do_seq_backward(ssd, WRITE, test_data, st.st_size);
178 | //
179 | // printf("Test 9. Read backward sequential test data.\n");
180 | // result += do_seq_backward(ssd, READ, test_data, st.st_size);
181 |
182 | printf("Write time: %.10lfs\n", result);
183 |
184 | ssd->print_statistics();
185 | delete ssd;
186 | return 0;
187 | }
188 |
--------------------------------------------------------------------------------
/run_debug.cpp:
--------------------------------------------------------------------------------
1 | /* FlashSim is free software: you can redistribute it and/or modify
2 | * it under the terms of the GNU General Public License as published by
3 | * the Free Software Foundation, either version 3 of the License, or
4 | * any later version. */
5 |
6 | /* FlashSim is distributed in the hope that it will be useful,
7 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
8 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 | * GNU General Public License for more details. */
10 |
11 | /* You should have received a copy of the GNU General Public License
12 | * along with FlashSim. If not, see . */
13 |
14 | /****************************************************************************/
15 |
16 | /* Interactive debugger.
17 | * Yishuai Li
18 | * Dec 29, 2015 */
19 |
20 | #include
21 | #include
22 | #include "ssd.h"
23 |
24 | using namespace ssd;
25 |
26 | /* Input Format
27 |
28 | Each request consists of two or three fields, separated by whitespaces:
29 | 1. One character, representing the type of I/O: (R)ead, (W)rite, (T)rim;
30 | 2. One integer, representing the virtual address;
31 | 3. (Write only) One integer, representing the data written.
32 |
33 | * Output Format
34 |
35 | For read requests, the program responds with two integers: the data read, and
36 | the physical address being read.
37 | */
38 |
39 | void debug(Ssd& ssd) throw (std::invalid_argument)
40 | {
41 | char ioType;
42 | ulong vaddr;
43 | char buffer[PAGE_SIZE];
44 | while (std::cin >> ioType >> vaddr)
45 | {
46 | event_type type;
47 | switch (ioType)
48 | {
49 | case 'R':
50 | case 'r':
51 | type = READ;
52 | break;
53 | case 'W':
54 | case 'w':
55 | type = WRITE;
56 | std::cin >> *(int*) buffer;
57 | break;
58 | case 'T':
59 | case 't':
60 | type = TRIM;
61 | break;
62 | default:
63 | throw std::invalid_argument("Invalid I/O type!");
64 | }
65 | global_buffer = nullptr;
66 | ssd.event_arrive(type, vaddr, 1, time(NULL), buffer);
67 | if (type == READ)
68 | {
69 | std::cout << (global_buffer ? *(int*) global_buffer : 0) << '\t';
70 | std::cout << global_buffer << std::endl;
71 | }
72 | }
73 | }
74 |
75 | int main() throw (std::invalid_argument)
76 | {
77 | load_config();
78 | print_config(stderr);
79 |
80 | Ssd ssd;
81 |
82 | std::clog << "INITIALIZING SSD" << std::endl;
83 |
84 | debug(ssd);
85 | }
86 |
87 |
--------------------------------------------------------------------------------
/run_raid.cpp:
--------------------------------------------------------------------------------
1 | /* Copyright 2012 Matias Bjørling */
2 |
3 | /* FlashSim is free software: you can redistribute it and/or modify
4 | * it under the terms of the GNU General Public License as published by
5 | * the Free Software Foundation, either version 3 of the License, or
6 | * any later version. */
7 |
8 | /* FlashSim is distributed in the hope that it will be useful,
9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 | * GNU General Public License for more details. */
12 |
13 | /* You should have received a copy of the GNU General Public License
14 | * along with FlashSim. If not, see . */
15 |
16 | /****************************************************************************/
17 |
18 | #include "ssd.h"
19 |
20 | #define SIZE 10
21 |
22 | using namespace ssd;
23 |
24 | int main()
25 | {
26 | load_config();
27 | print_config(NULL);
28 |
29 | RaidSsd *ssd = new RaidSsd();
30 |
31 | double result;
32 | double cur_time = 1;
33 |
34 | for (int i = 0; i < SIZE; i++)
35 | {
36 | result = ssd -> event_arrive(WRITE, i*2, 1, 0);
37 | cur_time += result;
38 | }
39 | for (int i = 0; i < SIZE; i++)
40 | {
41 | result = ssd -> event_arrive(READ, i*2, 1, 0);
42 | cur_time += result;
43 | }
44 |
45 | printf("Total execution time %f\n", cur_time);
46 |
47 | delete ssd;
48 | return 0;
49 | }
50 |
--------------------------------------------------------------------------------
/run_test.cpp:
--------------------------------------------------------------------------------
1 | /* Copyright 2009, 2010 Brendan Tauras */
2 |
3 | /* run_test.cpp is part of FlashSim. */
4 |
5 | /* FlashSim is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published by
7 | * the Free Software Foundation, either version 3 of the License, or
8 | * any later version. */
9 |
10 | /* FlashSim is distributed in the hope that it will be useful,
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * GNU General Public License for more details. */
14 |
15 | /* You should have received a copy of the GNU General Public License
16 | * along with FlashSim. If not, see . */
17 |
18 | /****************************************************************************/
19 |
20 | /* Basic test driver
21 | * Brendan Tauras 2009-11-02
22 | *
23 | * driver to create and run a very basic test of writes then reads */
24 |
25 | #include "ssd.h"
26 |
27 | #define SIZE 130
28 |
29 | using namespace ssd;
30 |
31 | int main()
32 | {
33 | load_config();
34 | print_config(NULL);
35 | //printf("Press ENTER to continue...");
36 | //getchar();
37 | printf("\n");
38 |
39 | Ssd *ssd = new Ssd();
40 |
41 | double result;
42 |
43 | // // Test one write to some blocks.
44 | // for (int i = 0; i < SIZE; i++)
45 | // {
46 | // /* event_arrive(event_type, logical_address, size, start_time) */
47 | // result = ssd -> event_arrive(WRITE, i*100000, 1, (double) 1+(250*i));
48 | //
49 | // printf("Write time: %.20lf\n", result);
50 | //// result = ssd -> event_arrive(WRITE, i+10240, 1, (double) 1);
51 | ////
52 | // }
53 | // for (int i = 0; i < SIZE; i++)
54 | // {
55 | // /* event_arrive(event_type, logical_address, size, start_time) */
56 | // result = ssd -> event_arrive(READ, i*100000, 1, (double) 1+(500*i));
57 | // printf("Read time : %.20lf\n", result);
58 | //// result = ssd -> event_arrive(READ, i, 1, (double) 1);
59 | //// printf("Read time : %.20lf\n", result);
60 | // }
61 |
62 | // // Test writes and read to same block.
63 | // for (int i = 0; i < SIZE; i++)
64 | // {
65 | // result = ssd -> event_arrive(WRITE, i%64, 1, (double) 1+(250*i));
66 | //
67 | // printf("Write time: %.20lf\n", result);
68 | // }
69 | // for (int i = 0; i < SIZE; i++)
70 | // {
71 | // result = ssd -> event_arrive(READ, i%64, 1, (double) 1+(500*i));
72 | // printf("Read time : %.20lf\n", result);
73 | // }
74 |
75 | // Test random writes to a block
76 | result = ssd -> event_arrive(WRITE, 5, 1, (double) 0.0);
77 | printf("Write time: %.20lf\n", result);
78 | result = ssd -> event_arrive(WRITE, 4, 1, (double) 300.0);
79 | printf("Write time: %.20lf\n", result);
80 | result = ssd -> event_arrive(WRITE, 3, 1, (double) 600.0);
81 | printf("Write time: %.20lf\n", result);
82 | result = ssd -> event_arrive(WRITE, 2, 1, (double) 900.0);
83 | printf("Write time: %.20lf\n", result);
84 | result = ssd -> event_arrive(WRITE, 1, 1, (double) 1200.0);
85 | printf("Write time: %.20lf\n", result);
86 | result = ssd -> event_arrive(WRITE, 0, 1, (double) 1500.0);
87 | printf("Write time: %.20lf\n", result);
88 |
89 | for (int i = 0; i < SIZE-6; i++)
90 | {
91 | /* event_arrive(event_type, logical_address, size, start_time) */
92 | result = ssd -> event_arrive(WRITE, 6+i, 1, (double) 1800+(300*i));
93 | printf("Write time: %.20lf\n", result);
94 | }
95 |
96 | // Force Merge
97 | result = ssd -> event_arrive(WRITE, 10 , 1, (double) 0.0);
98 | printf("Write time: %.20lf\n", result);
99 | // for (int i = 0; i < SIZE; i++)
100 | // {
101 | // /* event_arrive(event_type, logical_address, size, start_time) */
102 | // result = ssd -> event_arrive(READ, i%64, 1, (double) 1+(500*i));
103 | // printf("Read time : %.20lf\n", result);
104 | // }
105 |
106 | delete ssd;
107 | return 0;
108 | }
109 |
--------------------------------------------------------------------------------
/run_test2.cpp:
--------------------------------------------------------------------------------
1 | /* Copyright 2009, 2010 Brendan Tauras */
2 |
3 | /* run_test2.cpp is part of FlashSim. */
4 |
5 | /* FlashSim is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published by
7 | * the Free Software Foundation, either version 3 of the License, or
8 | * any later version. */
9 |
10 | /* FlashSim is distributed in the hope that it will be useful,
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * GNU General Public License for more details. */
14 |
15 | /* You should have received a copy of the GNU General Public License
16 | * along with FlashSim. If not, see . */
17 |
18 | /****************************************************************************/
19 |
20 | /* Basic test driver
21 | * Brendan Tauras 2010-08-03
22 | *
23 | * driver to create and run a very basic test of writes then reads */
24 |
25 | #include "ssd.h"
26 |
27 | #define SIZE 10
28 |
29 | using namespace ssd;
30 |
31 | int main()
32 | {
33 | load_config();
34 | print_config(NULL);
35 | printf("Press ENTER to continue...");
36 | getchar();
37 | printf("\n");
38 |
39 | Ssd *ssd = new Ssd();
40 |
41 | double result;
42 | double cur_time = 1;
43 | double delta = BUS_DATA_DELAY - 2 > 0 ? BUS_DATA_DELAY - 2 : BUS_DATA_DELAY;
44 |
45 | for (int i = 0; i < SIZE; i++, cur_time += delta)
46 | {
47 | /* event_arrive(event_type, logical_address, size, start_time) */
48 | result = ssd -> event_arrive(WRITE, i, 1, cur_time);
49 | result = ssd -> event_arrive(WRITE, i+10240, 1, cur_time);
50 | }
51 | for (int i = 0; i < SIZE; i++, cur_time += delta)
52 | {
53 | /* event_arrive(event_type, logical_address, size, start_time) */
54 | result = ssd -> event_arrive(READ, 1, 1, cur_time);
55 | result = ssd -> event_arrive(READ, i, 1, cur_time);
56 | }
57 | delete ssd;
58 | return 0;
59 | }
60 |
--------------------------------------------------------------------------------
/run_ufliptrace.cpp:
--------------------------------------------------------------------------------
1 | /* FlashSim is free software: you can redistribute it and/or modify
2 | * it under the terms of the GNU General Public License as published by
3 | * the Free Software Foundation, either version 3 of the License, or
4 | * any later version. */
5 |
6 | /* FlashSim is distributed in the hope that it will be useful,
7 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
8 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 | * GNU General Public License for more details. */
10 |
11 | /* You should have received a copy of the GNU General Public License
12 | * along with FlashSim. If not, see . */
13 |
14 | /****************************************************************************/
15 |
16 |
17 |
18 | #include
19 | #include
20 | #include
21 | #include
22 | #include
23 | #include
24 | #include
25 | #include
26 | #include "ssd.h"
27 |
28 | using namespace ssd;
29 |
30 | int main(int argc, char **argv){
31 |
32 | long vaddr;
33 | ssd::uint queryTime;
34 | char ioPatternType; // (S)equential or (R)andom
35 | char ioType; // (R)ead or (W)rite
36 | double arrive_time;
37 | int ioSize;
38 |
39 | char line[80];
40 |
41 | double afterFormatStartTime = 0;
42 |
43 | load_config();
44 | print_config(NULL);
45 |
46 | Ssd ssd;
47 |
48 | printf("INITIALIZING SSD\n");
49 |
50 | int preIO = SSD_SIZE * PACKAGE_SIZE * DIE_SIZE * PLANE_SIZE * BLOCK_SIZE;
51 |
52 | if (FTL_IMPLEMENTATION == 0) // PAGE
53 | preIO -= 16*BLOCK_SIZE;
54 |
55 | if (FTL_IMPLEMENTATION == 1) // BAST
56 | preIO -= (BAST_LOG_BLOCK_LIMIT*BLOCK_SIZE)*1.2;
57 |
58 | if (FTL_IMPLEMENTATION == 2) // FAST
59 | preIO -= (FAST_LOG_BLOCK_LIMIT*BLOCK_SIZE)*1.1;
60 |
61 | if (FTL_IMPLEMENTATION > 2) // DFTL BIFTL
62 | preIO -= 1000;
63 |
64 | //int deviceSize = 2827059;
65 | int deviceSize = 2097024;
66 |
67 | if (preIO > deviceSize)
68 | preIO = deviceSize;
69 |
70 | printf("Writes %i pages for startup out of %i total pages.\n", preIO, SSD_SIZE * PACKAGE_SIZE * DIE_SIZE * PLANE_SIZE * BLOCK_SIZE);
71 |
72 | // srand(1);
73 | // for (int i=0; i files;
92 | struct dirent *dirp;
93 | while ((dirp = readdir(working_directory)) != NULL)
94 | {
95 | if (dirp->d_type == DT_REG)
96 | files.push_back(dirp->d_name);
97 | }
98 |
99 | std::sort(files.begin(), files.end());
100 |
101 | double start_time = afterFormatStartTime;
102 | double timeMultiplier = 10000;
103 |
104 |
105 | long writeEvent = 0;
106 | long readEvent = 0;
107 | for (unsigned int i=0; i.
17 |
18 | ##############################################################################
19 |
20 | # ssd.conf
21 | # FlashSim configuration file
22 | # default values in ssd_config.cpp as used if value is not set in config file
23 |
24 | # Ram class:
25 | # delay to read from and write to the RAM for 1 page of data
26 | RAM_READ_DELAY 0.01
27 | RAM_WRITE_DELAY 0.01
28 |
29 | # Bus class:
30 | # delay to communicate over bus
31 | # max number of connected devices allowed
32 | # number of time entries bus has to keep track of future schedule usage
33 | # number of simultaneous communication channels - defined by SSD_SIZE
34 | BUS_CTRL_DELAY 2
35 | BUS_DATA_DELAY 10
36 | BUS_MAX_CONNECT 8
37 | BUS_TABLE_SIZE 512
38 |
39 | # Ssd class:
40 | # number of Packages per Ssd (size)
41 | SSD_SIZE 1
42 |
43 | # Package class:
44 | # number of Dies per Package (size)
45 | PACKAGE_SIZE 2
46 |
47 | # Die class:
48 | # number of Planes per Die (size)
49 | DIE_SIZE 2
50 |
51 | # Plane class:
52 | # number of Blocks per Plane (size)
53 | # delay for reading from plane register
54 | # delay for writing to plane register
55 | # delay for merging is based on read, write, reg_read, reg_write
56 | # and does not need to be explicitly defined
57 | PLANE_SIZE 256
58 | PLANE_REG_READ_DELAY 0.01
59 | PLANE_REG_WRITE_DELAY 0.01
60 |
61 | # Block class:
62 | # number of Pages per Block (size)
63 | # number of erases in lifetime of block
64 | # delay for erasing block
65 | BLOCK_SIZE 64
66 | BLOCK_ERASES 100000
67 | BLOCK_ERASE_DELAY 2000
68 |
69 | # Page class:
70 | # delay for Page reads
71 | # delay for Page writes
72 | # -- A 64bit kernel is required if data pages are used. --
73 | # Allocate actual data for pages
74 | # Size of pages (in bytes)
75 | PAGE_READ_DELAY 25
76 | PAGE_WRITE_DELAY 300
77 | PAGE_ENABLE_DATA 1
78 |
79 | # MAPPING
80 | # Specify reservation of
81 | # blocks for mapping purposes.
82 | MAP_DIRECTORY_SIZE 100
83 |
84 | # FTL Implementation to use 0 = Page, 1 = BAST,
85 | # 2 = FAST, 3 = DFTL, 4 = Bimodal
86 | FTL_IMPLEMENTATION 3
87 |
88 | # LOG Block limit for BAST
89 | BAST_LOG_BLOCK_LIMIT 1024
90 |
91 | # LOG Block limit for FAST
92 | FAST_LOG_BLOCK_LIMIT 1024
93 |
94 | # Number of pages allowed to be in DFTL Cached Mapping Table.
95 | CACHE_DFTL_LIMIT 512
96 |
97 | # 0 -> Normal behavior, 1 -> Striping, 2 -> Logical address space parallelism
98 | PARALLELISM_MODE 2
99 |
100 | # Written in round robin: Virtual block size (as a multiple of the physical block size)
101 | VIRTUAL_BLOCK_SIZE 1
102 |
103 | # Striping: Virtual page size (as a multiple of the physical page size)
104 | VIRTUAL_PAGE_SIZE 1
105 |
106 | # RAISSDs: Number of physical SSDs
107 | RAID_NUMBER_OF_PHYSICAL_SSDS 2
108 |
109 |
--------------------------------------------------------------------------------
/ssd.conf.testing:
--------------------------------------------------------------------------------
1 | # Copyright 2009, 2010 Brendan Tauras
2 |
3 | # ssd.conf.testing is part of FlashSim.
4 |
5 | # FlashSim is free software: you can redistribute it and/or modify
6 | # it under the terms of the GNU General Public License as published by
7 | # the Free Software Foundation, either version 3 of the License, or
8 | # any later version.
9 |
10 | # FlashSim is distributed in the hope that it will be useful,
11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | # GNU General Public License for more details.
14 |
15 | # You should have received a copy of the GNU General Public License
16 | # along with FlashSim. If not, see .
17 |
18 | ##############################################################################
19 |
20 | # ssd.conf
21 | # FlashSim configuration file
22 | # default values in ssd_config.cpp as used if value is not set in config file
23 |
24 |
25 | # Ram class:
26 | # delay to read from and write to the RAM for 1 page of data
27 | RAM_READ_DELAY 1
28 | RAM_WRITE_DELAY 8
29 |
30 | # Bus class:
31 | # delay to communicate over bus
32 | # max number of connected devices allowed
33 | # number of time entries bus has to keep track of future schedule usage
34 | # number of simultaneous communication channels - defined by SSD_SIZE
35 | BUS_CTRL_DELAY 10
36 | BUS_DATA_DELAY 20
37 | BUS_MAX_CONNECT 8
38 | BUS_TABLE_SIZE 64
39 |
40 | # Ssd class:
41 | # number of Packages per Ssd (size)
42 | SSD_SIZE 4
43 |
44 | # Package class:
45 | # number of Dies per Package (size)
46 | PACKAGE_SIZE 8
47 |
48 | # Die class:
49 | # number of Planes per Die (size)
50 | DIE_SIZE 2
51 |
52 | # Plane class:
53 | # number of Blocks per Plane (size)
54 | # delay for reading from plane register
55 | # delay for writing to plane register
56 | # delay for merging is based on read, write, reg_read, reg_write
57 | # and does not need to be explicitly defined
58 | PLANE_SIZE 64
59 | PLANE_REG_READ_DELAY 1
60 | PLANE_REG_WRITE_DELAY 1
61 |
62 | # Block class:
63 | # number of Pages per Block (size)
64 | # number of erases in lifetime of block
65 | # delay for erasing block
66 | BLOCK_SIZE 16
67 | BLOCK_ERASES 1048675
68 | BLOCK_ERASE_DELAY 32
69 |
70 | # Page class:
71 | # delay for Page reads
72 | # delay for Page writes
73 | PAGE_READ_DELAY 4
74 | PAGE_WRITE_DELAY 12
75 |
--------------------------------------------------------------------------------
/ssd_address.cpp:
--------------------------------------------------------------------------------
1 | /* Copyright 2009, 2010 Brendan Tauras */
2 |
3 | /* ssd_address.cpp is part of FlashSim. */
4 |
5 | /* FlashSim is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published by
7 | * the Free Software Foundation, either version 3 of the License, or
8 | * any later version. */
9 |
10 | /* FlashSim is distributed in the hope that it will be useful,
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * GNU General Public License for more details. */
14 |
15 | /* You should have received a copy of the GNU General Public License
16 | * along with FlashSim. If not, see . */
17 |
18 | /****************************************************************************/
19 |
20 | /* Address class
21 | * Brendan Tauras 2009-06-19
22 | *
23 | * Class to manage physical addresses for the SSD. It was designed to have
24 | * public members like a struct for quick access but also have checking,
25 | * printing, and assignment functionality. An instance is created for each
26 | * physical address in the Event class.
27 | */
28 |
29 | #include
30 | #include "ssd.h"
31 |
32 | using namespace ssd;
33 |
34 | Address::Address(void):
35 | package(0),
36 | die(0),
37 | plane(0),
38 | block(0),
39 | page(0),
40 | valid(NONE)
41 | {
42 | return;
43 | }
44 |
45 | Address::Address(const Address &address)
46 | {
47 | *this = address;
48 | return;
49 | }
50 |
51 | Address::Address(const Address *address)
52 | {
53 | *this = *address;
54 | return;
55 | }
56 |
57 | /* see "enum address_valid" in ssd.h for details on valid status */
58 | Address::Address(uint package, uint die, uint plane, uint block, uint page, enum address_valid valid):
59 | package(package),
60 | die(die),
61 | plane(plane),
62 | block(block),
63 | page(page),
64 | valid(valid)
65 | {
66 | return;
67 | }
68 |
69 | Address::Address(uint address, enum address_valid valid):
70 | valid(valid)
71 | {
72 | assert(address >= 0);
73 | set_linear_address(address);
74 | }
75 |
76 | Address::~Address()
77 | {
78 | return;
79 | }
80 |
81 | /* default values for parameters are the global settings
82 | * see "enum address_valid" in ssd.h for details on valid status
83 | * note that method only checks for out-of-bounds types of errors */
84 | enum address_valid Address::check_valid(uint ssd_size, uint package_size, uint die_size, uint plane_size, uint block_size)
85 | {
86 | enum address_valid tmp = NONE;
87 |
88 | /* must check current valid status first
89 | * so we cannot expand the valid status */
90 | if(valid >= PACKAGE && package < ssd_size)
91 | {
92 | tmp = PACKAGE;
93 | if(valid >= DIE && die < package_size)
94 | {
95 | tmp = DIE;
96 | if(valid >= PLANE && plane < die_size)
97 | {
98 | tmp = PLANE;
99 | if(valid >= BLOCK && block < plane_size)
100 | {
101 | tmp = BLOCK;
102 | if(valid >= PAGE && page < block_size)
103 | tmp = PAGE;
104 | }
105 | }
106 | }
107 | }
108 | else
109 | tmp = NONE;
110 | valid = tmp;
111 | return valid;
112 | }
113 |
114 | /* returns enum indicating to what level two addresses match
115 | * limits comparison to the fields that are valid */
116 | enum address_valid Address::compare(const Address &address) const
117 | {
118 | enum address_valid match = NONE;
119 | if(package == address.package && valid >= PACKAGE && address.valid >= PACKAGE)
120 | {
121 | match = PACKAGE;
122 | if(die == address.die && valid >= DIE && address.valid >= DIE)
123 | {
124 | match = DIE;
125 | if(plane == address.plane && valid >= PLANE && address.valid >= PLANE)
126 | {
127 | match = PLANE;
128 | if(block == address.block && valid >= BLOCK && address.valid >= BLOCK)
129 | {
130 | match = BLOCK;
131 | if(page == address.page && valid >= PAGE && address.valid >= PAGE)
132 | {
133 | match = PAGE;
134 | }
135 | }
136 | }
137 | }
138 | }
139 | return match;
140 | }
141 |
142 | /* default stream is stdout */
143 | void Address::print(FILE *stream)
144 | {
145 | fprintf(stream, "(%d, %d, %d, %d, %d, %d)", package, die, plane, block, page, (int) valid);
146 | return;
147 | }
148 |
149 | void Address::set_linear_address(ulong address)
150 | {
151 | real_address = address;
152 | page = address % BLOCK_SIZE;
153 | address /= BLOCK_SIZE;
154 | block = address % PLANE_SIZE;
155 | address /= PLANE_SIZE;
156 | plane = address % DIE_SIZE;
157 | address /= DIE_SIZE;
158 | die = address % PACKAGE_SIZE;
159 | address /= PACKAGE_SIZE;
160 | package = address % SSD_SIZE;
161 | address /= SSD_SIZE;
162 | }
163 |
164 | void Address::set_linear_address(ulong address, enum address_valid valid)
165 | {
166 | set_linear_address(address);
167 | this->valid = valid;
168 | }
169 |
170 | unsigned long Address::get_linear_address() const
171 | {
172 | return real_address;
173 | }
174 |
175 | void Address::operator+(int i)
176 | {
177 | set_linear_address(real_address + i);
178 | }
179 |
180 | void Address::operator+(uint i)
181 | {
182 | set_linear_address(real_address + i);
183 | }
184 |
185 | Address &Address::operator+=(const uint i)
186 | {
187 | set_linear_address(real_address + i);
188 | return *this;
189 | }
190 |
191 |
192 | Address &Address::operator=(const Address &rhs)
193 | {
194 | if(this == &rhs)
195 | return *this;
196 | package = rhs.package;
197 | die = rhs.die;
198 | plane = rhs.plane;
199 | block = rhs.block;
200 | page = rhs.page;
201 | valid = rhs.valid;
202 | real_address = rhs.real_address;
203 | return *this;
204 | }
205 |
--------------------------------------------------------------------------------
/ssd_block.cpp:
--------------------------------------------------------------------------------
1 | /* Copyright 2009, 2010 Brendan Tauras */
2 |
3 | /* ssd_block.cpp is part of FlashSim. */
4 |
5 | /* FlashSim is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published by
7 | * the Free Software Foundation, either version 3 of the License, or
8 | * any later version. */
9 |
10 | /* FlashSim is distributed in the hope that it will be useful,
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * GNU General Public License for more details. */
14 |
15 | /* You should have received a copy of the GNU General Public License
16 | * along with FlashSim. If not, see . */
17 |
18 | /****************************************************************************/
19 |
20 | /* Block class
21 | * Brendan Tauras 2009-10-26
22 | *
23 | * The block is the data storage hardware unit where erases are implemented.
24 | * Blocks maintain wear statistics for the FTL. */
25 |
26 | #include
27 | #include
28 | #include
29 | #include "ssd.h"
30 |
31 | using namespace ssd;
32 |
33 | Block::Block(const Plane &parent, uint block_size, ulong erases_remaining, double erase_delay, long physical_address):
34 | pages_invalid(0),
35 | physical_address(physical_address),
36 | size(block_size),
37 |
38 | /* use a const pointer (Page * const data) to use as an array
39 | * but like a reference, we cannot reseat the pointer */
40 | data((Page *) malloc(block_size * sizeof(Page))),
41 | parent(parent),
42 | pages_valid(0),
43 |
44 | state(FREE),
45 |
46 | /* set erases remaining to BLOCK_ERASES to match Block constructor args
47 | * in Plane class
48 | * this is the cheap implementation but can change to pass through classes */
49 | erases_remaining(erases_remaining),
50 |
51 | /* assume hardware created at time 0 and had an implied free erasure */
52 | last_erase_time(0.0),
53 | erase_delay(erase_delay),
54 |
55 | modification_time(-1)
56 |
57 | {
58 | uint i;
59 |
60 | if(erase_delay < 0.0)
61 | {
62 | fprintf(stderr, "Block warning: %s: constructor received negative erase delay value\n\tsetting erase delay to 0.0\n", __func__);
63 | erase_delay = 0.0;
64 | }
65 |
66 | /* new cannot initialize an array with constructor args so
67 | * malloc the array
68 | * then use placement new to call the constructor for each element
69 | * chose an array over container class so we don't have to rely on anything
70 | * i.e. STL's std::vector */
71 | /* array allocated in initializer list:
72 | * data = (Page *) malloc(size * sizeof(Page)); */
73 | if(data == NULL){
74 | fprintf(stderr, "Block error: %s: constructor unable to allocate Page data\n", __func__);
75 | exit(MEM_ERR);
76 | }
77 |
78 | for(i = 0; i < size; i++)
79 | (void) new (&data[i]) Page(*this, PAGE_READ_DELAY, PAGE_WRITE_DELAY);
80 |
81 | // Creates the active cost structure in the block manager.
82 | // It assumes that it is created lineary.
83 | Block_manager::instance()->cost_insert(this);
84 |
85 | return;
86 | }
87 |
88 | Block::~Block(void)
89 | {
90 | assert(data != NULL);
91 | uint i;
92 | /* call destructor for each Page array element
93 | * since we used malloc and placement new */
94 | for(i = 0; i < size; i++)
95 | data[i].~Page();
96 | free(data);
97 | return;
98 | }
99 |
100 | enum status Block::read(Event &event)
101 | {
102 | assert(data != NULL);
103 | return data[event.get_address().page]._read(event);
104 | }
105 |
106 | enum status Block::write(Event &event)
107 | {
108 | assert(data != NULL);
109 | enum status ret = data[event.get_address().page]._write(event);
110 |
111 | if(event.get_noop() == false)
112 | {
113 | pages_valid++;
114 | state = ACTIVE;
115 | modification_time = event.get_start_time();
116 |
117 | Block_manager::instance()->update_block(this);
118 | }
119 | return ret;
120 | }
121 |
122 | enum status Block::replace(Event &event)
123 | {
124 | invalidate_page(event.get_replace_address().page);
125 | return SUCCESS;
126 | }
127 |
128 | /* updates Event time_taken
129 | * sets Page statuses to EMPTY
130 | * updates last_erase_time and erases_remaining
131 | * returns 1 for success, 0 for failure */
132 | enum status Block::_erase(Event &event)
133 | {
134 | assert(data != NULL && erase_delay >= 0.0);
135 | uint i;
136 |
137 | if (!event.get_noop())
138 | {
139 | if(erases_remaining < 1)
140 | {
141 | fprintf(stderr, "Block error: %s: No erases remaining when attempting to erase\n", __func__);
142 | return FAILURE;
143 | }
144 |
145 | for(i = 0; i < size; i++)
146 | {
147 | //assert(data[i].get_state() == INVALID);
148 | data[i].set_state(EMPTY);
149 | }
150 |
151 |
152 | event.incr_time_taken(erase_delay);
153 | last_erase_time = event.get_start_time() + event.get_time_taken();
154 | erases_remaining--;
155 | pages_valid = 0;
156 | pages_invalid = 0;
157 | state = FREE;
158 |
159 | Block_manager::instance()->update_block(this);
160 | }
161 |
162 | return SUCCESS;
163 | }
164 |
165 | const Plane &Block::get_parent(void) const
166 | {
167 | return parent;
168 | }
169 |
170 | ssd::uint Block::get_pages_valid(void) const
171 | {
172 | return pages_valid;
173 | }
174 |
175 | ssd::uint Block::get_pages_invalid(void) const
176 | {
177 | return pages_invalid;
178 | }
179 |
180 |
181 | enum block_state Block::get_state(void) const
182 | {
183 | return state;
184 | }
185 |
186 | enum page_state Block::get_state(uint page) const
187 | {
188 | assert(data != NULL && page < size);
189 | return data[page].get_state();
190 | }
191 |
192 | enum page_state Block::get_state(const Address &address) const
193 | {
194 | assert(data != NULL && address.page < size && address.valid >= BLOCK);
195 | return data[address.page].get_state();
196 | }
197 |
198 | double Block::get_last_erase_time(void) const
199 | {
200 | return last_erase_time;
201 | }
202 |
203 | ssd::ulong Block::get_erases_remaining(void) const
204 | {
205 | return erases_remaining;
206 | }
207 |
208 | ssd::uint Block::get_size(void) const
209 | {
210 | return size;
211 | }
212 |
213 | void Block::invalidate_page(uint page)
214 | {
215 | assert(page < size);
216 |
217 | if (data[page].get_state() == INVALID )
218 | return;
219 |
220 | //assert(data[page].get_state() == VALID);
221 |
222 | data[page].set_state(INVALID);
223 |
224 | pages_invalid++;
225 |
226 | Block_manager::instance()->update_block(this);
227 |
228 | /* update block state */
229 | if(pages_invalid >= size)
230 | state = INACTIVE;
231 | else if(pages_valid > 0 || pages_invalid > 0)
232 | state = ACTIVE;
233 | else
234 | state = FREE;
235 |
236 | return;
237 | }
238 |
239 | double Block::get_modification_time(void) const
240 | {
241 | return modification_time;
242 | }
243 |
244 | /* method to find the next usable (empty) page in this block
245 | * method is called by write and erase methods and in Plane::get_next_page() */
246 | enum status Block::get_next_page(Address &address) const
247 | {
248 | uint i;
249 |
250 | for(i = 0; i < size; i++)
251 | {
252 | if(data[i].get_state() == EMPTY)
253 | {
254 | address.set_linear_address(i + physical_address - physical_address % BLOCK_SIZE, PAGE);
255 | return SUCCESS;
256 | }
257 | }
258 | return FAILURE;
259 | }
260 |
261 | long Block::get_physical_address(void) const
262 | {
263 | return physical_address;
264 | }
265 |
266 | Block *Block::get_pointer(void)
267 | {
268 | return this;
269 | }
270 |
271 | block_type Block::get_block_type(void) const
272 | {
273 | return this->btype;
274 | }
275 |
276 | void Block::set_block_type(block_type value)
277 | {
278 | this->btype = value;
279 | }
280 |
--------------------------------------------------------------------------------
/ssd_bm.cpp:
--------------------------------------------------------------------------------
1 | /* Copyright 2011 Matias Bjørling */
2 |
3 | /* Block Management
4 | *
5 | * This class handle allocation of block pools for the FTL
6 | * algorithms.
7 | */
8 |
9 | #include
10 | #include
11 | #include
12 | #include
13 | #include
14 | #include
15 | #include
16 | #include "ssd.h"
17 |
18 | using namespace ssd;
19 |
20 |
21 | Block_manager::Block_manager(FtlParent *ftl) : ftl(ftl)
22 | {
23 | /*
24 | * Configuration of blocks.
25 | * User-space is the number of blocks minus the
26 | * requirements for map directory.
27 | */
28 |
29 | max_blocks = NUMBER_OF_ADDRESSABLE_BLOCKS;
30 | max_log_blocks = max_blocks;
31 |
32 | if (FTL_IMPLEMENTATION == IMPL_FAST)
33 | max_log_blocks = FAST_LOG_BLOCK_LIMIT;
34 |
35 | // Block-based map lookup simulation
36 | max_map_pages = MAP_DIRECTORY_SIZE * BLOCK_SIZE;
37 |
38 | directoryCurrentPage = 0;
39 | num_insert_events = 0;
40 |
41 | data_active = 0;
42 | log_active = 0;
43 |
44 | current_writing_block = -2;
45 |
46 | out_of_blocks = false;
47 |
48 | simpleCurrentFree = 0;
49 |
50 | active_cost.reserve(NUMBER_OF_ADDRESSABLE_BLOCKS);
51 | }
52 |
53 | Block_manager::~Block_manager(void)
54 | {
55 | return;
56 | }
57 |
58 | void Block_manager::cost_insert(Block *b)
59 | {
60 | active_cost.push_back(b);
61 | }
62 |
63 | void Block_manager::instance_initialize(FtlParent *ftl)
64 | {
65 | Block_manager::inst = new Block_manager(ftl);
66 | }
67 |
68 | Block_manager *Block_manager::instance()
69 | {
70 | return Block_manager::inst;
71 | }
72 |
73 | /*
74 | * Retrieves a page using either simple approach (when not all
75 | * pages have been written or the complex that retrieves
76 | * it from a free page list.
77 | */
78 | void Block_manager::get_page_block(Address &address, Event &event)
79 | {
80 | // We need separate queues for each plane? communication channel? communication channel is at the per die level at the moment. i.e. each LUN is a die.
81 |
82 | if (simpleCurrentFree < max_blocks*BLOCK_SIZE)
83 | {
84 | address.set_linear_address(simpleCurrentFree, BLOCK);
85 | current_writing_block = simpleCurrentFree;
86 | simpleCurrentFree += BLOCK_SIZE;
87 | }
88 | else
89 | {
90 | if (free_list.size() <= 1 && !out_of_blocks)
91 | {
92 | out_of_blocks = true;
93 | insert_events(event);
94 | }
95 |
96 | assert(free_list.size() != 0);
97 | address.set_linear_address(free_list.front()->get_physical_address(), BLOCK);
98 | current_writing_block = free_list.front()->get_physical_address();
99 | free_list.erase(free_list.begin());
100 | out_of_blocks = false;
101 | }
102 | }
103 |
104 |
105 | Address Block_manager::get_free_block(Event &event)
106 | {
107 | return get_free_block(DATA, event);
108 | }
109 |
110 | /*
111 | * Handles block manager statistics when changing a
112 | * block to a data block from a log block or vice versa.
113 | */
114 | void Block_manager::promote_block(block_type to_type)
115 | {
116 | if (to_type == DATA)
117 | {
118 | data_active++;
119 | log_active--;
120 | }
121 | else if (to_type == LOG)
122 | {
123 | log_active++;
124 | data_active--;
125 | }
126 | }
127 |
128 | /*
129 | * Returns true if there are no space left for additional log pages.
130 | */
131 | bool Block_manager::is_log_full()
132 | {
133 | return log_active == max_log_blocks;
134 | }
135 |
136 | void Block_manager::print_statistics()
137 | {
138 | printf("-----------------\n");
139 | printf("Block Statistics:\n");
140 | printf("-----------------\n");
141 | printf("Log blocks: %lu\n", log_active);
142 | printf("Data blocks: %lu\n", data_active);
143 | printf("Free blocks: %lu\n", (max_blocks - (simpleCurrentFree/BLOCK_SIZE)) + free_list.size());
144 | printf("Invalid blocks: %lu\n", invalid_list.size());
145 | printf("Free2 blocks: %lu\n", (unsigned long int)invalid_list.size() + (unsigned long int)log_active + (unsigned long int)data_active - (unsigned long int)free_list.size());
146 | printf("-----------------\n");
147 |
148 |
149 | }
150 |
151 | void Block_manager::invalidate(Address address, block_type type)
152 | {
153 | invalid_list.push_back(ftl->get_block_pointer(address));
154 |
155 | switch (type)
156 | {
157 | case DATA:
158 | data_active--;
159 | break;
160 | case LOG:
161 | log_active--;
162 | break;
163 | case LOG_SEQ:
164 | break;
165 | }
166 | }
167 |
168 | /*
169 | * Insert erase events into the event stream.
170 | * The strategy is to clean up all invalid pages instantly.
171 | */
172 | void Block_manager::insert_events(Event &event)
173 | {
174 | // Calculate if GC should be activated.
175 | float used = (int)invalid_list.size() + (int)log_active + (int)data_active - (int)free_list.size();
176 | float total = NUMBER_OF_ADDRESSABLE_BLOCKS;
177 | float ratio = used/total;
178 |
179 | if (ratio < 0.90) // Magic number
180 | return;
181 |
182 | uint num_to_erase = 5; // More Magic!
183 |
184 | //printf("%i %i %i\n", invalid_list.size(), log_active, data_active);
185 |
186 | // First step and least expensive is to go though invalid list. (Only used by FAST)
187 | while (num_to_erase != 0 && invalid_list.size() != 0)
188 | {
189 | Event erase_event = Event(ERASE, event.get_logical_address(), 1, event.get_start_time());
190 | erase_event.set_address(Address(invalid_list.back()->get_physical_address(), BLOCK));
191 | if (ftl->controller.issue(erase_event) == FAILURE) { assert(false);}
192 | event.incr_time_taken(erase_event.get_time_taken());
193 |
194 | free_list.push_back(invalid_list.back());
195 | invalid_list.pop_back();
196 |
197 | num_to_erase--;
198 | ftl->controller.stats.numFTLErase++;
199 | }
200 |
201 | num_insert_events++;
202 |
203 | if (FTL_IMPLEMENTATION == IMPL_DFTL || FTL_IMPLEMENTATION == IMPL_BIMODAL)
204 | {
205 |
206 | ActiveByCost::iterator it = active_cost.get<1>().end();
207 | --it;
208 |
209 |
210 | while (num_to_erase != 0 && (*it)->get_pages_invalid() > 0 && (*it)->get_pages_valid() == BLOCK_SIZE)
211 | {
212 | if (current_writing_block != (*it)->physical_address)
213 | {
214 | //printf("erase p: %p phy: %li ratio: %i num: %i\n", (*it), (*it)->physical_address, (*it)->get_pages_invalid(), num_to_erase);
215 | Block *blockErase = (*it);
216 |
217 | // Let the FTL handle cleanup of the block.
218 | ftl->cleanup_block(event, blockErase);
219 |
220 | // Create erase event and attach to current event queue.
221 | Event erase_event = Event(ERASE, event.get_logical_address(), 1, event.get_start_time());
222 | erase_event.set_address(Address(blockErase->get_physical_address(), BLOCK));
223 |
224 | // Execute erase
225 | if (ftl->controller.issue(erase_event) == FAILURE) { assert(false); }
226 |
227 | free_list.push_back(blockErase);
228 |
229 | event.incr_time_taken(erase_event.get_time_taken());
230 |
231 | ftl->controller.stats.numFTLErase++;
232 | }
233 |
234 | it = active_cost.get<1>().end();
235 | --it;
236 |
237 | if (current_writing_block == (*it)->physical_address)
238 | --it;
239 |
240 | num_to_erase--;
241 | }
242 | }
243 | }
244 |
245 | Address Block_manager::get_free_block(block_type type, Event &event)
246 | {
247 | Address address;
248 | get_page_block(address, event);
249 | switch (type)
250 | {
251 | case DATA:
252 | ftl->controller.get_block_pointer(address)->set_block_type(DATA);
253 | data_active++;
254 | break;
255 | case LOG:
256 | if (log_active > max_log_blocks)
257 | throw std::bad_alloc();
258 |
259 | ftl->controller.get_block_pointer(address)->set_block_type(LOG);
260 | log_active++;
261 | break;
262 | default:
263 | break;
264 | }
265 |
266 | return address;
267 | }
268 |
269 | void Block_manager::print_cost_status()
270 | {
271 |
272 | ActiveByCost::iterator it = active_cost.get<1>().begin();
273 |
274 | for (uint i=0;i<10;i++) //SSD_SIZE*PACKAGE_SIZE*DIE_SIZE*PLANE_SIZE
275 | {
276 | printf("%li %i %i\n", (*it)->physical_address, (*it)->get_pages_valid(), (*it)->get_pages_invalid());
277 | ++it;
278 | }
279 |
280 | printf("end:::\n");
281 |
282 | it = active_cost.get<1>().end();
283 | --it;
284 |
285 | for (uint i=0;i<10;i++) //SSD_SIZE*PACKAGE_SIZE*DIE_SIZE*PLANE_SIZE
286 | {
287 | printf("%li %i %i\n", (*it)->physical_address, (*it)->get_pages_valid(), (*it)->get_pages_invalid());
288 | --it;
289 | }
290 | }
291 |
292 | void Block_manager::erase_and_invalidate(Event &event, Address &address, block_type btype)
293 | {
294 | Event erase_event = Event(ERASE, event.get_logical_address(), 1, event.get_start_time()+event.get_time_taken());
295 | erase_event.set_address(address);
296 |
297 | if (ftl->controller.issue(erase_event) == FAILURE) { assert(false);}
298 |
299 | free_list.push_back(ftl->get_block_pointer(address));
300 |
301 | switch (btype)
302 | {
303 | case DATA:
304 | data_active--;
305 | break;
306 | case LOG:
307 | log_active--;
308 | break;
309 | case LOG_SEQ:
310 | break;
311 | }
312 |
313 | event.incr_time_taken(erase_event.get_time_taken());
314 | ftl->controller.stats.numFTLErase++;
315 | }
316 |
317 | int Block_manager::get_num_free_blocks()
318 | {
319 | if (simpleCurrentFree < max_blocks*BLOCK_SIZE)
320 | return (simpleCurrentFree / BLOCK_SIZE) + free_list.size();
321 | else
322 | return free_list.size();
323 | }
324 |
325 | void Block_manager::update_block(Block * b)
326 | {
327 | std::size_t pos = (b->physical_address / BLOCK_SIZE);
328 | active_cost.replace(active_cost.begin()+pos, b);
329 | }
330 |
--------------------------------------------------------------------------------
/ssd_bus.cpp:
--------------------------------------------------------------------------------
1 | /* Copyright 2009, 2010 Brendan Tauras */
2 |
3 | /* ssd_bus.cpp is part of FlashSim. */
4 |
5 | /* FlashSim is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published by
7 | * the Free Software Foundation, either version 3 of the License, or
8 | * any later version. */
9 |
10 | /* FlashSim is distributed in the hope that it will be useful,
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * GNU General Public License for more details. */
14 |
15 | /* You should have received a copy of the GNU General Public License
16 | * along with FlashSim. If not, see . */
17 |
18 | /****************************************************************************/
19 |
20 | /* Bus class
21 | * Brendan Tauras 2009-04-06
22 | *
23 | * Multi-channel bus comprised of Channel class objects
24 | * Simulates control and data delays by allowing variable channel lock
25 | * durations. The sender (controller class) should specify the delay (control,
26 | * data, or both) for events (i.e. read = ctrl, ctrl+data; write = ctrl+data;
27 | * erase or merge = ctrl). The hardware enable signals are implicitly
28 | * simulated by the sender locking the appropriate bus channel through the lock
29 | * method, then sending to multiple devices by calling the appropriate method
30 | * in the Package class. */
31 |
32 | #include
33 | #include
34 | #include
35 | #include "ssd.h"
36 |
37 | using namespace ssd;
38 |
39 | /* a multi-channel bus: multiple independent channels that operate in parallel
40 | * allocate channels and pass parameters to channels via the lock method
41 | * the table size is synonymous to the queue size for each separate channel
42 | * it is not necessary to use the max connections properly, but it is provided
43 | * to help ensure correctness */
44 | Bus::Bus(uint num_channels, double ctrl_delay, double data_delay, uint table_size, uint max_connections):
45 | num_channels(num_channels),
46 |
47 | /* use a const pointer (Channel * const channels) to use as an array
48 | * but like a reference, we cannot reseat the pointer */
49 | channels((Channel *) malloc(num_channels * sizeof(Channel)))
50 | {
51 | assert(table_size > 0);
52 | if(ctrl_delay < 0.0){
53 | fprintf(stderr, "Bus warning: %s: constructor received negative control delay value\n\tsetting control delay to 0.0\n", __func__);
54 | ctrl_delay = 0.0;
55 | }
56 | if(data_delay < 0.0){
57 | fprintf(stderr, "Bus warning: %s: constructor received negative data delay value\n\tsetting data delay to 0.0\n", __func__);
58 | data_delay = 0.0;
59 | }
60 | uint i;
61 |
62 | /* allocate channels */
63 | /* new cannot initialize an array with constructor args
64 | * malloc the array
65 | * then use placement new to call the constructor for each element
66 | * chose an array over container class so we don't have to rely on anything
67 | * i.e. STL's std::vector */
68 | /* array allocated in initializer list:
69 | * channels = (Channel *) malloc(num_channels * sizeof(Channel)); */
70 | if(channels == NULL)
71 | {
72 | fprintf(stderr, "Bus error: %s: constructor unable to allocate Channels\n", __func__);
73 | exit(MEM_ERR);
74 | }
75 | for(i = 0; i < num_channels; i++)
76 | (void) new (&channels[i]) Channel(ctrl_delay, data_delay, table_size, max_connections);
77 |
78 | return;
79 | }
80 |
81 | /* deallocate channels */
82 | Bus::~Bus(void)
83 | {
84 | assert(channels != NULL);
85 | uint i;
86 | for(i = 0; i < num_channels; i++)
87 | channels[i].~Channel();
88 | free(channels);
89 | return;
90 | }
91 |
92 | /* not required before calling lock()
93 | * but should be used to help ensure correctness
94 | * controller that talks on all channels should not connect/disconnect
95 | * only devices that use a channel should connect/disconnect */
96 | enum status Bus::connect(uint channel)
97 | {
98 | assert(channels != NULL && channel < num_channels);
99 | return channels[channel].connect();
100 | }
101 |
102 | /* not required when finished
103 | * but should be used to help ensure correctness
104 | * controller that talks on all channels should not connect/disconnect
105 | * only devices that use a channel should connect/disconnect */
106 | enum status Bus::disconnect(uint channel)
107 | {
108 | assert(channels != NULL && channel < num_channels);
109 | return channels[channel].disconnect();
110 | }
111 |
112 | /* lock bus channel for event
113 | * updates event with bus delay and bus wait time if there is wait time
114 | * channel will automatically unlock after event is finished using bus
115 | * assumes event is sent across channel as soon as bus is available
116 | * event may fail if channel is saturated so check return value
117 | */
118 | enum status Bus::lock(uint channel, double start_time, double duration, Event &event)
119 | {
120 | assert(channels != NULL && start_time >= 0.0 && duration > 0.0);
121 | return channels[channel].lock(start_time, duration, event);
122 | }
123 |
124 | Channel &Bus::get_channel(uint channel)
125 | {
126 | assert(channels != NULL && channel < num_channels);
127 | return channels[channel];
128 | }
129 |
130 | double Bus::ready_time(uint channel)
131 | {
132 | assert(channels != NULL && channel < num_channels);
133 | return channels[channel].ready_time();
134 | }
135 |
--------------------------------------------------------------------------------
/ssd_channel.cpp:
--------------------------------------------------------------------------------
1 | /* Copyright 2009, 2010 Brendan Tauras */
2 |
3 | /* ssd_channel.cpp is part of FlashSim. */
4 |
5 | /* FlashSim is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published by
7 | * the Free Software Foundation, either version 3 of the License, or
8 | * any later version. */
9 |
10 | /* FlashSim is distributed in the hope that it will be useful,
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * GNU General Public License for more details. */
14 |
15 | /* You should have received a copy of the GNU General Public License
16 | * along with FlashSim. If not, see . */
17 |
18 | /****************************************************************************/
19 |
20 | /* Channel class
21 | * Brendan Tauras 2010-08-09
22 | *
23 | * Single bus channel
24 | * Simulate multiple devices on 1 bus channel with variable bus transmission
25 | * durations for data and control delays with the Channel class. Provide the
26 | * delay times to send a control signal or 1 page of data across the bus
27 | * channel, the bus table size for the maximum number channel transmissions that
28 | * can be queued, and the maximum number of devices that can connect to the bus.
29 | * To elaborate, the table size is the size of the channel scheduling table that
30 | * holds start and finish times of events that have not yet completed in order
31 | * to determine where the next event can be scheduled for bus utilization.
32 | */
33 |
34 | #include
35 | #include
36 | #include
37 | #include
38 | #include
39 | #include "ssd.h"
40 |
41 | using namespace ssd;
42 |
43 | /* a single channel bus: all connected devices share the same channel
44 | * simulates control and data
45 | * enable signals are implicitly simulated by the sender locking the bus
46 | * then sending to multiple devices
47 | * the table size is synonymous to the queue size for the channel
48 | * it is not necessary to use the max connections properly, but it is provided
49 | * to help ensure correctness */
50 | Channel::Channel(double ctrl_delay, double data_delay, uint table_size, uint max_connections):
51 | //table_size(table_size),
52 |
53 | /* use a const pointer (double * const) for the scheduling table arrays
54 | * like a reference, we cannot reseat the pointer */
55 | table_entries(0),
56 | selected_entry(0),
57 | num_connected(0),
58 | max_connections(max_connections),
59 | ctrl_delay(ctrl_delay),
60 | data_delay(data_delay)
61 | {
62 | if(ctrl_delay < 0.0){
63 | fprintf(stderr, "Bus channel warning: %s: constructor received negative control delay value\n\tsetting control delay to 0.0\n", __func__);
64 | ctrl_delay = 0.0;
65 | }
66 | if(data_delay < 0.0){
67 | fprintf(stderr, "Bus channel warning: %s: constructor received negative data delay value\n\tsetting data delay to 0.0\n", __func__);
68 | data_delay = 0.0;
69 | }
70 |
71 | timings.reserve(4096);
72 |
73 | ready_at = -1;
74 | }
75 |
76 | /* free allocated bus channel state space */
77 | Channel::~Channel(void)
78 | {
79 | if(num_connected > 0)
80 | fprintf(stderr, "Bus channel warning: %s: %d connected devices when bus channel terminated\n", __func__, num_connected);
81 | return;
82 | }
83 |
84 | /* not required before calling lock()
85 | * but should be used to help ensure correctness
86 | * controller that talks on all channels should not connect/disconnect
87 | * only components that receive a single channel should connect */
88 | enum status Channel::connect(void)
89 | {
90 | if(num_connected < max_connections)
91 | {
92 | num_connected++;
93 | return SUCCESS;
94 | }
95 | else
96 | {
97 | fprintf(stderr, "Bus channel error: %s: device attempting to connect to channel when %d max devices already connected\n", __func__, max_connections);
98 | return FAILURE;
99 | }
100 | }
101 |
102 | /* not required when finished
103 | * but should be used to help ensure correctness
104 | * controller that talks on all channels should not connect/disconnect
105 | * only components that receive a single channel should connect */
106 | enum status Channel::disconnect(void)
107 | {
108 | if(num_connected > 0)
109 | {
110 | num_connected--;
111 | return SUCCESS;
112 | }
113 | fprintf(stderr, "Bus channel error: %s: device attempting to disconnect from bus channel when no devices connected\n", __func__);
114 | return FAILURE;
115 | }
116 |
117 | /* lock bus channel for event
118 | * updates event with bus delay and bus wait time if there is wait time
119 | * bus will automatically unlock after event is finished using bus
120 | * event is sent across bus as soon as bus channel is available
121 | * event may fail if bus channel is saturated so check return value
122 | */
123 | enum status Channel::lock(double start_time, double duration, Event &event)
124 | {
125 | assert(num_connected <= max_connections);
126 | assert(ctrl_delay >= 0.0);
127 | assert(data_delay >= 0.0);
128 | assert(start_time >= 0.0);
129 | assert(duration >= 0.0);
130 |
131 | /* free up any table slots and sort existing ones */
132 | unlock(start_time);
133 |
134 | double sched_time = BUS_CHANNEL_FREE_FLAG;
135 |
136 | /* just schedule if table is empty */
137 | if(timings.size() == 0)
138 | sched_time = start_time;
139 |
140 | /* check if can schedule before or in between before just scheduling
141 | * after all other events */
142 | else
143 | {
144 | /* skip over empty table entries
145 | * empty table entries will be first from sorting (in unlock method)
146 | * because the flag is a negative value */
147 | std::vector::iterator it = timings.begin();
148 |
149 | /* schedule before first event in table */
150 | if((*it).lock_time > start_time && (*it).lock_time - start_time >= duration)
151 | sched_time = start_time;
152 |
153 | /* schedule in between other events in table */
154 | if(sched_time == BUS_CHANNEL_FREE_FLAG)
155 | {
156 | for(; it < timings.end(); it++)
157 | {
158 | if (it + 1 != timings.end())
159 | {
160 | /* enough time to schedule in between next two events */
161 | if((*it).unlock_time >= start_time && (*(it+1)).lock_time - (*it).unlock_time >= duration)
162 | {
163 | sched_time = (*it).unlock_time;
164 | break;
165 | }
166 | }
167 |
168 | }
169 | }
170 |
171 | /* schedule after all events in table */
172 | if(sched_time == BUS_CHANNEL_FREE_FLAG)
173 | sched_time = timings.back().unlock_time;
174 | }
175 |
176 | /* write scheduling info in free table slot */
177 | lock_times lt;
178 | lt.lock_time = sched_time;
179 | lt.unlock_time = sched_time + duration;
180 | timings.push_back(lt);
181 |
182 | if (lt.unlock_time > ready_at)
183 | ready_at = lt.unlock_time;
184 |
185 | /* update event times for bus wait and time taken */
186 | event.incr_bus_wait_time(sched_time - start_time);
187 | event.incr_time_taken(sched_time - start_time + duration);
188 |
189 | return SUCCESS;
190 | }
191 |
192 | /* remove all expired entries (finish time is less than provided time)
193 | * update current number of table entries used
194 | * sort table by finish times (2nd row) */
195 | void Channel::unlock(double start_time)
196 | {
197 | /* remove expired channel lock entries */
198 | std::vector::iterator it;
199 | for ( it = timings.begin(); it < timings.end();)
200 | {
201 | if((*it).unlock_time <= start_time)
202 | timings.erase(it);
203 | else
204 | {
205 | it++;
206 | }
207 | }
208 | std::sort(timings.begin(), timings.end(), &timings_sorter);
209 | }
210 |
211 | bool Channel::timings_sorter(lock_times const& lhs, lock_times const& rhs) {
212 | return lhs.lock_time < rhs.lock_time;
213 | }
214 |
215 | double Channel::ready_time(void)
216 | {
217 | return ready_at;
218 | }
219 |
220 |
--------------------------------------------------------------------------------
/ssd_config.cpp:
--------------------------------------------------------------------------------
1 | /* Copyright 2009, 2010 Brendan Tauras */
2 |
3 | /* ssd_config.cpp is part of FlashSim. */
4 |
5 | /* FlashSim is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published by
7 | * the Free Software Foundation, either version 3 of the License, or
8 | * any later version. */
9 |
10 | /* FlashSim is distributed in the hope that it will be useful,
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * GNU General Public License for more details. */
14 |
15 | /* You should have received a copy of the GNU General Public License
16 | * along with FlashSim. If not, see . */
17 |
18 | /****************************************************************************/
19 |
20 | /* Configuration loader
21 | * Brendan Tauras 2009-11-02
22 | * Matias Bjørling 2011-03
23 | *
24 | * Functions below provide basic configuration file parsing. Config file
25 | * support includes skipping blank lines, comment lines (begin with a #).
26 | * Parsed lines consist of the variable name, a space, then the value
27 | * (e.g. SSD_SIZE 4 ). Default config values (if config file is missing
28 | * an entry to set the value) are defined in the variable declarations below.
29 | *
30 | * A function is also provided for printing the current configuration. */
31 |
32 | #include
33 | #include
34 | #include
35 |
36 | /* using namespace ssd; */
37 | namespace ssd {
38 |
39 | /* Define typedefs and error macros from ssd.h here instead of including
40 | * header file because we want to declare the global configuration variables
41 | * and set them in this file. ssd.h declares the global configuration
42 | * variables as extern const, which would conflict this file's definitions.
43 | * This is not the best solution, but it is easy and it works. */
44 |
45 | /* some obvious typedefs for laziness */
46 | typedef unsigned int uint;
47 | typedef unsigned long ulong;
48 |
49 | /* define exit codes for errors */
50 | #define MEM_ERR -1
51 | #define FILE_ERR -2
52 |
53 | /* Simulator configuration
54 | * All configuration variables are set by reading ssd.conf and referenced with
55 | * as "extern const" in ssd.h
56 | * Configuration variables are described below and are assigned default values
57 | * in case of config file error. The values defined below are overwritten
58 | * when defined in the config file.
59 | * We do not want a class here because we want to use the configuration
60 | * variables in the same was as macros. */
61 |
62 | /* Ram class:
63 | * delay to read from and write to the RAM for 1 page of data */
64 | double RAM_READ_DELAY = 0.00000001;
65 | double RAM_WRITE_DELAY = 0.00000001;
66 |
67 | /* Bus class:
68 | * delay to communicate over bus
69 | * max number of connected devices allowed
70 | * number of time entries bus has to keep track of future schedule usage
71 | * value used as a flag to indicate channel is free
72 | * (use a value not used as a delay value - e.g. -1.0)
73 | * number of simultaneous communication channels - defined by SSD_SIZE */
74 | double BUS_CTRL_DELAY = 0.000000005;
75 | double BUS_DATA_DELAY = 0.00000001;
76 | uint BUS_MAX_CONNECT = 8;
77 | uint BUS_TABLE_SIZE = 64;
78 | double BUS_CHANNEL_FREE_FLAG = -1.0;
79 | /* uint BUS_CHANNELS = 4; same as # of Packages, defined by SSD_SIZE */
80 |
81 | /* Ssd class:
82 | * number of Packages per Ssd (size) */
83 | uint SSD_SIZE = 4;
84 |
85 | /* Package class:
86 | * number of Dies per Package (size) */
87 | uint PACKAGE_SIZE = 8;
88 |
89 | /* Die class:
90 | * number of Planes per Die (size) */
91 | uint DIE_SIZE = 2;
92 |
93 | /* Plane class:
94 | * number of Blocks per Plane (size)
95 | * delay for reading from plane register
96 | * delay for writing to plane register
97 | * delay for merging is based on read, write, reg_read, reg_write
98 | * and does not need to be explicitly defined */
99 | uint PLANE_SIZE = 64;
100 | double PLANE_REG_READ_DELAY = 0.0000000001;
101 | double PLANE_REG_WRITE_DELAY = 0.0000000001;
102 |
103 | /* Block class:
104 | * number of Pages per Block (size)
105 | * number of erases in lifetime of block
106 | * delay for erasing block */
107 | uint BLOCK_SIZE = 16;
108 | uint BLOCK_ERASES = 1048675;
109 | double BLOCK_ERASE_DELAY = 0.001;
110 |
111 | /* Page class:
112 | * delay for Page reads
113 | * delay for Page writes */
114 | double PAGE_READ_DELAY = 0.000001;
115 | double PAGE_WRITE_DELAY = 0.00001;
116 |
117 | /* Page data memory allocation
118 | *
119 | */
120 | uint PAGE_SIZE = 4096;
121 | bool PAGE_ENABLE_DATA = true;
122 |
123 | /*
124 | * Memory area to support pages with data.
125 | */
126 | void *page_data;
127 |
128 | /*
129 | * Number of blocks to reserve for mappings. e.g. map directory in BAST.
130 | */
131 | uint MAP_DIRECTORY_SIZE = 0;
132 |
133 | /*
134 | * Implementation to use (0 -> Page, 1 -> BAST, 2 -> FAST, 3 -> DFTL, 4 -> BiModal
135 | */
136 | uint FTL_IMPLEMENTATION = 0;
137 |
138 | /*
139 | * Limit of LOG pages (for use in BAST)
140 | */
141 | uint BAST_LOG_BLOCK_LIMIT = 100;
142 |
143 |
144 | /*
145 | * Limit of LOG pages (for use in FAST)
146 | */
147 | uint FAST_LOG_BLOCK_LIMIT = 4;
148 |
149 | /*
150 | * Number of pages allowed to be in DFTL Cached Mapping Table.
151 | * (Size equals CACHE_BLOCK_LIMIT * block size * page size)
152 | *
153 | */
154 | uint CACHE_DFTL_LIMIT = 8;
155 |
156 | /*
157 | * Parallelism mode.
158 | * 0 -> Normal
159 | * 1 -> Striping
160 | * 2 -> Logical Address Space Parallelism (LASP)
161 | */
162 | uint PARALLELISM_MODE = 0;
163 |
164 | /* Virtual block size (as a multiple of the physical block size) */
165 | uint VIRTUAL_BLOCK_SIZE = 1;
166 |
167 | /* Virtual page size (as a multiple of the physical page size) */
168 | uint VIRTUAL_PAGE_SIZE = 1;
169 |
170 | uint NUMBER_OF_ADDRESSABLE_BLOCKS = 0;
171 |
172 | /* RAISSDs: Number of physical SSDs */
173 | uint RAID_NUMBER_OF_PHYSICAL_SSDS = 0;
174 |
175 | void load_entry(char *name, double value, uint line_number) {
176 | /* cheap implementation - go through all possibilities and match entry */
177 | if (!strcmp(name, "RAM_READ_DELAY"))
178 | RAM_READ_DELAY = value;
179 | else if (!strcmp(name, "RAM_WRITE_DELAY"))
180 | RAM_WRITE_DELAY = value;
181 | else if (!strcmp(name, "BUS_CTRL_DELAY"))
182 | BUS_CTRL_DELAY = value;
183 | else if (!strcmp(name, "BUS_DATA_DELAY"))
184 | BUS_DATA_DELAY = value;
185 | else if (!strcmp(name, "BUS_MAX_CONNECT"))
186 | BUS_MAX_CONNECT = (uint) value;
187 | else if (!strcmp(name, "BUS_TABLE_SIZE"))
188 | BUS_TABLE_SIZE = (uint) value;
189 | else if (!strcmp(name, "SSD_SIZE"))
190 | SSD_SIZE = (uint) value;
191 | else if (!strcmp(name, "PACKAGE_SIZE"))
192 | PACKAGE_SIZE = (uint) value;
193 | else if (!strcmp(name, "DIE_SIZE"))
194 | DIE_SIZE = (uint) value;
195 | else if (!strcmp(name, "PLANE_SIZE"))
196 | PLANE_SIZE = (uint) value;
197 | else if (!strcmp(name, "PLANE_REG_READ_DELAY"))
198 | PLANE_REG_READ_DELAY = value;
199 | else if (!strcmp(name, "PLANE_REG_WRITE_DELAY"))
200 | PLANE_REG_WRITE_DELAY = value;
201 | else if (!strcmp(name, "BLOCK_SIZE"))
202 | BLOCK_SIZE = (uint) value;
203 | else if (!strcmp(name, "BLOCK_ERASES"))
204 | BLOCK_ERASES = (uint) value;
205 | else if (!strcmp(name, "BLOCK_ERASE_DELAY"))
206 | BLOCK_ERASE_DELAY = value;
207 | else if (!strcmp(name, "PAGE_READ_DELAY"))
208 | PAGE_READ_DELAY = value;
209 | else if (!strcmp(name, "PAGE_WRITE_DELAY"))
210 | PAGE_WRITE_DELAY = value;
211 | else if (!strcmp(name, "PAGE_SIZE"))
212 | PAGE_SIZE = value;
213 | else if (!strcmp(name, "FTL_IMPLEMENTATION"))
214 | FTL_IMPLEMENTATION = value;
215 | else if (!strcmp(name, "PAGE_ENABLE_DATA"))
216 | PAGE_ENABLE_DATA = (value == 1);
217 | else if (!strcmp(name, "MAP_DIRECTORY_SIZE"))
218 | MAP_DIRECTORY_SIZE = value;
219 | else if (!strcmp(name, "FTL_IMPLEMENTATION"))
220 | FTL_IMPLEMENTATION = value;
221 | else if (!strcmp(name, "BAST_LOG_BLOCK_LIMIT"))
222 | BAST_LOG_BLOCK_LIMIT = value;
223 | else if (!strcmp(name, "FAST_LOG_BLOCK_LIMIT"))
224 | FAST_LOG_BLOCK_LIMIT = value;
225 | else if (!strcmp(name, "CACHE_DFTL_LIMIT"))
226 | CACHE_DFTL_LIMIT = value;
227 | else if (!strcmp(name, "PARALLELISM_MODE"))
228 | PARALLELISM_MODE = value;
229 | else if (!strcmp(name, "VIRTUAL_BLOCK_SIZE"))
230 | VIRTUAL_BLOCK_SIZE = value;
231 | else if (!strcmp(name, "VIRTUAL_PAGE_SIZE"))
232 | VIRTUAL_PAGE_SIZE = value;
233 | else if (!strcmp(name, "RAID_NUMBER_OF_PHYSICAL_SSDS"))
234 | RAID_NUMBER_OF_PHYSICAL_SSDS = value;
235 | else
236 | fprintf(stderr, "Config file parsing error on line %u\n", line_number);
237 | return;
238 | }
239 |
240 | void load_config(void) {
241 | const char * const config_name = "ssd.conf";
242 | FILE *config_file = NULL;
243 |
244 | /* update sscanf line below with max name length (%s) if changing sizes */
245 | uint line_size = 128;
246 | char line[line_size];
247 | uint line_number;
248 |
249 | char name[line_size];
250 | double value;
251 |
252 | if ((config_file = fopen(config_name, "r")) == NULL) {
253 | fprintf(stderr, "Config file %s not found. Exiting.\n", config_name);
254 | exit(FILE_ERR);
255 | }
256 |
257 | for (line_number = 1; fgets(line, line_size, config_file) != NULL; line_number++) {
258 | line[line_size - 1] = '\0';
259 |
260 | /* ignore comments and blank lines */
261 | if (line[0] == '#' || line[0] == '\n')
262 | continue;
263 |
264 | /* read lines with entries (name value) */
265 | if (sscanf(line, "%127s %lf", name, &value) == 2) {
266 | name[line_size - 1] = '\0';
267 | load_entry(name, value, line_number);
268 | } else
269 | fprintf(stderr, "Config file parsing error on line %u\n",
270 | line_number);
271 | }
272 | fclose(config_file);
273 |
274 | NUMBER_OF_ADDRESSABLE_BLOCKS = (SSD_SIZE * PACKAGE_SIZE * DIE_SIZE * PLANE_SIZE) / VIRTUAL_PAGE_SIZE;
275 |
276 | return;
277 | }
278 |
279 | void print_config(FILE *stream) {
280 | if (stream == NULL)
281 | stream = stdout;
282 | fprintf(stream, "RAM_READ_DELAY: %.16lf\n", RAM_READ_DELAY);
283 | fprintf(stream, "RAM_WRITE_DELAY: %.16lf\n", RAM_WRITE_DELAY);
284 | fprintf(stream, "BUS_CTRL_DELAY: %.16lf\n", BUS_CTRL_DELAY);
285 | fprintf(stream, "BUS_DATA_DELAY: %.16lf\n", BUS_DATA_DELAY);
286 | fprintf(stream, "BUS_MAX_CONNECT: %u\n", BUS_MAX_CONNECT);
287 | fprintf(stream, "BUS_TABLE_SIZE: %u\n", BUS_TABLE_SIZE);
288 | fprintf(stream, "SSD_SIZE: %u\n", SSD_SIZE);
289 | fprintf(stream, "PACKAGE_SIZE: %u\n", PACKAGE_SIZE);
290 | fprintf(stream, "DIE_SIZE: %u\n", DIE_SIZE);
291 | fprintf(stream, "PLANE_SIZE: %u\n", PLANE_SIZE);
292 | fprintf(stream, "PLANE_REG_READ_DELAY: %.16lf\n", PLANE_REG_READ_DELAY);
293 | fprintf(stream, "PLANE_REG_WRITE_DELAY: %.16lf\n", PLANE_REG_WRITE_DELAY);
294 | fprintf(stream, "BLOCK_SIZE: %u\n", BLOCK_SIZE);
295 | fprintf(stream, "BLOCK_ERASES: %u\n", BLOCK_ERASES);
296 | fprintf(stream, "BLOCK_ERASE_DELAY: %.16lf\n", BLOCK_ERASE_DELAY);
297 | fprintf(stream, "PAGE_READ_DELAY: %.16lf\n", PAGE_READ_DELAY);
298 | fprintf(stream, "PAGE_WRITE_DELAY: %.16lf\n", PAGE_WRITE_DELAY);
299 | fprintf(stream, "PAGE_SIZE: %u\n", PAGE_SIZE);
300 | fprintf(stream, "PAGE_ENABLE_DATA: %i\n", PAGE_ENABLE_DATA);
301 | fprintf(stream, "MAP_DIRECTORY_SIZE: %i\n", MAP_DIRECTORY_SIZE);
302 | fprintf(stream, "FTL_IMPLEMENTATION: %i\n", FTL_IMPLEMENTATION);
303 | fprintf(stream, "PARALLELISM_MODE: %i\n", PARALLELISM_MODE);
304 | fprintf(stream, "RAID_NUMBER_OF_PHYSICAL_SSDS: %i\n", RAID_NUMBER_OF_PHYSICAL_SSDS);
305 |
306 | return;
307 | }
308 |
309 | }
310 |
--------------------------------------------------------------------------------
/ssd_controller.cpp:
--------------------------------------------------------------------------------
1 | /* Copyright 2009, 2010 Brendan Tauras */
2 |
3 | /* ssd_controller.cpp is part of FlashSim. */
4 |
5 | /* FlashSim is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published by
7 | * the Free Software Foundation, either version 3 of the License, or
8 | * any later version. */
9 |
10 | /* FlashSim is distributed in the hope that it will be useful,
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * GNU General Public License for more details. */
14 |
15 | /* You should have received a copy of the GNU General Public License
16 | * along with FlashSim. If not, see . */
17 |
18 | /****************************************************************************/
19 |
20 | /* Controller class
21 | *
22 | * Brendan Tauras 2009-11-03
23 | *
24 | * The controller accepts read/write requests through its event_arrive method
25 | * and consults the FTL regarding what to do by calling the FTL's read/write
26 | * methods. The FTL returns an event list for the controller through its issue
27 | * method that the controller buffers in RAM and sends across the bus. The
28 | * controller's issue method passes the events from the FTL to the SSD.
29 | *
30 | * The controller also provides an interface for the FTL to collect wear
31 | * information to perform wear-leveling.
32 | */
33 |
34 | #include
35 | #include
36 | #include
37 | #include "ssd.h"
38 |
39 | using namespace ssd;
40 |
41 | Controller::Controller(Ssd &parent):
42 | ssd(parent)
43 | {
44 | switch (FTL_IMPLEMENTATION)
45 | {
46 | case 0:
47 | ftl = new FtlImpl_Page(*this);
48 | break;
49 | case 1:
50 | ftl = new FtlImpl_Bast(*this);
51 | break;
52 | case 2:
53 | ftl = new FtlImpl_Fast(*this);
54 | break;
55 | case 3:
56 | ftl = new FtlImpl_Dftl(*this);
57 | break;
58 | case 4:
59 | ftl = new FtlImpl_BDftl(*this);
60 | break;
61 | }
62 | return;
63 | }
64 |
65 | Controller::~Controller(void)
66 | {
67 | delete ftl;
68 | return;
69 | }
70 |
71 | enum status Controller::event_arrive(Event &event)
72 | {
73 | if(event.get_event_type() == READ)
74 | return ftl->read(event);
75 | else if(event.get_event_type() == WRITE)
76 | return ftl->write(event);
77 | else if(event.get_event_type() == TRIM)
78 | return ftl->trim(event);
79 | else
80 | fprintf(stderr, "Controller: %s: Invalid event type\n", __func__);
81 | return FAILURE;
82 | }
83 |
84 | enum status Controller::issue(Event &event_list)
85 | {
86 | Event *cur;
87 |
88 | /* go through event list and issue each to the hardware
89 | * stop processing events and return failure status if any event in the
90 | * list fails */
91 | for(cur = &event_list; cur != NULL; cur = cur -> get_next()){
92 | if(cur -> get_size() != 1){
93 | fprintf(stderr, "Controller: %s: Received non-single-page-sized event from FTL.\n", __func__);
94 | return FAILURE;
95 | }
96 | else if(cur -> get_event_type() == READ)
97 | {
98 | assert(cur -> get_address().valid > NONE);
99 | if(ssd.bus.lock(cur -> get_address().package, cur -> get_start_time(), BUS_CTRL_DELAY, *cur) == FAILURE
100 | || ssd.read(*cur) == FAILURE
101 | || ssd.bus.lock(cur -> get_address().package, cur -> get_start_time()+cur -> get_time_taken(), BUS_CTRL_DELAY + BUS_DATA_DELAY, *cur) == FAILURE
102 | || ssd.ram.write(*cur) == FAILURE
103 | || ssd.ram.read(*cur) == FAILURE
104 | || ssd.replace(*cur) == FAILURE)
105 | return FAILURE;
106 | }
107 | else if(cur -> get_event_type() == WRITE)
108 | {
109 | assert(cur -> get_address().valid > NONE);
110 | if(ssd.bus.lock(cur -> get_address().package, cur -> get_start_time(), BUS_CTRL_DELAY + BUS_DATA_DELAY, *cur) == FAILURE
111 | || ssd.ram.write(*cur) == FAILURE
112 | || ssd.ram.read(*cur) == FAILURE
113 | || ssd.write(*cur) == FAILURE
114 | || ssd.replace(*cur) == FAILURE)
115 | return FAILURE;
116 | }
117 | else if(cur -> get_event_type() == ERASE)
118 | {
119 | assert(cur -> get_address().valid > NONE);
120 | if(ssd.bus.lock(cur -> get_address().package, cur -> get_start_time(), BUS_CTRL_DELAY, *cur) == FAILURE
121 | || ssd.erase(*cur) == FAILURE)
122 | return FAILURE;
123 | }
124 | else if(cur -> get_event_type() == MERGE)
125 | {
126 | assert(cur -> get_address().valid > NONE);
127 | assert(cur -> get_merge_address().valid > NONE);
128 | if(ssd.bus.lock(cur -> get_address().package, cur -> get_start_time(), BUS_CTRL_DELAY, *cur) == FAILURE
129 | || ssd.merge(*cur) == FAILURE)
130 | return FAILURE;
131 | }
132 | else if(cur -> get_event_type() == TRIM)
133 | {
134 | return SUCCESS;
135 | }
136 | else
137 | {
138 | fprintf(stderr, "Controller: %s: Invalid event type\n", __func__);
139 | return FAILURE;
140 | }
141 | }
142 | return SUCCESS;
143 | }
144 |
145 | void Controller::translate_address(Address &address)
146 | {
147 | if (PARALLELISM_MODE != 1)
148 | return;
149 | }
150 |
151 | ssd::ulong Controller::get_erases_remaining(const Address &address) const
152 | {
153 | assert(address.valid > NONE);
154 | return ssd.get_erases_remaining(address);
155 | }
156 |
157 | void Controller::get_least_worn(Address &address) const
158 | {
159 | assert(address.valid > NONE);
160 | return ssd.get_least_worn(address);
161 | }
162 |
163 | double Controller::get_last_erase_time(const Address &address) const
164 | {
165 | assert(address.valid > NONE);
166 | return ssd.get_last_erase_time(address);
167 | }
168 |
169 | enum page_state Controller::get_state(const Address &address) const
170 | {
171 | assert(address.valid > NONE);
172 | return (ssd.get_state(address));
173 | }
174 |
175 | enum block_state Controller::get_block_state(const Address &address) const
176 | {
177 | assert(address.valid > NONE);
178 | return (ssd.get_block_state(address));
179 | }
180 |
181 | void Controller::get_free_page(Address &address) const
182 | {
183 | assert(address.valid > NONE);
184 | ssd.get_free_page(address);
185 | return;
186 | }
187 |
188 | ssd::uint Controller::get_num_free(const Address &address) const
189 | {
190 | assert(address.valid > NONE);
191 | return ssd.get_num_free(address);
192 | }
193 |
194 | ssd::uint Controller::get_num_valid(const Address &address) const
195 | {
196 | assert(address.valid > NONE);
197 | return ssd.get_num_valid(address);
198 | }
199 |
200 | ssd::uint Controller::get_num_invalid(const Address &address) const
201 | {
202 | assert(address.valid > NONE);
203 | return ssd.get_num_invalid(address);
204 | }
205 |
206 | Block *Controller::get_block_pointer(const Address & address)
207 | {
208 | return ssd.get_block_pointer(address);
209 | }
210 |
211 | const FtlParent &Controller::get_ftl(void) const
212 | {
213 | return (*ftl);
214 | }
215 |
216 | void Controller::print_ftl_statistics()
217 | {
218 | ftl->print_ftl_statistics();
219 | }
220 |
--------------------------------------------------------------------------------
/ssd_die.cpp:
--------------------------------------------------------------------------------
1 | /* Copyright 2009, 2010 Brendan Tauras */
2 |
3 | /* ssd_die.cpp is part of FlashSim. */
4 |
5 | /* FlashSim is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published by
7 | * the Free Software Foundation, either version 3 of the License, or
8 | * any later version. */
9 |
10 | /* FlashSim is distributed in the hope that it will be useful,
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * GNU General Public License for more details. */
14 |
15 | /* You should have received a copy of the GNU General Public License
16 | * along with FlashSim. If not, see . */
17 |
18 | /****************************************************************************/
19 |
20 | /* Die class
21 | * Brendan Tauras 2009-11-03
22 | *
23 | * The die is the data storage hardware unit that contains planes and is a flash
24 | * chip. Dies maintain wear statistics for the FTL. */
25 |
26 | #include
27 | #include
28 | #include
29 | #include "ssd.h"
30 |
31 | using namespace ssd;
32 |
33 | Die::Die(const Package &parent, Channel &channel, uint die_size, long physical_address):
34 | size(die_size),
35 |
36 | /* use a const pointer (Plane * const data) to use as an array
37 | * but like a reference, we cannot reseat the pointer */
38 | data((Plane *) malloc(size * sizeof(Plane))),
39 | parent(parent),
40 | channel(channel),
41 |
42 | /* assume all Planes are same so first one can start as least worn */
43 | least_worn(0),
44 |
45 | /* set erases remaining to BLOCK_ERASES to match Block constructor args
46 | * in Plane class
47 | * this is the cheap implementation but can change to pass through classes */
48 | erases_remaining(BLOCK_ERASES),
49 |
50 | /* assume hardware created at time 0 and had an implied free erasure */
51 | last_erase_time(0.0)
52 | {
53 | uint i;
54 |
55 | if(channel.connect() == FAILURE)
56 | fprintf(stderr, "Die error: %s: constructor unable to connect to Bus Channel\n", __func__);
57 |
58 | /* new cannot initialize an array with constructor args so
59 | * malloc the array
60 | * then use placement new to call the constructor for each element
61 | * chose an array over container class so we don't have to rely on anything
62 | * i.e. STL's std::vector */
63 | /* array allocated in initializer list:
64 | * data = (Plane *) malloc(size * sizeof(Plane)); */
65 | if(data == NULL){
66 | fprintf(stderr, "Die error: %s: constructor unable to allocate Plane data\n", __func__);
67 | exit(MEM_ERR);
68 | }
69 |
70 |
71 |
72 | for(i = 0; i < size; i++)
73 | (void) new (&data[i]) Plane(*this, PLANE_SIZE, PLANE_REG_READ_DELAY, PLANE_REG_WRITE_DELAY, physical_address+(PLANE_SIZE*BLOCK_SIZE*i));
74 |
75 | return;
76 | }
77 |
78 | Die::~Die(void)
79 | {
80 | assert(data != NULL);
81 | uint i;
82 | /* call destructor for each Block array element
83 | * since we used malloc and placement new */
84 | for(i = 0; i < size; i++)
85 | data[i].~Plane();
86 | free(data);
87 | (void) channel.disconnect();
88 | return;
89 | }
90 |
91 | enum status Die::read(Event &event)
92 | {
93 | assert(data != NULL);
94 | assert(event.get_address().plane < size && event.get_address().valid > DIE);
95 | return data[event.get_address().plane].read(event);
96 | }
97 |
98 | enum status Die::write(Event &event)
99 | {
100 | assert(data != NULL);
101 | assert(event.get_address().plane < size && event.get_address().valid > DIE);
102 | return data[event.get_address().plane].write(event);
103 | }
104 |
105 | enum status Die::replace(Event &event)
106 | {
107 | assert(data != NULL);
108 | assert(event.get_address().plane < size);
109 | return data[event.get_replace_address().plane].replace(event);
110 | }
111 |
112 | /* if no errors
113 | * updates last_erase_time if later time
114 | * updates erases_remaining if smaller value
115 | * returns 1 for success, 0 for failure */
116 | enum status Die::erase(Event &event)
117 | {
118 | assert(data != NULL);
119 | assert(event.get_address().plane < size && event.get_address().valid > DIE);
120 | enum status status = data[event.get_address().plane].erase(event);
121 |
122 | /* update values if no errors */
123 | if(status == SUCCESS)
124 | update_wear_stats(event.get_address());
125 | return status;
126 | }
127 |
128 | /* TODO: move Plane::_merge() to Die and make generic to handle merge across
129 | * both cases: 2 separate planes or within 1 plane */
130 | enum status Die::merge(Event &event)
131 | {
132 | assert(data != NULL);
133 | assert(event.get_address().plane < size && event.get_address().valid > DIE && event.get_merge_address().plane < size && event.get_merge_address().valid > DIE);
134 | if(event.get_address().plane != event.get_merge_address().plane)
135 | return _merge(event);
136 | else return data[event.get_address().plane]._merge(event);
137 | }
138 |
139 | /* TODO: update stub as per Die::merge() comment above
140 | * to support Die-level merge operations */
141 | enum status Die::_merge(Event &event)
142 | {
143 | assert(data != NULL);
144 | assert(event.get_address().plane < size && event.get_address().valid > DIE && event.get_merge_address().plane < size && event.get_merge_address().valid > DIE);
145 | assert(event.get_address().plane != event.get_merge_address().plane);
146 | return SUCCESS;
147 | }
148 |
149 | const Package &Die::get_parent(void) const
150 | {
151 | return parent;
152 | }
153 |
154 | /* if given a valid Block address, call the Block's method
155 | * else return local value */
156 | double Die::get_last_erase_time(const Address &address) const
157 | {
158 | assert(data != NULL);
159 | if(address.valid > DIE && address.plane < size)
160 | return data[address.plane].get_last_erase_time(address);
161 | else
162 | return last_erase_time;
163 | }
164 |
165 | /* if given a valid Plane address, call the Plane's method
166 | * else return local value */
167 | ssd::ulong Die::get_erases_remaining(const Address &address) const
168 | {
169 | assert(data != NULL);
170 | if(address.valid > DIE && address.plane < size)
171 | return data[address.plane].get_erases_remaining(address);
172 | else
173 | return erases_remaining;
174 | }
175 |
176 |
177 |
178 | /* Plane with the most erases remaining is the least worn */
179 | void Die::update_wear_stats(const Address &address)
180 | {
181 | assert(data != NULL);
182 | uint i;
183 | uint max_index = 0;
184 | ulong max = data[0].get_erases_remaining(address);
185 | for(i = 1; i < size; i++)
186 | if(data[i].get_erases_remaining(address) > max)
187 | max_index = i;
188 | least_worn = max_index;
189 | erases_remaining = max;
190 | last_erase_time = data[max_index].get_last_erase_time(address);
191 | return;
192 | }
193 |
194 | /* update given address -> die to least worn die */
195 | void Die::get_least_worn(Address &address) const
196 | {
197 | assert(data != NULL && least_worn < size);
198 | address.plane = least_worn;
199 | address.valid = PLANE;
200 | data[least_worn].get_least_worn(address);
201 | return;
202 | }
203 |
204 | enum page_state Die::get_state(const Address &address) const
205 | {
206 | assert(data != NULL && address.plane < size && address.valid >= DIE);
207 | return data[address.plane].get_state(address);
208 | }
209 |
210 | enum block_state Die::get_block_state(const Address &address) const
211 | {
212 | assert(data != NULL && address.plane < size && address.valid >= DIE);
213 | return data[address.plane].get_block_state(address);
214 | }
215 |
216 | void Die::get_free_page(Address &address) const
217 | {
218 | assert(address.plane < size && address.valid >= PLANE);
219 | data[address.plane].get_free_page(address);
220 | return;
221 | }
222 |
223 | ssd::uint Die::get_num_free(const Address &address) const
224 | {
225 | assert(address.valid >= PLANE);
226 | return data[address.plane].get_num_free(address);
227 | }
228 |
229 | ssd::uint Die::get_num_valid(const Address &address) const
230 | {
231 | assert(address.valid >= PLANE);
232 | return data[address.plane].get_num_valid(address);
233 | }
234 |
235 | ssd::uint Die::get_num_invalid(const Address & address) const
236 | {
237 | assert(address.valid >= PLANE);
238 | return data[address.plane].get_num_invalid(address);
239 | }
240 |
241 | Block *Die::get_block_pointer(const Address & address)
242 | {
243 | assert(address.valid >= PLANE);
244 | return data[address.plane].get_block_pointer(address);
245 | }
246 |
--------------------------------------------------------------------------------
/ssd_event.cpp:
--------------------------------------------------------------------------------
1 | /* Copyright 2009, 2010 Brendan Tauras */
2 |
3 | /* ssd_event.cpp is part of FlashSim. */
4 |
5 | /* FlashSim is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published by
7 | * the Free Software Foundation, either version 3 of the License, or
8 | * any later version. */
9 |
10 | /* FlashSim is distributed in the hope that it will be useful,
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * GNU General Public License for more details. */
14 |
15 | /* You should have received a copy of the GNU General Public License
16 | * along with FlashSim. If not, see . */
17 |
18 | /****************************************************************************/
19 |
20 | /* Event class
21 | * Brendan Tauras 2010-07-16
22 | *
23 | * Class to manage I/O requests as events for the SSD. It was designed to keep
24 | * track of an I/O request by storing its type, addressing, and timing. The
25 | * SSD class creates an instance for each I/O request it receives.
26 | */
27 |
28 | #include
29 | #include
30 | #include "ssd.h"
31 |
32 | using namespace ssd;
33 |
34 | /* see "enum event_type" in ssd.h for details on event types */
35 | Event::Event(enum event_type type, ulong logical_address, uint size, double start_time):
36 | start_time(start_time),
37 | time_taken(0.0),
38 | bus_wait_time(0.0),
39 | type(type),
40 | logical_address(logical_address),
41 | size(size),
42 | payload(NULL),
43 | next(NULL),
44 | noop(false)
45 | {
46 | assert(start_time >= 0.0);
47 | return;
48 | }
49 |
50 | Event::~Event(void)
51 | {
52 | return;
53 | }
54 |
55 | /* find the last event in the list to finish and use that event's finish time
56 | * to calculate time_taken
57 | * add bus_wait_time for all events in the list to bus_wait_time
58 | * all events in the list do not need to start at the same time
59 | * bus_wait_time can potentially exceed time_taken with long event lists
60 | * because bus_wait_time is a sum while time_taken is a max
61 | * be careful to only call this method once when the metaevent is finished */
62 | void Event::consolidate_metaevent(Event &list)
63 | {
64 | Event *cur;
65 | double max;
66 | double tmp;
67 |
68 | assert(start_time >= 0);
69 |
70 | /* find max time taken with respect to this event's start_time */
71 | max = start_time - list.start_time + list.time_taken;
72 | for(cur = list.next; cur != NULL; cur = cur -> next)
73 | {
74 | tmp = start_time - cur -> start_time + cur -> time_taken;
75 | if(tmp > max)
76 | max = tmp;
77 | bus_wait_time += cur -> get_bus_wait_time();
78 | }
79 | time_taken = max;
80 |
81 | assert(time_taken >= 0);
82 | assert(bus_wait_time >= 0);
83 | return;
84 | }
85 |
86 | ssd::ulong Event::get_logical_address(void) const
87 | {
88 | return logical_address;
89 | }
90 |
91 | const Address &Event::get_address(void) const
92 | {
93 | return address;
94 | }
95 |
96 | const Address &Event::get_merge_address(void) const
97 | {
98 | return merge_address;
99 | }
100 |
101 | const Address &Event::get_log_address(void) const
102 | {
103 | return log_address;
104 | }
105 |
106 | const Address &Event::get_replace_address(void) const
107 | {
108 | return replace_address;
109 | }
110 |
111 | void Event::set_log_address(const Address &address)
112 | {
113 | log_address = address;
114 | }
115 |
116 | ssd::uint Event::get_size(void) const
117 | {
118 | return size;
119 | }
120 |
121 | enum event_type Event::get_event_type(void) const
122 | {
123 | return type;
124 | }
125 |
126 | void Event::set_event_type(const enum event_type &type)
127 | {
128 | this->type = type;
129 | }
130 |
131 | double Event::get_start_time(void) const
132 | {
133 | assert(start_time >= 0.0);
134 | return start_time;
135 | }
136 |
137 | double Event::get_time_taken(void) const
138 | {
139 |
140 | assert(time_taken >= 0.0);
141 | return time_taken;
142 | }
143 |
144 | double Event::get_bus_wait_time(void) const
145 | {
146 | assert(bus_wait_time >= 0.0);
147 | return bus_wait_time;
148 | }
149 |
150 | bool Event::get_noop(void) const
151 | {
152 | return noop;
153 | }
154 |
155 | Event *Event::get_next(void) const
156 | {
157 | return next;
158 | }
159 |
160 | void Event::set_payload(void *payload)
161 | {
162 | this->payload = payload;
163 | }
164 |
165 | void *Event::get_payload(void) const
166 | {
167 | return payload;
168 | }
169 |
170 | void Event::set_address(const Address &address)
171 | {
172 | this -> address = address;
173 | return;
174 | }
175 |
176 | void Event::set_merge_address(const Address &address)
177 | {
178 | merge_address = address;
179 | return;
180 | }
181 |
182 | void Event::set_replace_address(const Address &address)
183 | {
184 | replace_address = address;
185 | }
186 |
187 | void Event::set_noop(bool value)
188 | {
189 | noop = value;
190 | }
191 |
192 | void Event::set_next(Event &next)
193 | {
194 | this -> next = &next;
195 | return;
196 | }
197 |
198 | double Event::incr_bus_wait_time(double time_incr)
199 | {
200 | if(time_incr > 0.0)
201 | bus_wait_time += time_incr;
202 | return bus_wait_time;
203 | }
204 |
205 | double Event::incr_time_taken(double time_incr)
206 | {
207 | if(time_incr > 0.0)
208 | time_taken += time_incr;
209 | return time_taken;
210 | }
211 |
212 | void Event::print(FILE *stream)
213 | {
214 | if(type == READ)
215 | fprintf(stream, "Read ");
216 | else if(type == WRITE)
217 | fprintf(stream, "Write");
218 | else if(type == ERASE)
219 | fprintf(stream, "Erase");
220 | else if(type == MERGE)
221 | fprintf(stream, "Merge");
222 | else
223 | fprintf(stream, "Unknown event type: ");
224 | address.print(stream);
225 | if(type == MERGE)
226 | merge_address.print(stream);
227 | fprintf(stream, " Time[%f, %f) Bus_wait: %f\n", start_time, start_time + time_taken, bus_wait_time);
228 | return;
229 | }
230 |
231 | #if 0
232 | /* may be useful for further integration with DiskSim */
233 |
234 | /* caution: copies pointers from rhs */
235 | ioreq_event &Event::operator= (const ioreq_event &rhs)
236 | {
237 | assert(&rhs != NULL);
238 | if((const ioreq_event *) &rhs == (const ioreq_event *) &(this -> ioreq))
239 | return *(this -> ioreq);
240 | ioreq -> time = rhs.time;
241 | ioreq -> type = rhs.type;
242 | ioreq -> next = rhs.next;
243 | ioreq -> prev = rhs.prev;
244 | ioreq -> bcount = rhs.bcount;
245 | ioreq -> blkno = rhs.blkno;
246 | ioreq -> flags = rhs.flags;
247 | ioreq -> busno = rhs.busno;
248 | ioreq -> slotno = rhs.slotno;
249 | ioreq -> devno = rhs.devno;
250 | ioreq -> opid = rhs.opid;
251 | ioreq -> buf = rhs.buf;
252 | ioreq -> cause = rhs.cause;
253 | ioreq -> tempint1 = rhs.tempint1;
254 | ioreq -> tempint2 = rhs.tempint2;
255 | ioreq -> tempptr1 = rhs.tempptr1;
256 | ioreq -> tempptr2 = rhs.tempptr2;
257 | ioreq -> mems_sled = rhs.mems_sled;
258 | ioreq -> mems_reqinfo = rhs.mems_reqinfo;
259 | ioreq -> start_time = rhs.start_time;
260 | ioreq -> batchno = rhs.batchno;
261 | ioreq -> batch_complete = rhs.batch_complete;
262 | ioreq -> batch_size = rhs.batch_size;
263 | ioreq -> batch_next = rhs.batch_next;
264 | ioreq -> batch_prev = rhs.batch_prev;
265 | return *ioreq;
266 | }
267 | #endif
268 |
--------------------------------------------------------------------------------
/ssd_ftl.cpp:
--------------------------------------------------------------------------------
1 | /* Copyright 2009, 2010 Brendan Tauras */
2 |
3 | /* ssd_ftl.cpp is part of FlashSim. */
4 |
5 | /* FlashSim is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published by
7 | * the Free Software Foundation, either version 3 of the License, or
8 | * any later version. */
9 |
10 | /* FlashSim is distributed in the hope that it will be useful,
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * GNU General Public License for more details. */
14 |
15 | /* You should have received a copy of the GNU General Public License
16 | * along with FlashSim. If not, see . */
17 |
18 | /****************************************************************************/
19 |
20 | /* Ftl class
21 | * Brendan Tauras 2009-11-04
22 | *
23 | * This class is a stub class for the user to use as a template for implementing
24 | * his/her FTL scheme. A few functions to gather information from lower-level
25 | * hardware are added to assist writing a FTL scheme. The Ftl class should
26 | * rely on the Garbage_collector and Wear_leveler classes for modularity and
27 | * simplicity. */
28 |
29 | #include
30 | #include
31 | #include
32 | #include
33 | #include "ssd.h"
34 |
35 | using namespace ssd;
36 |
37 | Ftl::Ftl(Controller &controller):
38 | controller(controller),
39 | garbage(*this),
40 | wear(*this)
41 | {
42 | currentPage = 0;
43 |
44 | uint numCells = SSD_SIZE * PACKAGE_SIZE * DIE_SIZE * PLANE_SIZE * BLOCK_SIZE;
45 | map = new long[numCells];
46 | for (int i=0;i. */
17 |
18 | /****************************************************************************/
19 |
20 | /*
21 | * Implements parent interface for all FTL implementations to use.
22 | */
23 |
24 | #include "ssd.h"
25 |
26 | using namespace ssd;
27 |
28 | // Initialization of the block layer.
29 | Block_manager *Block_manager::inst = NULL;
30 |
31 | FtlParent::FtlParent(Controller &controller) : controller(controller)
32 | {
33 | Block_manager::instance_initialize(this);
34 |
35 | printf("Number of addressable blocks: %u\n", NUMBER_OF_ADDRESSABLE_BLOCKS);
36 |
37 | }
38 |
39 |
40 | ssd::ulong FtlParent::get_erases_remaining(const Address &address) const
41 | {
42 | return controller.get_erases_remaining(address);
43 | }
44 |
45 | void FtlParent::get_least_worn(Address &address) const
46 | {
47 | controller.get_least_worn(address);
48 | return;
49 | }
50 |
51 | enum page_state FtlParent::get_state(const Address &address) const
52 | {
53 | return controller.get_state(address);
54 | }
55 |
56 | enum block_state FtlParent::get_block_state(const Address &address) const
57 | {
58 | return controller.get_block_state(address);
59 | }
60 |
61 | Block *FtlParent::get_block_pointer(const Address &address)
62 | {
63 | return controller.get_block_pointer(address);
64 | }
65 |
66 | void FtlParent::cleanup_block(Event &event, Block *block)
67 | {
68 | assert(false);
69 | return;
70 | }
71 |
72 | void FtlParent::print_ftl_statistics()
73 | {
74 | return;
75 | }
76 |
--------------------------------------------------------------------------------
/ssd_gc.cpp:
--------------------------------------------------------------------------------
1 | /* Copyright 2009, 2010 Brendan Tauras */
2 |
3 | /* ssd_gc.cpp is part of FlashSim. */
4 |
5 | /* FlashSim is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published by
7 | * the Free Software Foundation, either version 3 of the License, or
8 | * any later version. */
9 |
10 | /* FlashSim is distributed in the hope that it will be useful,
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * GNU General Public License for more details. */
14 |
15 | /* You should have received a copy of the GNU General Public License
16 | * along with FlashSim. If not, see . */
17 |
18 | /****************************************************************************/
19 |
20 | /* Garbage_collector class
21 | * Brendan Tauras 2009-11-04
22 | *
23 | * This class is a stub class for the user to use as a template for implementing
24 | * his/her garbage collector scheme. The garbage collector class was added to
25 | * simplify and modularize the garbage collection in FTL schemes. */
26 |
27 | #include
28 | #include
29 | #include
30 | #include "ssd.h"
31 |
32 | using namespace ssd;
33 |
34 | Garbage_collector::Garbage_collector(FtlParent &ftl)
35 | {
36 | return;
37 | }
38 |
39 | Garbage_collector::~Garbage_collector(void)
40 | {
41 | return;
42 | }
43 |
44 | void Garbage_collector::clean(Address &address)
45 | {
46 |
47 | }
48 |
--------------------------------------------------------------------------------
/ssd_package.cpp:
--------------------------------------------------------------------------------
1 | /* Copyright 2009, 2010 Brendan Tauras */
2 |
3 | /* ssd_package.cpp is part of FlashSim. */
4 |
5 | /* FlashSim is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published by
7 | * the Free Software Foundation, either version 3 of the License, or
8 | * any later version. */
9 |
10 | /* FlashSim is distributed in the hope that it will be useful,
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * GNU General Public License for more details. */
14 |
15 | /* You should have received a copy of the GNU General Public License
16 | * along with FlashSim. If not, see . */
17 |
18 | /****************************************************************************/
19 |
20 | /* Package class
21 | * Brendan Tauras 2009-11-03
22 | *
23 | * The package is the highest level data storage hardware unit. While the
24 | * package is a virtual component, events are passed through the package for
25 | * organizational reasons, including helping to simplify maintaining wear
26 | * statistics for the FTL. */
27 |
28 | #include
29 | #include
30 | #include
31 | #include "ssd.h"
32 |
33 | using namespace ssd;
34 |
35 | Package::Package(const ssd::Ssd &parent, Channel &channel, uint package_size, long physical_address):
36 | size(package_size),
37 |
38 | /* use a const pointer (Die * const data) to use as an array
39 | * but like a reference, we cannot reseat the pointer */
40 | data((Die *) malloc(package_size * sizeof(Die))),
41 | parent(parent),
42 |
43 | /* assume all Dies are same so first one can start as least worn */
44 | least_worn(0),
45 |
46 | /* set erases remaining to BLOCK_ERASES to match Block constructor args
47 | * in Plane class
48 | * this is the cheap implementation but can change to pass through classes */
49 | erases_remaining(BLOCK_ERASES),
50 |
51 | /* assume hardware created at time 0 and had an implied free erasure */
52 | last_erase_time(0.0)
53 | {
54 | uint i;
55 |
56 | /* new cannot initialize an array with constructor args so
57 | * malloc the array
58 | * then use placement new to call the constructor for each element
59 | * chose an array over container class so we don't have to rely on anything
60 | * i.e. STL's std::vector */
61 | /* array allocated in initializer list:
62 | * data = (Die *) malloc(size * sizeof(Die)); */
63 | if(data == NULL){
64 | fprintf(stderr, "Package error: %s: constructor unable to allocate Die data\n", __func__);
65 | exit(MEM_ERR);
66 | }
67 |
68 | for(i = 0; i < size; i++)
69 | (void) new (&data[i]) Die(*this, channel, DIE_SIZE, physical_address+(DIE_SIZE*PLANE_SIZE*BLOCK_SIZE*i));
70 |
71 | return;
72 | }
73 |
74 | Package::~Package(void)
75 | {
76 | assert(data != NULL);
77 | uint i;
78 | /* call destructor for each Block array element
79 | * since we used malloc and placement new */
80 | for(i = 0; i < size; i++)
81 | data[i].~Die();
82 | free(data);
83 | return;
84 | }
85 |
86 | enum status Package::read(Event &event)
87 | {
88 | assert(data != NULL && event.get_address().die < size && event.get_address().valid > PACKAGE);
89 | return data[event.get_address().die].read(event);
90 | }
91 |
92 | enum status Package::write(Event &event)
93 | {
94 | assert(data != NULL && event.get_address().die < size && event.get_address().valid > PACKAGE);
95 | return data[event.get_address().die].write(event);
96 | }
97 |
98 | enum status Package::replace(Event &event)
99 | {
100 | assert(data != NULL);
101 | return data[event.get_replace_address().die].replace(event);
102 | }
103 |
104 | enum status Package::erase(Event &event)
105 | {
106 | assert(data != NULL && event.get_address().die < size && event.get_address().valid > PACKAGE);
107 | enum status status = data[event.get_address().die].erase(event);
108 | if(status == SUCCESS)
109 | update_wear_stats(event.get_address());
110 | return status;
111 | }
112 |
113 | enum status Package::merge(Event &event)
114 | {
115 | assert(data != NULL && event.get_address().die < size && event.get_address().valid > PACKAGE);
116 | return data[event.get_address().die].merge(event);
117 | }
118 |
119 | const Ssd &Package::get_parent(void) const
120 | {
121 | return parent;
122 | }
123 |
124 | /* if given a valid Block address, call the Block's method
125 | * else return local value */
126 | double Package::get_last_erase_time(const Address &address) const
127 | {
128 | assert(data != NULL);
129 | if(address.valid > PACKAGE && address.die < size)
130 | return data[address.die].get_last_erase_time(address);
131 | else
132 | return last_erase_time;
133 | }
134 |
135 | /* if given a valid Die address, call the Die's method
136 | * else return local value */
137 | ssd::ulong Package::get_erases_remaining(const Address &address) const
138 | {
139 | assert(data != NULL);
140 | if(address.valid > PACKAGE && address.die < size)
141 | return data[address.die].get_erases_remaining(address);
142 | else
143 | return erases_remaining;
144 | }
145 |
146 | ssd::uint ssd::Package::get_num_invalid(const Address & address) const
147 | {
148 | assert(address.valid >= DIE);
149 | return data[address.die].get_num_invalid(address);
150 | }
151 |
152 | /* Plane with the most erases remaining is the least worn */
153 | void Package::update_wear_stats(const Address &address)
154 | {
155 | uint i;
156 | uint max_index = 0;
157 | ulong max = data[0].get_erases_remaining(address);
158 | for(i = 1; i < size; i++)
159 | if(data[i].get_erases_remaining(address) > max)
160 | max_index = i;
161 | least_worn = max_index;
162 | erases_remaining = max;
163 | last_erase_time = data[max_index].get_last_erase_time(address);
164 | return;
165 | }
166 |
167 | /* update given address -> package to least worn package */
168 | void Package::get_least_worn(Address &address) const
169 | {
170 | assert(least_worn < size);
171 | address.die = least_worn;
172 | address.valid = DIE;
173 | data[least_worn].get_least_worn(address);
174 | return;
175 | }
176 |
177 | enum page_state Package::get_state(const Address &address) const
178 | {
179 | assert(data != NULL && address.die < size && address.valid >= PACKAGE);
180 | return data[address.die].get_state(address);
181 | }
182 |
183 | enum block_state Package::get_block_state(const Address &address) const
184 | {
185 | assert(data != NULL && address.die < size && address.valid >= PACKAGE);
186 | return data[address.die].get_block_state(address);
187 | }
188 |
189 | void Package::get_free_page(Address &address) const
190 | {
191 | assert(address.die < size && address.valid >= DIE);
192 | data[address.die].get_free_page(address);
193 | return;
194 | }
195 | ssd::uint Package::get_num_free(const Address &address) const
196 | {
197 | assert(address.valid >= DIE);
198 | return data[address.die].get_num_free(address);
199 | }
200 |
201 | ssd::uint Package::get_num_valid(const Address &address) const
202 | {
203 | assert(address.valid >= DIE);
204 | return data[address.die].get_num_valid(address);
205 | }
206 |
207 | Block *Package::get_block_pointer(const Address & address)
208 | {
209 | assert(address.valid >= DIE);
210 | return data[address.die].get_block_pointer(address);
211 | }
212 |
--------------------------------------------------------------------------------
/ssd_page.cpp:
--------------------------------------------------------------------------------
1 | /* Copyright 2009, 2010 Brendan Tauras */
2 |
3 | /* ssd_page.cpp is part of FlashSim. */
4 |
5 | /* FlashSim is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published by
7 | * the Free Software Foundation, either version 3 of the License, or
8 | * any later version. */
9 |
10 | /* FlashSim is distributed in the hope that it will be useful,
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * GNU General Public License for more details. */
14 |
15 | /* You should have received a copy of the GNU General Public License
16 | * along with FlashSim. If not, see . */
17 |
18 | /****************************************************************************/
19 |
20 | /* Page class
21 | * Brendan Tauras 2009-04-06
22 | *
23 | * The page is the lowest level data storage unit that is the size unit of
24 | * requests (events). Pages maintain their state as events modify them. */
25 |
26 | #include
27 | #include
28 | #include
29 | #include
30 |
31 | #include "ssd.h"
32 |
33 | namespace ssd {
34 | /*
35 | * Buffer used for accessing data pages.
36 | */
37 | void *global_buffer;
38 |
39 | }
40 |
41 | using namespace ssd;
42 |
43 | Page::Page(const Block &parent, double read_delay, double write_delay):
44 | state(EMPTY),
45 | parent(parent),
46 | read_delay(read_delay),
47 | write_delay(write_delay)
48 | {
49 | if(read_delay < 0.0){
50 | fprintf(stderr, "Page warning: %s: constructor received negative read delay value\n\tsetting read delay to 0.0\n", __func__);
51 | this -> read_delay = 0.0;
52 | }
53 |
54 | if(write_delay < 0.0){
55 | fprintf(stderr, "Page warning: %s: constructor received negative write delay value\n\tsetting write delay to 0.0\n", __func__);
56 | this -> write_delay = 0.0;
57 | }
58 | return;
59 | }
60 |
61 | Page::~Page(void)
62 | {
63 | return;
64 | }
65 |
66 | enum status Page::_read(Event &event)
67 | {
68 | assert(read_delay >= 0.0);
69 |
70 | event.incr_time_taken(read_delay);
71 |
72 | if (!event.get_noop() && PAGE_ENABLE_DATA)
73 | global_buffer = (char*)page_data + event.get_address().get_linear_address() * PAGE_SIZE;
74 |
75 | return SUCCESS;
76 | }
77 |
78 | enum status Page::_write(Event &event)
79 | {
80 | assert(write_delay >= 0.0);
81 |
82 | event.incr_time_taken(write_delay);
83 |
84 | if (PAGE_ENABLE_DATA && event.get_payload() != NULL && event.get_noop() == false)
85 | {
86 | void *data = (char*)page_data + event.get_address().get_linear_address() * PAGE_SIZE;
87 | memcpy (data, event.get_payload(), PAGE_SIZE);
88 | }
89 |
90 | if (event.get_noop() == false)
91 | {
92 | assert(state == EMPTY);
93 | state = VALID;
94 | }
95 |
96 | return SUCCESS;
97 | }
98 |
99 | const Block &Page::get_parent(void) const
100 | {
101 | return parent;
102 | }
103 |
104 | enum page_state Page::get_state(void) const
105 | {
106 | return state;
107 | }
108 |
109 | void Page::set_state(enum page_state state)
110 | {
111 | this -> state = state;
112 | }
113 |
--------------------------------------------------------------------------------
/ssd_plane.cpp:
--------------------------------------------------------------------------------
1 | /* Copyright 2009, 2010 Brendan Tauras */
2 |
3 | /* ssd_plane.cpp is part of FlashSim. */
4 |
5 | /* FlashSim is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published by
7 | * the Free Software Foundation, either version 3 of the License, or
8 | * any later version. */
9 |
10 | /* FlashSim is distributed in the hope that it will be useful,
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * GNU General Public License for more details. */
14 |
15 | /* You should have received a copy of the GNU General Public License
16 | * along with FlashSim. If not, see . */
17 |
18 | /****************************************************************************/
19 |
20 | /* Plane class
21 | * Brendan Tauras 2009-11-03
22 | *
23 | * The plane is the data storage hardware unit that contains blocks.
24 | * Plane-level merges are implemented in the plane. Planes maintain wear
25 | * statistics for the FTL. */
26 |
27 | #include
28 | #include
29 | #include
30 | #include "ssd.h"
31 |
32 | using namespace ssd;
33 |
34 | Plane::Plane(const Die &parent, uint plane_size, double reg_read_delay, double reg_write_delay, long physical_address):
35 | size(plane_size),
36 |
37 | /* use a const pointer (Block * const data) to use as an array
38 | * but like a reference, we cannot reseat the pointer */
39 | data((Block *) malloc(size * sizeof(Block))),
40 |
41 | parent(parent),
42 |
43 | /* assume all Blocks are same so first one can start as least worn */
44 | least_worn(0),
45 |
46 | /* set erases remaining to BLOCK_ERASES to match Block constructor args */
47 | erases_remaining(BLOCK_ERASES),
48 |
49 | /* assume hardware created at time 0 and had an implied free erasure */
50 | last_erase_time(0.0),
51 |
52 | free_blocks(size)
53 | {
54 | uint i;
55 |
56 | if(reg_read_delay < 0.0)
57 | {
58 | fprintf(stderr, "Plane error: %s: constructor received negative register read delay value\n\tsetting register read delay to 0.0\n", __func__);
59 | reg_read_delay = 0.0;
60 | }
61 | else
62 | this -> reg_read_delay = reg_read_delay;
63 |
64 | if(reg_write_delay < 0.0)
65 | {
66 | fprintf(stderr, "Plane error: %s: constructor received negative register write delay value\n\tsetting register write delay to 0.0\n", __func__);
67 | reg_write_delay = 0.0;
68 | }
69 | else
70 | this -> reg_write_delay = reg_write_delay;
71 |
72 | /* next page only uses the block, page, and valid fields of the address
73 | * object so we can ignore setting the other fields
74 | * plane does not know about higher-level hardware organization, so we cannot
75 | * set the other fields anyway */
76 | next_page.block = 0;
77 | next_page.page = 0;
78 | next_page.valid = PAGE;
79 |
80 | /* new cannot initialize an array with constructor args so
81 | * malloc the array
82 | * then use placement new to call the constructor for each element
83 | * chose an array over container class so we don't have to rely on anything
84 | * i.e. STL's std::vector */
85 | /* array allocated in initializer list:
86 | * data = (Block *) malloc(size * sizeof(Block)); */
87 | if(data == NULL){
88 | fprintf(stderr, "Plane error: %s: constructor unable to allocate Block data\n", __func__);
89 | exit(MEM_ERR);
90 | }
91 |
92 | for(i = 0; i < size; i++)
93 | {
94 | (void) new (&data[i]) Block(*this, BLOCK_SIZE, BLOCK_ERASES, BLOCK_ERASE_DELAY,physical_address+(i*BLOCK_SIZE));
95 | }
96 |
97 |
98 | return;
99 | }
100 |
101 | Plane::~Plane(void)
102 | {
103 | assert(data != NULL);
104 | uint i;
105 | /* call destructor for each Block array element
106 | * since we used malloc and placement new */
107 | for(i = 0; i < size; i++)
108 | data[i].~Block();
109 | free(data);
110 | return;
111 | }
112 |
113 | enum status Plane::read(Event &event)
114 | {
115 | assert(event.get_address().block < size && event.get_address().valid > PLANE);
116 | return data[event.get_address().block].read(event);
117 | }
118 |
119 | enum status Plane::write(Event &event)
120 | {
121 | assert(event.get_address().block < size && event.get_address().valid > PLANE && next_page.valid >= BLOCK);
122 |
123 | enum block_state prev = data[event.get_address().block].get_state();
124 |
125 | status s = data[event.get_address().block].write(event);
126 |
127 | if(event.get_address().block == next_page.block)
128 | /* if all blocks in the plane are full and this function fails,
129 | * the next_page address valid field will be set to PLANE */
130 | (void) get_next_page();
131 |
132 | if(prev == FREE && data[event.get_address().block].get_state() != FREE)
133 | free_blocks--;
134 |
135 | return s;
136 | }
137 |
138 | enum status Plane::replace(Event &event)
139 | {
140 | assert(event.get_address().block < size);
141 | return data[event.get_replace_address().block].replace(event);
142 | }
143 |
144 |
145 | /* if no errors
146 | * updates last_erase_time if later time
147 | * updates erases_remaining if smaller value
148 | * returns 1 for success, 0 for failure */
149 | enum status Plane::erase(Event &event)
150 | {
151 | assert(event.get_address().block < size && event.get_address().valid > PLANE);
152 | enum status status = data[event.get_address().block]._erase(event);
153 |
154 | /* update values if no errors */
155 | if(status == 1)
156 | {
157 | update_wear_stats();
158 | free_blocks++;
159 |
160 | /* set next free page if plane was completely full */
161 | if(next_page.valid < PAGE)
162 | (void) get_next_page();
163 | }
164 | return status;
165 | }
166 |
167 | /* handle everything for a merge operation
168 | * address.block and address_merge.block must be valid
169 | * move event::address valid pages to event::address_merge empty pages
170 | * creates own events for resulting read/write operations
171 | * supports blocks that have different sizes */
172 | enum status Plane::_merge(Event &event)
173 | {
174 | assert(event.get_address().block < size && event.get_address().valid > PLANE);
175 | assert(reg_read_delay >= 0.0 && reg_write_delay >= 0.0);
176 | uint i;
177 | uint merge_count = 0;
178 | uint merge_avail = 0;
179 | uint num_merged = 0;
180 | double total_delay = 0;
181 |
182 | /* get and check address validity and size of blocks involved in the merge */
183 | const Address &address = event.get_address();
184 | const Address &merge_address = event.get_merge_address();
185 | assert(address.compare(merge_address) >= BLOCK);
186 | assert(address.block < size && merge_address.block < size);
187 | uint block_size = data[address.block].get_size();
188 | uint merge_block_size = data[merge_address.block].get_size();
189 |
190 | /* how many pages must be moved */
191 | for(i = 0; i < block_size; i++)
192 | if(data[address.block].get_state(i) == VALID)
193 | merge_count++;
194 |
195 | /* how many pages are available */
196 | for(i = 0; i < merge_block_size; i++)
197 | if(data[merge_address.block].get_state(i) == EMPTY)
198 | merge_avail++;
199 |
200 | /* fail if not enough space to do the merge */
201 | if(merge_count > merge_avail)
202 | {
203 | fprintf(stderr, "Plane error: %s: Not enough space to merge block %d into block %d\n", __func__, address.block, merge_address.block);
204 | return FAILURE;
205 | }
206 |
207 | /* create event classes to handle read and write events for the merge */
208 | Address read(address);
209 | Address write(merge_address);
210 | read.page = 0;
211 | read.valid = PAGE;
212 | write.page = 0;
213 | write.valid = PAGE;
214 | Event read_event(READ, 0, 1, event.get_start_time());
215 | Event write_event(WRITE, 0, 1, event.get_start_time());
216 | read_event.set_address(read);
217 | write_event.set_address(write);
218 |
219 | /* calculate merge delay and add to event time
220 | * use i as an error counter */
221 | for(i = 0; num_merged < merge_count && read.page < block_size; read.page++)
222 | {
223 | /* find next page to read from */
224 | if(data[read.block].get_state(read.page) == VALID)
225 | {
226 | /* read from page and set status to invalid */
227 | if(data[read.block].read(read_event) == 0)
228 | {
229 | fprintf(stderr, "Plane error: %s: Read for merge block %d into %d failed\n", __func__, read.block, write.block);
230 | i++;
231 | }
232 | data[read.block].invalidate_page(read.page);
233 |
234 | /* get time taken for read and plane register write
235 | * read event time will accumulate and be added at end */
236 | total_delay += reg_write_delay;
237 |
238 | /* keep advancing from last page written to */
239 | for(; write.page < merge_block_size; write.page++)
240 | {
241 | /* find next page to write to */
242 | if(data[write.block].get_state(write.page) == EMPTY)
243 | {
244 | /* write to page (page::_write() sets status to valid) */
245 | if(data[merge_address.block].write(write_event) == 0)
246 | {
247 | fprintf(stderr, "Plane error: %s: Write for merge block %d into %d failed\n", __func__, address.block, merge_address.block);
248 | i++;
249 | }
250 |
251 | /* get time taken for plane register read
252 | * write event time will accumulate and be added at end */
253 | total_delay += reg_read_delay;
254 | num_merged++;
255 | break;
256 | }
257 | }
258 | }
259 | }
260 | total_delay += read_event.get_time_taken() + write_event.get_time_taken();
261 | event.incr_time_taken(total_delay);
262 |
263 | /* update next_page for the get_free_page method if we used the page */
264 | if(next_page.valid < PAGE)
265 | (void) get_next_page();
266 |
267 | if(i == 0)
268 | return SUCCESS;
269 | else
270 | {
271 | fprintf(stderr, "Plane error: %s: %u failures during merge operation\n", __func__, i);
272 | return FAILURE;
273 | }
274 | }
275 |
276 | ssd::uint Plane::get_size(void) const
277 | {
278 | return size;
279 | }
280 |
281 | const Die &Plane::get_parent(void) const
282 | {
283 | return parent;
284 | }
285 |
286 | /* if given a valid Block address, call the Block's method
287 | * else return local value */
288 | double Plane::get_last_erase_time(const Address &address) const
289 | {
290 | assert(data != NULL);
291 | if(address.valid > PLANE && address.block < size)
292 | return data[address.block].get_last_erase_time();
293 | else
294 | return last_erase_time;
295 | }
296 |
297 | /* if given a valid Block address, call the Block's method
298 | * else return local value */
299 | ssd::ulong Plane::get_erases_remaining(const Address &address) const
300 | {
301 | assert(data != NULL);
302 | if(address.valid > PLANE && address.block < size)
303 | return data[address.block].get_erases_remaining();
304 | else
305 | return erases_remaining;
306 | }
307 |
308 | /* Block with the most erases remaining is the least worn */
309 | void Plane::update_wear_stats(void)
310 | {
311 | uint i;
312 | uint max_index = 0;
313 | ulong max = data[0].get_erases_remaining();
314 | for(i = 1; i < size; i++)
315 | if(data[i].get_erases_remaining() > max)
316 | max_index = i;
317 | least_worn = max_index;
318 | erases_remaining = max;
319 | last_erase_time = data[max_index].get_last_erase_time();
320 | return;
321 | }
322 |
323 | /* update given address.block to least worn block */
324 | void Plane::get_least_worn(Address &address) const
325 | {
326 | assert(least_worn < size);
327 | address.block = least_worn;
328 | address.valid = BLOCK;
329 | return;
330 | }
331 |
332 | enum page_state Plane::get_state(const Address &address) const
333 | {
334 | assert(data != NULL && address.block < size && address.valid >= PLANE);
335 | return data[address.block].get_state(address);
336 | }
337 |
338 | enum block_state Plane::get_block_state(const Address &address) const
339 | {
340 | assert(data != NULL && address.block < size && address.valid >= PLANE);
341 | return data[address.block].get_state();
342 | }
343 |
344 | /* update address to next free page in plane
345 | * error condition will result in (address.valid < PAGE) */
346 | void Plane::get_free_page(Address &address) const
347 | {
348 | assert(data[address.block].get_pages_valid() < BLOCK_SIZE);
349 |
350 | address.page = data[address.block].get_pages_valid();
351 | address.valid = PAGE;
352 | address.set_linear_address(address.get_linear_address()+ address.page - (address.get_linear_address()%BLOCK_SIZE));
353 | return;
354 | }
355 |
356 | /* internal method to keep track of the next usable (free or active) page in
357 | * this plane
358 | * method is called by write and erase methods and calls Block::get_next_page()
359 | * such that the get_free_page method can run in constant time */
360 | enum status Plane::get_next_page(void)
361 | {
362 | return SUCCESS;
363 |
364 | uint i;
365 | next_page.valid = PLANE;
366 |
367 | for(i = 0; i < size; i++)
368 | {
369 | if(data[i].get_state() != INACTIVE)
370 | {
371 | next_page.valid = BLOCK;
372 | if(data[i].get_next_page(next_page) == SUCCESS)
373 | {
374 | next_page.block = i;
375 | return SUCCESS;
376 | }
377 | }
378 | }
379 | return FAILURE;
380 | }
381 |
382 | /* free_blocks is updated in the write and erase methods */
383 | ssd::uint Plane::get_num_free(const Address &address) const
384 | {
385 | assert(address.valid >= PLANE);
386 | return free_blocks;
387 | }
388 |
389 | ssd::uint Plane::get_num_valid(const Address &address) const
390 | {
391 | assert(address.valid >= PLANE);
392 | return data[address.block].get_pages_valid();
393 | }
394 |
395 | ssd::uint Plane::get_num_invalid(const Address & address) const
396 | {
397 | assert(address.valid >= PLANE);
398 | return data[address.block].get_pages_invalid();
399 | }
400 |
401 | Block *Plane::get_block_pointer(const Address & address)
402 | {
403 | assert(address.valid >= PLANE);
404 | return data[address.block].get_pointer();
405 | }
406 |
--------------------------------------------------------------------------------
/ssd_raidssd.cpp:
--------------------------------------------------------------------------------
1 | /* Copyright 2012 Matias Bjørling */
2 |
3 | /* FlashSim is free software: you can redistribute it and/or modify
4 | * it under the terms of the GNU General Public License as published by
5 | * the Free Software Foundation, either version 3 of the License, or
6 | * any later version. */
7 |
8 | /* FlashSim is distributed in the hope that it will be useful,
9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 | * GNU General Public License for more details. */
12 |
13 | /* You should have received a copy of the GNU General Public License
14 | * along with FlashSim. If not, see . */
15 |
16 | /****************************************************************************/
17 |
18 | /* Ssd class
19 | * Matias Bjørling 2012-01-09
20 | *
21 | * The Raid SSD is responsible for raiding multiple SSDs together using different mapping techniques.
22 | */
23 |
24 | #include
25 | #include
26 | #include
27 | #include
28 | #include "ssd.h"
29 | #include
30 | #include
31 | #include
32 | #include
33 | #include
34 |
35 | using namespace ssd;
36 |
37 | /* use caution when editing the initialization list - initialization actually
38 | * occurs in the order of declaration in the class definition and not in the
39 | * order listed here */
40 | RaidSsd::RaidSsd(uint ssd_size):
41 | size(ssd_size)
42 | {
43 | /*
44 | * Idea
45 | *
46 | * Create the instances of the SSDs.
47 | *
48 | * Techniques
49 | *
50 | * 1. Striping
51 | * 2. Address splitting.
52 | * 3. Complete control
53 | */
54 | Ssds = new Ssd[RAID_NUMBER_OF_PHYSICAL_SSDS];
55 |
56 | return;
57 | }
58 |
59 | RaidSsd::~RaidSsd(void)
60 | {
61 | return;
62 | }
63 |
64 | double RaidSsd::event_arrive(enum event_type type, ulong logical_address, uint size, double start_time)
65 | {
66 | return event_arrive(type, logical_address, size, start_time, NULL);
67 | }
68 |
69 | /* This is the function that will be called by DiskSim
70 | * Provide the event (request) type (see enum in ssd.h),
71 | * logical_address (page number), size of request in pages, and the start
72 | * time (arrive time) of the request
73 | * The SSD will process the request and return the time taken to process the
74 | * request. Remember to use the same time units as in the config file. */
75 | double RaidSsd::event_arrive(enum event_type type, ulong logical_address, uint size, double start_time, void *buffer)
76 | {
77 | if (type == WRITE)
78 | printf("Writing to logical address: %lu\n", logical_address);
79 | else if (type == READ)
80 | printf("Read from logical address: %lu\n", logical_address);
81 |
82 | if (PARALLELISM_MODE == 1) // Striping
83 | {
84 | double timings[RAID_NUMBER_OF_PHYSICAL_SSDS];
85 | for (int i=0;i. */
17 |
18 | /****************************************************************************/
19 |
20 | /* Ram class
21 | *
22 | * Brendan Tauras 2009-06-03
23 | *
24 | * This is a basic implementation that only provides delay updates to events
25 | * based on a delay value multiplied by the size (number of pages) needed to
26 | * be read or written.
27 | */
28 |
29 | #include
30 | #include
31 | #include "ssd.h"
32 |
33 | using namespace ssd;
34 |
35 |
36 | Ram::Ram(double read_delay, double write_delay):
37 | read_delay(read_delay),
38 | write_delay(write_delay)
39 | {
40 | if(read_delay <= 0)
41 | {
42 | fprintf(stderr, "RAM: %s: constructor received negative read delay value\n\tsetting read delay to 0.0\n", __func__);
43 | read_delay = 0.0;
44 | }
45 | if(write_delay <= 0)
46 | {
47 | fprintf(stderr, "RAM: %s: constructor received negative write delay value\n\tsetting write delay to 0.0\n", __func__);
48 | write_delay = 0.0;
49 | }
50 | return;
51 | }
52 |
53 | Ram::~Ram(void)
54 | {
55 | return;
56 | }
57 |
58 | enum status Ram::read(Event &event)
59 | {
60 | assert(read_delay >= 0.0);
61 | (void) event.incr_time_taken(read_delay * event.get_size());
62 | return SUCCESS;
63 | }
64 |
65 | enum status Ram::write(Event &event)
66 | {
67 | assert(write_delay >= 0.0);
68 | (void) event.incr_time_taken(write_delay * event.get_size());
69 | return SUCCESS;
70 | }
71 |
--------------------------------------------------------------------------------
/ssd_ssd.cpp:
--------------------------------------------------------------------------------
1 | /* Copyright 2009, 2010 Brendan Tauras */
2 |
3 | /* ssd_ssd.cpp is part of FlashSim. */
4 |
5 | /* FlashSim is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published by
7 | * the Free Software Foundation, either version 3 of the License, or
8 | * any later version. */
9 |
10 | /* FlashSim is distributed in the hope that it will be useful,
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * GNU General Public License for more details. */
14 |
15 | /* You should have received a copy of the GNU General Public License
16 | * along with FlashSim. If not, see . */
17 |
18 | /****************************************************************************/
19 |
20 | /* Ssd class
21 | * Brendan Tauras 2009-11-03
22 | *
23 | * The SSD is the single main object that will be created to simulate a real
24 | * SSD. Creating a SSD causes all other objects in the SSD to be created. The
25 | * event_arrive method is where events will arrive from DiskSim. */
26 |
27 | #include
28 | #include
29 | #include
30 | #include
31 | #include "ssd.h"
32 | #include
33 | #include
34 | #include
35 | #include
36 | #include
37 | #include
38 |
39 | using namespace ssd;
40 |
41 | /* use caution when editing the initialization list - initialization actually
42 | * occurs in the order of declaration in the class definition and not in the
43 | * order listed here */
44 | Ssd::Ssd(uint ssd_size):
45 | size(ssd_size),
46 | controller(*this),
47 | ram(RAM_READ_DELAY, RAM_WRITE_DELAY),
48 | bus(size, BUS_CTRL_DELAY, BUS_DATA_DELAY, BUS_TABLE_SIZE, BUS_MAX_CONNECT),
49 |
50 | /* use a const pointer (Package * const data) to use as an array
51 | * but like a reference, we cannot reseat the pointer */
52 | data((Package *) malloc(ssd_size * sizeof(Package))),
53 |
54 | /* set erases remaining to BLOCK_ERASES to match Block constructor args
55 | * in Plane class
56 | * this is the cheap implementation but can change to pass through classes */
57 | erases_remaining(BLOCK_ERASES),
58 |
59 | /* assume all Planes are same so first one can start as least worn */
60 | least_worn(0),
61 |
62 | /* assume hardware created at time 0 and had an implied free erasure */
63 | last_erase_time(0.0)
64 | {
65 | uint i;
66 |
67 | /* new cannot initialize an array with constructor args so
68 | * malloc the array
69 | * then use placement new to call the constructor for each element
70 | * chose an array over container class so we don't have to rely on anything
71 | * i.e. STL's std::vector */
72 | /* array allocated in initializer list:
73 | * data = (Package *) malloc(ssd_size * sizeof(Package)); */
74 | if(data == NULL){
75 | fprintf(stderr, "Ssd error: %s: constructor unable to allocate Package data\n", __func__);
76 | exit(MEM_ERR);
77 | }
78 | for (i = 0; i < ssd_size; i++)
79 | {
80 | (void) new (&data[i]) Package(*this, bus.get_channel(i), PACKAGE_SIZE, PACKAGE_SIZE*DIE_SIZE*PLANE_SIZE*BLOCK_SIZE*i);
81 | }
82 |
83 | // Check for 32bit machine. We do not allow page data on 32bit machines.
84 | if (PAGE_ENABLE_DATA == 1 && sizeof(void*) == 4)
85 | {
86 | fprintf(stderr, "Ssd error: %s: The simulator requires a 64bit kernel when using data pages. Disabling data pages.\n", __func__);
87 | exit(MEM_ERR);
88 | }
89 |
90 | if (PAGE_ENABLE_DATA)
91 | {
92 | /* Allocate memory for data pages */
93 | ulong pageSize = ((ulong)(SSD_SIZE * PACKAGE_SIZE * DIE_SIZE * PLANE_SIZE * BLOCK_SIZE)) * (ulong)PAGE_SIZE;
94 | #ifdef __APPLE__
95 | page_data = mmap(NULL, pageSize, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS|MAP_NORESERVE, -1, 0);
96 | #else
97 | page_data = mmap64(NULL, pageSize, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS|MAP_NORESERVE, -1 ,0);
98 | #endif
99 |
100 | if (page_data == MAP_FAILED)
101 | {
102 | fprintf(stderr, "Ssd error: %s: constructor unable to allocate page data.\n", __func__);
103 | switch (errno)
104 | {
105 | case EACCES:
106 | break;
107 | }
108 | printf("%i\n",errno);
109 | exit(MEM_ERR);
110 | }
111 | }
112 |
113 | assert(VIRTUAL_BLOCK_SIZE > 0);
114 | assert(VIRTUAL_PAGE_SIZE > 0);
115 |
116 | return;
117 | }
118 |
119 | Ssd::~Ssd(void)
120 | {
121 | /* explicitly call destructors and use free
122 | * since we used malloc and placement new */
123 | for (uint i = 0; i < size; i++)
124 | {
125 | data[i].~Package();
126 | }
127 | free(data);
128 | ulong pageSize = ((ulong)(SSD_SIZE * PACKAGE_SIZE * DIE_SIZE * PLANE_SIZE * BLOCK_SIZE)) * (ulong)PAGE_SIZE;
129 | munmap(page_data, pageSize);
130 |
131 | return;
132 | }
133 |
134 | double Ssd::event_arrive(enum event_type type, ulong logical_address, uint size, double start_time)
135 | {
136 | return event_arrive(type, logical_address, size, start_time, NULL);
137 | }
138 |
139 | /* This is the function that will be called by DiskSim
140 | * Provide the event (request) type (see enum in ssd.h),
141 | * logical_address (page number), size of request in pages, and the start
142 | * time (arrive time) of the request
143 | * The SSD will process the request and return the time taken to process the
144 | * request. Remember to use the same time units as in the config file. */
145 | double Ssd::event_arrive(enum event_type type, ulong logical_address, uint size, double start_time, void *buffer)
146 | {
147 | assert(start_time >= 0.0);
148 |
149 | if (VIRTUAL_PAGE_SIZE == 1)
150 | assert((long long int) logical_address <= (long long int) SSD_SIZE * PACKAGE_SIZE * DIE_SIZE * PLANE_SIZE * BLOCK_SIZE);
151 | else
152 | assert((long long int) logical_address*VIRTUAL_PAGE_SIZE <= (long long int) SSD_SIZE * PACKAGE_SIZE * DIE_SIZE * PLANE_SIZE * BLOCK_SIZE);
153 |
154 | /* allocate the event and address dynamically so that the allocator can
155 | * handle efficiency issues for us */
156 | Event *event = NULL;
157 |
158 | if((event = new Event(type, logical_address , size, start_time)) == NULL)
159 | {
160 | fprintf(stderr, "Ssd error: %s: could not allocate Event\n", __func__);
161 | exit(MEM_ERR);
162 | }
163 |
164 | event->set_payload(buffer);
165 |
166 | if(controller.event_arrive(*event) != SUCCESS)
167 | {
168 | fprintf(stderr, "Ssd error: %s: request failed:\n", __func__);
169 | event -> print(stderr);
170 | }
171 |
172 | /* use start_time as a temporary for returning time taken to service event */
173 | start_time = event -> get_time_taken();
174 | delete event;
175 | return start_time;
176 | }
177 |
178 | /*
179 | * Returns a pointer to the global buffer of the Ssd.
180 | * It is up to the user to not read out of bound and only
181 | * read the intended size. i.e. the page size.
182 | */
183 | void *Ssd::get_result_buffer()
184 | {
185 | return global_buffer;
186 | }
187 |
188 | /* read write erase and merge should only pass on the event
189 | * the Controller should lock the bus channels
190 | * technically the Package is conceptual, but we keep track of statistics
191 | * and addresses with Packages, so send Events through Package but do not
192 | * have Package do anything but update its statistics and pass on to Die */
193 | enum status Ssd::read(Event &event)
194 | {
195 | assert(data != NULL && event.get_address().package < size && event.get_address().valid >= PACKAGE);
196 | return data[event.get_address().package].read(event);
197 | }
198 |
199 | enum status Ssd::write(Event &event)
200 | {
201 | assert(data != NULL && event.get_address().package < size && event.get_address().valid >= PACKAGE);
202 | return data[event.get_address().package].write(event);
203 | }
204 |
205 | enum status Ssd::replace(Event &event)
206 | {
207 | if(event.get_replace_address().valid == NONE)
208 | return SUCCESS;
209 | assert(data != NULL && event.get_replace_address().package < size);
210 | if (event.get_replace_address().valid == PAGE)
211 | return data[event.get_replace_address().package].replace(event);
212 | else
213 | return SUCCESS;
214 | }
215 |
216 |
217 | enum status Ssd::erase(Event &event)
218 | {
219 | assert(data != NULL && event.get_address().package < size && event.get_address().valid >= PACKAGE);
220 | enum status status = data[event.get_address().package].erase(event);
221 |
222 | /* update values if no errors */
223 | if (status == SUCCESS)
224 | update_wear_stats(event.get_address());
225 | return status;
226 | }
227 |
228 | enum status Ssd::merge(Event &event)
229 | {
230 | assert(data != NULL && event.get_address().package < size && event.get_address().valid >= PACKAGE);
231 | return data[event.get_address().package].merge(event);
232 | }
233 |
234 | enum status Ssd::merge_replacement_block(Event &event)
235 | {
236 | //assert(data != NULL && event.get_address().package < size && event.get_address().valid >= PACKAGE && event.get_log_address().valid >= PACKAGE);
237 | return SUCCESS;
238 | }
239 |
240 | /* add up the erases remaining for all packages in the ssd*/
241 | ssd::ulong Ssd::get_erases_remaining(const Address &address) const
242 | {
243 | assert (data != NULL);
244 |
245 | if (address.package < size && address.valid >= PACKAGE)
246 | return data[address.package].get_erases_remaining(address);
247 | else return erases_remaining;
248 | }
249 |
250 | void Ssd::update_wear_stats(const Address &address)
251 | {
252 | assert(data != NULL);
253 | uint i;
254 | uint max_index = 0;
255 | ulong max = data[0].get_erases_remaining(address);
256 | for(i = 1; i < size; i++)
257 | if(data[i].get_erases_remaining(address) > max)
258 | max_index = i;
259 | least_worn = max_index;
260 | erases_remaining = max;
261 | last_erase_time = data[max_index].get_last_erase_time(address);
262 | return;
263 | }
264 |
265 | void Ssd::get_least_worn(Address &address) const
266 | {
267 | assert(data != NULL && least_worn < size);
268 | address.package = least_worn;
269 | address.valid = PACKAGE;
270 | data[least_worn].get_least_worn(address);
271 | return;
272 | }
273 |
274 | double Ssd::get_last_erase_time(const Address &address) const
275 | {
276 | assert(data != NULL);
277 | if(address.package < size && address.valid >= PACKAGE)
278 | return data[address.package].get_last_erase_time(address);
279 | else
280 | return last_erase_time;
281 | }
282 |
283 | enum page_state Ssd::get_state(const Address &address) const
284 | {
285 | assert(data != NULL);
286 | assert(address.package < size && address.valid >= PACKAGE);
287 | return data[address.package].get_state(address);
288 | }
289 |
290 | enum block_state Ssd::get_block_state(const Address &address) const
291 | {
292 | assert(data != NULL);
293 | assert(address.package < size && address.valid >= PACKAGE);
294 | return data[address.package].get_block_state(address);
295 | }
296 |
297 | void Ssd::get_free_page(Address &address) const
298 | {
299 | assert(address.package < size && address.valid >= PACKAGE);
300 | data[address.package].get_free_page(address);
301 | return;
302 | }
303 |
304 | ssd::uint Ssd::get_num_free(const Address &address) const
305 | {
306 | return 0;
307 | /* return data[address.package].get_num_free(address); */
308 | }
309 |
310 | ssd::uint Ssd::get_num_valid(const Address &address) const
311 | {
312 | assert(address.valid >= PACKAGE);
313 | return data[address.package].get_num_valid(address);
314 | }
315 |
316 | ssd::uint Ssd::get_num_invalid(const Address &address) const
317 | {
318 | assert(address.valid >= PACKAGE);
319 | return data[address.package].get_num_invalid(address);
320 | }
321 |
322 | void Ssd::print_statistics()
323 | {
324 | controller.stats.print_statistics();
325 | }
326 |
327 | void Ssd::reset_statistics()
328 | {
329 | controller.stats.reset_statistics();
330 | }
331 |
332 | void Ssd::write_statistics(FILE *stream)
333 | {
334 | controller.stats.write_statistics(stream);
335 | }
336 |
337 | void Ssd::print_ftl_statistics()
338 | {
339 | controller.print_ftl_statistics();
340 | }
341 |
342 | void Ssd::write_header(FILE *stream)
343 | {
344 | controller.stats.write_header(stream);
345 | }
346 |
347 | Block *Ssd::get_block_pointer(const Address & address)
348 | {
349 | assert(address.valid >= PACKAGE);
350 | return data[address.package].get_block_pointer(address);
351 | }
352 |
353 | const Controller &Ssd::get_controller(void) const
354 | {
355 | return controller;
356 | }
357 |
358 | /**
359 | * Returns the next ready time. The ready time is the latest point in time when one of the channels are ready to serve new requests.
360 | */
361 | double Ssd::ready_at(void)
362 | {
363 | double next_ready_time = std::numeric_limits::max();
364 |
365 | for (int i=0;i::max())
374 | return -1;
375 | else
376 | return next_ready_time;
377 | }
378 |
--------------------------------------------------------------------------------
/ssd_stats.cpp:
--------------------------------------------------------------------------------
1 | /* Copyright 2011 Matias Bjørling */
2 |
3 | /* dftp_ftl.cpp */
4 |
5 | /* FlashSim is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published by
7 | * the Free Software Foundation, either version 3 of the License, or
8 | * any later version. */
9 |
10 | /* FlashSim is distributed in the hope that it will be useful,
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * GNU General Public License for more details. */
14 |
15 | /* You should have received a copy of the GNU General Public License
16 | * along with FlashSim. If not, see . */
17 |
18 | /****************************************************************************/
19 |
20 | /* Runtime information for the SSD Model
21 | */
22 |
23 | #include
24 | #include
25 | #include
26 | #include
27 | #include
28 | #include "ssd.h"
29 |
30 | using namespace ssd;
31 |
32 | Stats::Stats()
33 | {
34 | reset();
35 | }
36 |
37 | void Stats::reset()
38 | {
39 | // FTL
40 | numFTLRead = 0;
41 | numFTLWrite = 0;
42 | numFTLErase = 0;
43 | numFTLTrim = 0;
44 |
45 | //GC
46 | numGCRead = 0;
47 | numGCWrite = 0;
48 | numGCErase = 0;
49 |
50 | // WL
51 | numWLRead = 0;
52 | numWLWrite = 0;
53 | numWLErase = 0;
54 |
55 | // Log based FTL's
56 | numLogMergeSwitch = 0;
57 | numLogMergePartial = 0;
58 | numLogMergeFull = 0;
59 |
60 | // Page based FTL's
61 | numPageBlockToPageConversion = 0;
62 |
63 | // Cache based FTL's
64 | numCacheHits = 0;
65 | numCacheFaults = 0;
66 |
67 | // Memory consumptions (Bytes)
68 | numMemoryTranslation = 0;
69 | numMemoryCache = 0;
70 |
71 | numMemoryRead = 0;
72 | numMemoryWrite = 0;
73 | }
74 |
75 | void Stats::reset_statistics()
76 | {
77 | reset();
78 | }
79 |
80 | void Stats::write_header(FILE *stream)
81 | {
82 | fprintf(stream, "numFTLRead;numFTLWrite;numFTLErase;numFTLTrim;numGCRead;numGCWrite;numGCErase;numWLRead;numWLWrite;numWLErase;numLogMergeSwitch;numLogMergePartial;numLogMergeFull;numPageBlockToPageConversion;numCacheHits;numCacheFaults;numMemoryTranslation;numMemoryCache;numMemoryRead;numMemoryWrite\n");
83 | }
84 |
85 | void Stats::write_statistics(FILE *stream)
86 | {
87 | fprintf(stream, "%li;%li;%li;%li;%li;%li;%li;%li;%li;%li;%li;%li;%li;%li;%li;%li;%li;%li;%li;%li;\n",
88 | numFTLRead, numFTLWrite, numFTLErase, numFTLTrim,
89 | numGCRead, numGCWrite, numGCErase,
90 | numWLRead, numWLWrite, numWLErase,
91 | numLogMergeSwitch, numLogMergePartial, numLogMergeFull,
92 | numPageBlockToPageConversion,
93 | numCacheHits, numCacheFaults,
94 | numMemoryTranslation,
95 | numMemoryCache,
96 | numMemoryRead,numMemoryWrite);
97 |
98 | //print_statistics();
99 | }
100 |
101 | void Stats::print_statistics()
102 | {
103 | printf("Statistics:\n");
104 | printf("-----------\n");
105 | printf("FTL Reads: %li\t Writes: %li\t Erases: %li\t Trims: %li\n", numFTLRead, numFTLWrite, numFTLErase, numFTLTrim);
106 | printf("GC Reads: %li\t Writes: %li\t Erases: %li\n", numGCRead, numGCWrite, numGCErase);
107 | printf("WL Reads: %li\t Writes: %li\t Erases: %li\n", numWLRead, numWLWrite, numWLErase);
108 | printf("Log FTL Switch: %li Partial: %li Full: %li\n", numLogMergeSwitch, numLogMergePartial, numLogMergeFull);
109 | printf("Page FTL Convertions: %li\n", numPageBlockToPageConversion);
110 | printf("Cache Hits: %li Faults: %li Hit Ratio: %f\n", numCacheHits, numCacheFaults, (double)numCacheHits/(double)(numCacheHits+numCacheFaults));
111 | printf("Memory Consumption:\n");
112 | printf("Tranlation: %li Cache: %li\n", numMemoryTranslation, numMemoryCache);
113 | printf("Reads: %li \tWrites: %li\n", numMemoryRead, numMemoryWrite);
114 | printf("-----------\n");
115 | }
116 |
--------------------------------------------------------------------------------
/ssd_wl.cpp:
--------------------------------------------------------------------------------
1 | /* Copyright 2009, 2010 Brendan Tauras */
2 |
3 | /* ssd_wl.cpp is part of FlashSim. */
4 |
5 | /* FlashSim is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published by
7 | * the Free Software Foundation, either version 3 of the License, or
8 | * any later version. */
9 |
10 | /* FlashSim is distributed in the hope that it will be useful,
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * GNU General Public License for more details. */
14 |
15 | /* You should have received a copy of the GNU General Public License
16 | * along with FlashSim. If not, see . */
17 |
18 | /****************************************************************************/
19 |
20 | /* Wear_leveler class
21 | * Brendan Tauras 2009-11-04
22 | *
23 | * This class is a stub class for the user to use as a template for implementing
24 | * his/her wear leveler scheme. The wear leveler class was added to simplify
25 | * and modularize the wear-leveling in FTL schemes. */
26 |
27 | #include
28 | #include
29 | #include
30 | #include "ssd.h"
31 |
32 | using namespace ssd;
33 |
34 | Wear_leveler::Wear_leveler(FtlParent &ftl)
35 | {
36 |
37 | return;
38 | }
39 |
40 | Wear_leveler::~Wear_leveler(void)
41 | {
42 | return;
43 | }
44 |
45 | enum status Wear_leveler::insert(const Address &address)
46 | {
47 | return SUCCESS;
48 | }
49 |
--------------------------------------------------------------------------------
/uml:
--------------------------------------------------------------------------------
1 | Copyright 2009, 2010 Brendan Tauras
2 |
3 | uml.* are part of FlashSim.
4 |
5 | FlashSim is free software: you can redistribute it and/or modify
6 | it under the terms of the GNU General Public License as published by
7 | the Free Software Foundation, either version 3 of the License, or
8 | any later version.
9 |
10 | FlashSim is distributed in the hope that it will be useful,
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | GNU General Public License for more details.
14 |
15 | You should have received a copy of the GNU General Public License
16 | along with FlashSim. If not, see .
17 |
18 | ##############################################################################
19 |
20 |
--------------------------------------------------------------------------------
/uml.dia:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MatiasBjorling/flashsim/53098b017a4dbbe27665a755000738ed70862141/uml.dia
--------------------------------------------------------------------------------
/uml.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MatiasBjorling/flashsim/53098b017a4dbbe27665a755000738ed70862141/uml.pdf
--------------------------------------------------------------------------------
/verification.cpp:
--------------------------------------------------------------------------------
1 | /* FlashSim is free software: you can redistribute it and/or modify
2 | * it under the terms of the GNU General Public License as published by
3 | * the Free Software Foundation, either version 3 of the License, or
4 | * any later version. */
5 |
6 | /* FlashSim is distributed in the hope that it will be useful,
7 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
8 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 | * GNU General Public License for more details. */
10 |
11 | /* You should have received a copy of the GNU General Public License
12 | * along with FlashSim. If not, see . */
13 |
14 | /****************************************************************************/
15 |
16 | #include
17 | #include
18 | #include
19 | #include
20 | #include
21 | #include
22 | #include
23 | #include
24 | #include
25 | #include "ssd.h"
26 |
27 | using namespace ssd;
28 |
29 | int main(int argc, char **argv){
30 |
31 | long vaddr;
32 |
33 | double arrive_time;
34 |
35 | double afterFormatStartTime = 0;
36 |
37 | load_config();
38 | print_config(NULL);
39 |
40 | Ssd ssd;
41 |
42 | printf("INITIALIZING SSD\n");
43 |
44 | srandom(1);
45 | int preIO = SSD_SIZE * PACKAGE_SIZE * DIE_SIZE * PLANE_SIZE * BLOCK_SIZE;
46 |
47 | if (FTL_IMPLEMENTATION == 0) // PAGE
48 | preIO -= 16*BLOCK_SIZE;
49 |
50 | if (FTL_IMPLEMENTATION == 1) // BAST
51 | preIO -= (BAST_LOG_BLOCK_LIMIT*BLOCK_SIZE)*1.3;
52 |
53 | if (FTL_IMPLEMENTATION == 2) // FAST
54 | preIO -= (FAST_LOG_BLOCK_LIMIT*BLOCK_SIZE)*1.1;
55 |
56 | if (FTL_IMPLEMENTATION > 2) // DFTL BIFTL
57 | preIO -= 1024;
58 |
59 | int deviceSize = 3145216;
60 |
61 | if (preIO > deviceSize)
62 | preIO = deviceSize;
63 |
64 | printf("Writes %i pages for startup out of %i total pages.\n", preIO, SSD_SIZE * PACKAGE_SIZE * DIE_SIZE * PLANE_SIZE * BLOCK_SIZE);
65 |
66 | double start_time = afterFormatStartTime;
67 | double timeMultiplier = 10000;
68 |
69 | FILE *logFile = NULL;
70 | if ((logFile = fopen("output.log", "w")) == NULL)
71 | {
72 | printf("Output file cannot be written to.\n");
73 | exit(-1);
74 | }
75 |
76 | fprintf(logFile, "NumIOReads;ReadIOTime;NumIOWrites;WriteIOTime;NumIOTotal;IOTime;");
77 | ssd.write_header(logFile);
78 |
79 | double read_time = 0;
80 | double write_time = 0;
81 |
82 | unsigned long num_reads = 0;
83 | unsigned long num_writes = 0;
84 |
85 | std::vector avgs;
86 |
87 | // Reset statistics
88 | ssd.reset_statistics();
89 |
90 | num_reads = 0;
91 | read_time = 0;
92 |
93 | num_writes = 0;
94 | write_time = 0;
95 |
96 | int addressDivisor = 1;
97 | float multiplier = 1;
98 |
99 | //ssd.reset_statistics();
100 |
101 | avgs.reserve(preIO);
102 |
103 |
104 |
105 | // /* Test 1 */
106 | // for (int i=0; i preIO/2-seqSize/2 && preIO/2+seqSize/2 > r);
148 | //
149 | // write_time = ssd.event_arrive(WRITE, r, 1, ((start_time+arrive_time)*timeMultiplier));
150 | // avgs.push_back(write_time);
151 | // num_writes++;
152 | //
153 | // arrive_time += write_time;
154 | //
155 | // if (i % 100000 == 0)
156 | // printf("%i\n", i);
157 | // }
158 |
159 | ssd.print_ftl_statistics();
160 |
161 | /* Test 3 Start -------------------------------------------------------------------------- */
162 | srandom(1);
163 | int seqSize = 128*64;
164 |
165 | for (int i=0; i