/* * reads the data out of a page and writes it back the active page. */ static double ssd_clean_one_page (int lp_num, int pp_index, int blk, int plane_num, int elem_num, ssd_element_metadata *metadata, ssd_t *s) { double cost = 0; double xfer_cost = 0; cost += s->params.page_read_latency; cost += ssd_move_page(lp_num, blk, plane_num, elem_num, s); // if the write is within the same plane, then the data need // not cross the pins. but if not, add the cost of transferring // the bytes across the pins xfer_cost = ssd_crossover_cost(s, metadata, blk, SSD_PAGE_TO_BLOCK(metadata->active_page, s)); cost += xfer_cost; ssd_assert_valid_pages(plane_num, metadata, s); ASSERT(metadata->block_usage[blk].page[pp_index] == -1); // stat -- we move 'valid_pages' out of this block s->elements[elem_num].stat.pages_moved ++; s->elements[elem_num].stat.tot_xfer_cost += xfer_cost; return cost; }
double ssd_fullmerge(ssd_t *s, ssd_element_metadata *metadata, ssd_power_element_stat *power_stat, int lbn, int elem_num) { int prev_block = metadata->lba_table[lbn]; int log_index = metadata->block_usage[prev_block].log_index; int log_block = metadata->log_data[log_index].bsn; int num_valid = 0; int num_valid_d = metadata->block_usage[prev_block].num_valid; int num_valid_u = metadata->block_usage[log_block].num_valid; int prev_plane_num = metadata->block_usage[prev_block].plane_num; int log_plane_num = metadata->block_usage[log_block].plane_num; int plane_num; int active_block; int i; double cost = 0.0; double r_cost, w_cost, xfer_cost; //set active_block metadata->active_block = metadata->plane_meta[prev_plane_num].active_block; active_block = metadata->active_block; _ssd_alloc_active_block(prev_plane_num, elem_num, s); plane_num = metadata->block_usage[active_block].plane_num; metadata->plane_meta[prev_plane_num].clean_in_block = prev_block; metadata->plane_meta[prev_plane_num].clean_in_progress = 1; metadata->plane_meta[log_plane_num].clean_in_block = prev_block; metadata->plane_meta[log_plane_num].clean_in_progress = 1; //page state copy & init page state for( i = 0 ; i < s->params.pages_per_block ; i++) { if((metadata->block_usage[prev_block].page[i] == 1) || (metadata->log_data[log_index].page[i] != -1)){ metadata->block_usage[active_block].page[i] = 1; } metadata->block_usage[prev_block].page[i] = -1; metadata->log_data[log_index].page[i] = -1; metadata->block_usage[log_block].page[i] = -1; } metadata->lba_table[lbn] = active_block; //update stat //update log_table metadata->block_usage[prev_block].log_index = -1; metadata->log_data[log_index].bsn = -1; metadata->log_data[log_index].data_block = -1; metadata->log_pos = log_index; metadata->num_log--; //update block usage metadata->block_usage[prev_block].num_valid = 0; metadata->block_usage[log_block].num_valid = 0; //update plane data metadata->plane_meta[prev_plane_num].valid_pages -= num_valid_d; metadata->plane_meta[log_plane_num].valid_pages -= num_valid_u; num_valid += num_valid_d; num_valid += num_valid_u; if(num_valid > s->params.pages_per_block) { fprintf(outputfile3, "Error number of pages : valid_page %d, Real_page %d\n", num_valid, s->params.pages_per_block); fprintf(outputfile3, "Error elem_num %d, lbn %d, original block %d, log block %d\n", elem_num, lbn, prev_block, log_block); exit(-1); } metadata->block_usage[active_block].num_valid = num_valid; metadata->plane_meta[plane_num].valid_pages += num_valid; //data tranfer cost //read r_cost = s->params.page_read_latency * num_valid; cost += r_cost; ssd_power_flash_calculate(SSD_POWER_FLASH_READ, r_cost, power_stat, s); //write w_cost = s->params.page_write_latency * num_valid; cost += w_cost; ssd_power_flash_calculate(SSD_POWER_FLASH_WRITE, w_cost, power_stat, s); //transfer cost for( i = 0 ; i < num_valid ; i++) { double xfer_cost; xfer_cost = ssd_crossover_cost(s, metadata, power_stat, prev_block, active_block); cost += xfer_cost; s->elements[elem_num].stat.tot_xfer_cost += xfer_cost; } //erase two block(D) cost += s->params.block_erase_latency; ssd_power_flash_calculate(SSD_POWER_FLASH_ERASE, s->params.block_erase_latency, power_stat, s); ssd_update_free_block_status(prev_block, prev_plane_num, metadata, s); ssd_update_block_lifetime(simtime+cost, prev_block, metadata); metadata->plane_meta[prev_plane_num].num_cleans++; metadata->plane_meta[prev_plane_num].clean_in_block = 0; metadata->plane_meta[prev_plane_num].clean_in_progress = -1; //erase two block(U) cost += s->params.block_erase_latency; ssd_power_flash_calculate(SSD_POWER_FLASH_ERASE, s->params.block_erase_latency, power_stat, s); ssd_update_free_block_status(log_block, log_plane_num, metadata, s); ssd_update_block_lifetime(simtime+cost, log_block, metadata); metadata->plane_meta[log_plane_num].num_cleans++; metadata->plane_meta[log_plane_num].clean_in_block = 0; metadata->plane_meta[log_plane_num].clean_in_progress = -1; //erase stat update s->elements[elem_num].stat.pages_moved += num_valid; s->elements[elem_num].stat.num_clean += 2; s->elements[elem_num].stat.num_fullmerge++; return cost; }
/* * migrate data from a cold block to "to_blk" */ int ssd_migrate_cold_data(int to_blk, double *mcost, int plane_num, int elem_num, ssd_t *s) { int i; int from_blk = -1; double oldest_erase_time = simtime; double cost = 0; int bitpos; #if SSD_ASSERT_ALL int f1; int f2; #endif ssd_element_metadata *metadata = &(s->elements[elem_num].metadata); // first select the coldest of all blocks. // one way to select is to find the one that has the oldest // erasure time. if (plane_num == -1) { for (i = 0; i < s->params.blocks_per_element; i ++) { if (metadata->block_usage[i].num_valid > 0) { if (metadata->block_usage[i].time_of_last_erasure < oldest_erase_time) { oldest_erase_time = metadata->block_usage[i].time_of_last_erasure; from_blk = i; } } } } else { #if SSD_ASSERT_ALL f1 = ssd_free_bits(plane_num, elem_num, metadata, s); ASSERT(f1 == metadata->plane_meta[metadata->block_usage[to_blk].plane_num].free_blocks); #endif bitpos = plane_num * s->params.blocks_per_plane; for (i = bitpos; i < bitpos + (int)s->params.blocks_per_plane; i ++) { int block = ssd_bitpos_to_block(i, s); ASSERT(metadata->block_usage[block].plane_num == plane_num); if (metadata->block_usage[block].num_valid > 0) { if (metadata->block_usage[block].time_of_last_erasure < oldest_erase_time) { oldest_erase_time = metadata->block_usage[block].time_of_last_erasure; from_blk = block; } } } } ASSERT(from_blk != -1); if (plane_num != -1) { ASSERT(metadata->block_usage[from_blk].plane_num == metadata->block_usage[to_blk].plane_num); } // next, clean the block to which we'll transfer the // cold data cost += _ssd_clean_block_fully(to_blk, metadata->block_usage[to_blk].plane_num, elem_num, metadata, s); #if SSD_ASSERT_ALL if (plane_num != -1) { f2 = ssd_free_bits(plane_num, elem_num, metadata, s); ASSERT(f2 == metadata->plane_meta[metadata->block_usage[to_blk].plane_num].free_blocks); } #endif // then, migrate the cold data to the worn out block. // for which, we first read all the valid data cost += metadata->block_usage[from_blk].num_valid * s->params.page_read_latency; // include the write cost cost += metadata->block_usage[from_blk].num_valid * s->params.page_write_latency; // if the src and dest blocks are on different planes // include the transfer cost also cost += ssd_crossover_cost(s, metadata, from_blk, to_blk); // the cost of erasing the cold block (represented by from_blk) // will be added later ... // finally, update the metadata metadata->block_usage[to_blk].bsn = metadata->block_usage[from_blk].bsn; metadata->block_usage[to_blk].num_valid = metadata->block_usage[from_blk].num_valid; metadata->block_usage[from_blk].num_valid = 0; for (i = 0; i < s->params.pages_per_block; i ++) { int lpn = metadata->block_usage[from_blk].page[i]; if (lpn != -1) { ASSERT(metadata->lba_table[lpn] == (from_blk * s->params.pages_per_block + i)); metadata->lba_table[lpn] = to_blk * s->params.pages_per_block + i; } metadata->block_usage[to_blk].page[i] = metadata->block_usage[from_blk].page[i]; } metadata->block_usage[to_blk].state = metadata->block_usage[from_blk].state; bitpos = ssd_block_to_bitpos(s, to_blk); ssd_set_bit(metadata->free_blocks, bitpos); metadata->tot_free_blocks --; metadata->plane_meta[metadata->block_usage[to_blk].plane_num].free_blocks --; #if SSD_ASSERT_ALL if (plane_num != -1) { f2 = ssd_free_bits(plane_num, elem_num, metadata, s); ASSERT(f2 == metadata->plane_meta[metadata->block_usage[to_blk].plane_num].free_blocks); } #endif ssd_assert_free_blocks(s, metadata); ASSERT(metadata->block_usage[from_blk].num_valid == 0); #if ASSERT_FREEBITS if (plane_num != -1) { f2 = ssd_free_bits(plane_num, elem_num, metadata, s); ASSERT(f1 == f2); } #endif *mcost = cost; // stat metadata->tot_migrations ++; metadata->tot_pgs_migrated += metadata->block_usage[to_blk].num_valid; metadata->mig_cost += cost; return from_blk; }
double ssd_replacement(ssd_t *s, int elem_num, int lbn) { ssd_element_metadata *metadata; ssd_power_element_stat *power_stat; int block; int log_index; int prev_log_block; int prev_plane_num; int log_block; int plane_num; int num_valid; double cost = 0.0; double r_cost, w_cost, xfer_cost; int i,j; metadata = &(s->elements[elem_num].metadata); power_stat = &(s->elements[elem_num].power_stat); block = metadata->lba_table[lbn]; log_index = metadata->block_usage[block].log_index; prev_log_block = metadata->log_data[log_index].bsn; prev_plane_num = metadata->block_usage[prev_log_block].plane_num; num_valid = metadata->block_usage[prev_log_block].num_valid; //alloc new logblock and erase old logblock log_block = metadata->plane_meta[prev_plane_num].active_block; _ssd_alloc_active_block(prev_plane_num, elem_num, s); plane_num = metadata->block_usage[log_block].plane_num; metadata->log_data[log_index].bsn = log_block; //move page old to new j = 0; for( i = 0 ; i < s->params.pages_per_block ; i++) { if( metadata->log_data[log_index].page[i] != -1) { metadata->log_data[log_index].page[i] = j; metadata->block_usage[log_block].page[j] = 1; metadata->block_usage[log_block].num_valid++; j++; } metadata->block_usage[prev_log_block].page[i] = -1; } metadata->block_usage[prev_log_block].num_valid = 0; //plane metadata update metadata->plane_meta[prev_plane_num].valid_pages -= metadata->block_usage[log_block].num_valid; metadata->plane_meta[plane_num].valid_pages += metadata->block_usage[log_block].num_valid; //cost //read r_cost = s->params.page_read_latency * num_valid; cost += r_cost; ssd_power_flash_calculate(SSD_POWER_FLASH_READ, r_cost, power_stat, s); //write w_cost = s->params.page_write_latency * num_valid; cost += w_cost; ssd_power_flash_calculate(SSD_POWER_FLASH_WRITE, w_cost, power_stat, s); //transfer cost for( i = 0 ; i < num_valid ; i++) { double xfer_cost; xfer_cost = ssd_crossover_cost(s, metadata, power_stat, prev_log_block, log_block); cost += xfer_cost; s->elements[elem_num].stat.tot_xfer_cost += xfer_cost; } //erase U block cost += s->params.block_erase_latency; ssd_power_flash_calculate(SSD_POWER_FLASH_ERASE, s->params.block_erase_latency, power_stat, s); ssd_update_free_block_status(prev_log_block, prev_plane_num, metadata, s); ssd_update_block_lifetime(simtime+cost, prev_log_block, metadata); s->elements[elem_num].stat.pages_moved += num_valid; s->elements[elem_num].stat.num_clean ++; s->elements[elem_num].stat.num_replacement++; metadata->plane_meta[prev_plane_num].num_cleans++; return cost; }