/* * computes the average lifetime of all the blocks in a plane. */ double ssd_compute_avg_lifetime_in_plane(int plane_num, int elem_num, ssd_t *s) { int i; int bitpos; double tot_lifetime = 0; ssd_element_metadata *metadata = &(s->elements[elem_num].metadata); 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); tot_lifetime += metadata->block_usage[block].rem_lifetime; } return (tot_lifetime / s->params.blocks_per_plane); }
void ssd_assert_valid_pages(int plane_num, ssd_element_metadata *metadata, ssd_t *s) { #if SSD_ASSERT_ALL int i; int block_valid_pages = 0; int start_bitpos = plane_num * s->params.blocks_per_plane; for (i = start_bitpos; i < (start_bitpos + (int)s->params.blocks_per_plane); i ++) { int block = ssd_bitpos_to_block(i, s); block_valid_pages += metadata->block_usage[block].num_valid; } ASSERT(block_valid_pages == metadata->plane_meta[plane_num].valid_pages); #else return; #endif }
int _ssd_alloc_log_block(int plane_num, int elem_num, ssd_t *s, int data_block){ ssd_element_metadata *metadata = &(s->elements[elem_num].metadata); unsigned char *free_blocks = metadata->free_blocks; int active_block = -1; int prev_pos; int bitpos; int index; if (plane_num != -1) { prev_pos = metadata->plane_meta[plane_num].block_alloc_pos; } else { prev_pos = metadata->block_alloc_pos; } // find a free bit bitpos = ssd_find_zero_bit(free_blocks, s->params.blocks_per_element, prev_pos); ASSERT((bitpos >= 0) && (bitpos < s->params.blocks_per_element)); // check if we found the free bit in the plane we wanted to if (plane_num != -1) { if (ssd_bitpos_to_plane(bitpos, s) != plane_num) { //printf("Error: We wanted a free block in plane %d but found another in %d\n", // plane_num, ssd_bitpos_to_plane(bitpos, s)); //printf("So, starting the search again for plane %d\n", plane_num); // start from the beginning metadata->plane_meta[plane_num].block_alloc_pos = plane_num * s->params.blocks_per_plane; prev_pos = metadata->plane_meta[plane_num].block_alloc_pos; bitpos = ssd_find_zero_bit(free_blocks, s->params.blocks_per_element, prev_pos); ASSERT((bitpos >= 0) && (bitpos < s->params.blocks_per_element)); if (ssd_bitpos_to_plane(bitpos, s) != plane_num) { plane_num = ssd_bitpos_to_plane(bitpos, s); } } metadata->plane_meta[plane_num].block_alloc_pos = \ (plane_num * s->params.blocks_per_plane) + ((bitpos+1) % s->params.blocks_per_plane); } else { metadata->block_alloc_pos = (bitpos+1) % s->params.blocks_per_element; } // find the block num active_block = ssd_bitpos_to_block(bitpos, s); if (active_block != -1) { plane_metadata *pm; // make sure we're doing the right thing ASSERT(metadata->block_usage[active_block].plane_num == ssd_bitpos_to_plane(bitpos, s)); ASSERT(metadata->block_usage[active_block].bsn == 0); ASSERT(metadata->block_usage[active_block].num_valid == 0); ASSERT(metadata->block_usage[active_block].state == SSD_BLOCK_CLEAN); if (plane_num == -1) { plane_num = metadata->block_usage[active_block].plane_num; } else { ASSERT(plane_num == metadata->block_usage[active_block].plane_num); } pm = &metadata->plane_meta[plane_num]; // reduce the total number of free blocks metadata->tot_free_blocks --; pm->free_blocks --; //assertion ssd_assert_free_blocks(s, metadata); // allocate the block ssd_set_bit(free_blocks, bitpos); metadata->block_usage[active_block].state = SSD_BLOCK_INUSE; metadata->block_usage[active_block].bsn = metadata->bsn ++; //ssd_assert_plane_freebits(plane_num, elem_num, metadata, s); } else { fprintf(outputfile3, "Error: cannot find a free block in ssd element %d\n", elem_num); exit(-1); } metadata->num_log++; index = ssd_index_search(s, metadata); metadata->log_data[index].bsn = active_block; metadata->log_data[index].data_block = data_block; return index; }
/* * 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; }