/* * 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; }
/* * updates the status of erased blocks */ void ssd_update_free_block_status(int blk, int plane_num, ssd_element_metadata *metadata, ssd_t *s) { int bitpos; // clear the bit corresponding to this block in the // free blocks list for future use bitpos = ssd_block_to_bitpos(s, blk); ssd_clear_bit(metadata->free_blocks, bitpos); metadata->block_usage[blk].state = SSD_BLOCK_CLEAN; metadata->block_usage[blk].bsn = 0; metadata->tot_free_blocks ++; metadata->plane_meta[plane_num].free_blocks ++; ssd_assert_free_blocks(s, metadata); // there must be no valid pages in the erased block ASSERT(metadata->block_usage[blk].num_valid == 0); ssd_assert_valid_pages(plane_num, metadata, s); }
/* * writes a single page into the active block of a ssd element. * this code assumes that there is a valid active page where the write can go * without invoking new cleaning. */ double _ssd_write_page_osr(ssd_t *s, ssd_element_metadata *metadata, int lpn) { double cost; unsigned int active_page = metadata->active_page; unsigned int active_block = SSD_PAGE_TO_BLOCK(active_page, s); unsigned int pagepos_in_block = active_page % s->params.pages_per_block; unsigned int active_plane = metadata->block_usage[active_block].plane_num; // see if this logical page no is already mapped. if (metadata->lba_table[lpn] != -1) { // since the lpn is going to be written to a new location, // its previous copy is invalid now. therefore reduce the block // usage of the previous copy's block. unsigned int prev_page = metadata->lba_table[lpn]; unsigned int prev_block = SSD_PAGE_TO_BLOCK(prev_page, s); unsigned int pagepos_in_prev_block = prev_page % s->params.pages_per_block; unsigned int prev_plane = metadata->block_usage[prev_block].plane_num; // make sure the version numbers are correct ssd_assert_page_version(prev_page, active_page, metadata, s); if (metadata->block_usage[prev_block].page[pagepos_in_prev_block] != lpn) { fprintf(stderr, "Error: lpn %d not found in prev block %d pos %d\n", lpn, prev_block, pagepos_in_prev_block); ASSERT(0); } else { metadata->block_usage[prev_block].page[pagepos_in_prev_block] = -1; metadata->block_usage[prev_block].num_valid --; metadata->plane_meta[prev_plane].valid_pages --; ssd_assert_valid_pages(prev_plane, metadata, s); } } else { fprintf(stderr, "Error: This case should not be executed\n"); } // add the entry to the lba table metadata->lba_table[lpn] = active_page; // increment the usage count on the active block metadata->block_usage[active_block].page[pagepos_in_block] = lpn; metadata->block_usage[active_block].num_valid ++; metadata->plane_meta[active_plane].valid_pages ++; ssd_assert_valid_pages(active_plane, metadata, s); // some sanity checking if (metadata->block_usage[active_block].num_valid >= s->params.pages_per_block) { fprintf(stderr, "Error: len %d of block %d is greater than or equal to pages per block %d\n", metadata->block_usage[active_block].num_valid, active_block, s->params.pages_per_block); exit(1); } // add the cost of the write cost = s->params.page_write_latency; //printf("lpn %d active pg %d\n", lpn, active_page); // go to the next free page metadata->active_page = active_page + 1; metadata->plane_meta[active_plane].active_page = metadata->active_page; // if this is the last data page on the block, let us write the // summary page also if (ssd_last_page_in_block(metadata->active_page, s)) { // cost of transferring the summary page data cost += ssd_data_transfer_cost(s, SSD_SECTORS_PER_SUMMARY_PAGE); // cost of writing the summary page data cost += s->params.page_write_latency; // seal the last summary page. since we use the summary page // as a metadata, we don't count it as a valid data page. metadata->block_usage[active_block].page[s->params.pages_per_block - 1] = -1; metadata->block_usage[active_block].state = SSD_BLOCK_SEALED; //printf("SUMMARY: lpn %d active pg %d\n", lpn, active_page); } return cost; }
/* * writes a single page into the active block of a ssd element. * this code assumes that there is a valid active page where the write can go * without invoking new cleaning. */ double _ssd_write_page_osr(ssd_t *s, ssd_element_metadata *metadata, int lbn, ssd_power_element_stat *power_stat, int blkno) { double cost; //unsigned int active_page = metadata->active_page; unsigned int active_block = metadata->active_block; //unsigned int pagepos_in_block = active_page % s->params.pages_per_block; unsigned int active_plane = metadata->block_usage[active_block].plane_num; unsigned int p_index = (blkno/s->params.page_size)%s->params.pages_per_block; int prev_num_valid = 0; int i; int elem_num = ssd_choose_element(s->user_params, blkno); // see if this logical page no is already mapped. if (metadata->lba_table[lbn] != -1) { // since the lpn is going to be written to a new location, // its previous copy is invalid now. therefore reduce the block // usage of the previous copy's block. unsigned int prev_block = metadata->lba_table[lbn]; //unsigned int prev_block = SSD_PAGE_TO_BLOCK(prev_page, s); //unsigned int pagepos_in_prev_block = prev_page % s->params.pages_per_block; unsigned int prev_plane = metadata->block_usage[prev_block].plane_num; // make sure the version numbers are correct //ssd_assert_page_version(prev_page, active_page, metadata, s); // if (metadata->block_usage[prev_block].page[0] != lpn) { // fprintf(stderr, "Error: lpn %d not found in prev block %d pos %d\n", // lpn, prev_block, pagepos_in_prev_block); // ASSERT(0); // } else { for( i = 0 ; i < (s->params.pages_per_block-1) ; i++) { metadata->block_usage[active_block].page[i] = metadata->block_usage[prev_block].page[i]; metadata->block_usage[prev_block].page[i] = -1; } prev_num_valid = metadata->block_usage[prev_block].num_valid; metadata->block_usage[prev_block].num_valid = 0; metadata->plane_meta[prev_plane].valid_pages -= prev_num_valid; ssd_assert_valid_pages(prev_plane, metadata, s); // } } else { fprintf(stderr, "Error: This case should not be executed\n"); } // add the entry to the lba table metadata->lba_table[lbn] = active_block; // increment the usage count on the active block if(metadata->block_usage[active_block].page[p_index] == 1) { int temp = 0; metadata->block_usage[active_block].num_valid = prev_num_valid; metadata->plane_meta[active_plane].valid_pages += prev_num_valid; //add cost cost = s->params.page_write_latency * prev_num_valid; ssd_power_flash_calculate(SSD_POWER_FLASH_WRITE, cost, power_stat, s); temp = prev_num_valid - 1; cost += ssd_data_transfer_cost(s, temp * 8); ssd_power_flash_calculate(SSD_POWER_FLASH_BUS_DATA_TRANSFER, ssd_data_transfer_cost(s, temp * 8), power_stat, s); //ssd_assert_valid_pages(active_plane, metadata, s); } else { // add the cost of the write cost = s->params.page_write_latency * (prev_num_valid +1); //printf("lpn %d active pg %d\n", lpn, active_page); //@20090831-Micky:add the power consumption of the write ssd_power_flash_calculate(SSD_POWER_FLASH_WRITE, cost, power_stat, s); cost += ssd_data_transfer_cost(s, prev_num_valid * 8); ssd_power_flash_calculate(SSD_POWER_FLASH_BUS_DATA_TRANSFER, ssd_data_transfer_cost(s, prev_num_valid * 8), power_stat, s); } // some sanity checking if (metadata->block_usage[active_block].num_valid >= s->params.pages_per_block) { fprintf(stderr, "Error: len %d of block %d is greater than or equal to pages per block %d\n", metadata->block_usage[active_block].num_valid, active_block, s->params.pages_per_block); exit(1); } // seal the last summary page. since we use the summary page // as a metadata, we don't count it as a valid data page. metadata->block_usage[active_block].page[s->params.pages_per_block - 1] = -1; metadata->block_usage[active_block].state = SSD_BLOCK_SEALED; // cost of transferring the summary page data cost += ssd_data_transfer_cost(s, SSD_SECTORS_PER_SUMMARY_PAGE); ssd_power_flash_calculate(SSD_POWER_FLASH_BUS_DATA_TRANSFER, ssd_data_transfer_cost(s, SSD_SECTORS_PER_SUMMARY_PAGE), power_stat, s); // cost of writing the summary page data cost += s->params.page_write_latency; //@20090831-Micky:add the power consumption of the write ssd_power_flash_calculate(SSD_POWER_FLASH_WRITE, s->params.page_write_latency, power_stat, s); return cost; }