Beispiel #1
0
/*
 * 1. find a plane to clean in each of the parallel unit
 * 2. invoke copyback cleaning on all such planes simultaneously
 */
double ssd_clean_element_copyback(int elem_num, ssd_t *s)
{
    // this means that some (or all) planes require cleaning
    int clean_req = 0;
    int i;
    double max_cleaning_cost = 0;
    int plane_to_clean[SSD_MAX_PARUNITS_PER_ELEM];
    ssd_element_metadata *metadata = &s->elements[elem_num].metadata;
    int tot_cleans = 0;

    for (i = 0; i < SSD_PARUNITS_PER_ELEM(s); i ++) {
        if ((plane_to_clean[i] = ssd_start_cleaning_parunit(i, elem_num, s)) != -1) {
            clean_req = 1;
        }
    }

    if (clean_req) {
        for (i = 0; i < SSD_PARUNITS_PER_ELEM(s); i ++) {
            double cleaning_cost = 0;
            int plane_num = plane_to_clean[i];

            if (plane_num == -1) {
                // don't force cleaning
                continue;
            }

            if (metadata->plane_meta[plane_num].clean_in_progress) {
                metadata->plane_meta[plane_num].clean_in_progress = 0;
                metadata->plane_meta[plane_num].clean_in_block = -1;
            }

            metadata->active_page = metadata->plane_meta[plane_num].active_page;
            cleaning_cost = ssd_clean_plane_copyback(plane_num, elem_num, s);

            tot_cleans ++;

            if (max_cleaning_cost < cleaning_cost) {
                max_cleaning_cost = cleaning_cost;
            }
        }
    }

    return max_cleaning_cost;
}
Beispiel #2
0
static double ssd_issue_overlapped_ios(ssd_req **reqs, int total, int elem_num, ssd_t *s)
{
    double max_cost = 0;
	double parunit_op_cost[SSD_MAX_PARUNITS_PER_ELEM];
    double parunit_tot_cost[SSD_MAX_PARUNITS_PER_ELEM];
    ssd_element_metadata *metadata;
    ssd_power_element_stat *power_stat;
    
    int lbn;
	int offset;
    int i;
    int read_cycle = 0;
    listnode **parunits;

    // all the requests must be of the same type
    for (i = 1; i < total; i ++) {
        ASSERT(reqs[i]->is_read == reqs[0]->is_read);
    }

    // is this a set of read requests?
    if (reqs[0]->is_read) {
        read_cycle = 1;
    }

    memset(parunit_tot_cost, 0, sizeof(double)*SSD_MAX_PARUNITS_PER_ELEM);

    // find the planes to which the reqs are to be issued
    metadata = &(s->elements[elem_num].metadata);
    power_stat = &(s->elements[elem_num].power_stat);
    parunits = ssd_pick_parunits(reqs, total, elem_num, metadata, s);

    // repeat until we've served all the requests
    while (1) {
        double max_op_cost = 0;
		double read_xfer_cost = 0.0;
		double write_xfer_cost = 0.0;
        int active_parunits = 0;
        int op_count = 0;

        // do we still have any request to service?
        for (i = 0; i < SSD_PARUNITS_PER_ELEM(s); i ++) {
            if (ll_get_size(parunits[i]) > 0) {
                active_parunits ++;
            }
        }

        // no more requests -- get out
        if (active_parunits == 0) {
            break;
        }

        // clear this arrays for storing costs
        memset(parunit_op_cost, 0, sizeof(double)*SSD_MAX_PARUNITS_PER_ELEM);

        // begin a round of serving. we serve one request per
        // parallel unit. if an unit has more than one request
        // in the list, they have to be serialized.
        max_cost = 0;
        for (i = 0; i < SSD_PARUNITS_PER_ELEM(s); i ++) {
            int size;

            size = ll_get_size(parunits[i]);
            if (size > 0) {
				int apn;
                // this parallel unit has a request to serve
                ssd_req *r;
                listnode *n = ll_get_nth_node(parunits[i], 0);

                op_count ++;
                ASSERT(op_count <= active_parunits);

                // get the request
                r = (ssd_req *)n->data;
                lbn = ssd_logical_blockno(r->blk, s);
				apn = r->blk/s->params.page_size;
				offset = (apn/s->params.nelements)%(s->params.pages_per_block-1);
				parunit_op_cost[i] = 0;

                if (r->is_read) {
					int block = metadata->lba_table[lbn];

					if(block == -1){
						parunit_op_cost[i] = s->params.page_read_latency;
						//Micky
						ssd_power_flash_calculate(SSD_POWER_FLASH_READ, s->params.page_read_latency, power_stat, s);
					}else if(metadata->block_usage[block].log_index == -1){
						parunit_op_cost[i] = s->params.page_read_latency;
						//Micky
						ssd_power_flash_calculate(SSD_POWER_FLASH_READ, s->params.page_read_latency, power_stat, s);
					}else{
						parunit_op_cost[i] = s->params.page_read_latency;
						//Micky
						ssd_power_flash_calculate(SSD_POWER_FLASH_READ, s->params.page_read_latency, power_stat, s);
						parunit_op_cost[i] += s->params.page_read_latency;
						ssd_power_flash_calculate(SSD_POWER_FLASH_READ, s->params.page_read_latency, power_stat, s);
						s->spare_read++;
					}

					//tiel xfer cost
					read_xfer_cost += ssd_data_transfer_cost(s,r->count);
                } else { //for write
                    int plane_num = r->plane_num;
					// issue the write to the current active page.
                    // we need to transfer the data across the serial pins for write.
					metadata->active_block = metadata->plane_meta[plane_num].active_block;
                    // check lbn table
					if(metadata->lba_table[lbn] == -1 ) {
						metadata->lba_table[lbn] = metadata->active_block;
						parunit_op_cost[i] = _ssd_write_page_osr(s, metadata, lbn, offset, power_stat);
						_ssd_alloc_active_block(plane_num, elem_num, s);
					}
					else { //if already mapped, check log block
						int tmp_block = metadata->lba_table[lbn];
						if(metadata->block_usage[tmp_block].page[offset] == -1) {
							parunit_op_cost[i] = _ssd_write_page_osr(s, metadata, lbn, offset, power_stat);
						}
						else {
							if (metadata->block_usage[tmp_block].log_index == -1) {
								metadata->block_usage[tmp_block].log_index = _ssd_alloc_log_block(plane_num, elem_num, s, tmp_block);
								parunit_op_cost[i] = _ssd_write_log_block_osr(s, metadata, lbn, offset, power_stat);
							}
							else {
								if(_last_page_in_log_block(metadata, s, tmp_block)){
									int new_block;
									parunit_op_cost[i] += ssd_invoke_logblock_cleaning(elem_num, s, lbn);
									new_block = metadata->lba_table[lbn];
									if(metadata->block_usage[new_block].log_index == -1){
										metadata->block_usage[new_block].log_index = _ssd_alloc_log_block(plane_num, elem_num, s, tmp_block);
									}
								}else{
									parunit_op_cost[i] += _ssd_write_log_block_osr(s, metadata, lbn, offset, power_stat);
								}
							}
						}
					}
					write_xfer_cost += ssd_data_transfer_cost(s,r->count);
				}

                ASSERT(r->count <= s->params.page_size);

                // calc the cost: the access time should be something like this
                // for read
                if (read_cycle) {
                    if (SSD_PARUNITS_PER_ELEM(s) > 4) {
                        printf("modify acc time here ...\n");
                        ASSERT(0);
                    }
                    if (op_count == 1) {
						r->acctime = parunit_op_cost[i] + read_xfer_cost;
                        r->schtime = parunit_tot_cost[i] + r->acctime;
                    } else {
						r->acctime = ssd_data_transfer_cost(s,r->count);
                        r->schtime = parunit_tot_cost[i] + read_xfer_cost + parunit_op_cost[i];
                    }
                } else {
                    // for write
                    r->acctime = parunit_op_cost[i];
                    r->schtime = parunit_tot_cost[i] + write_xfer_cost + r->acctime;
                }

                // find the maximum cost for this round of operations
                if (max_cost < r->schtime) {
                    max_cost = r->schtime;
                }

                // release the node from the linked list
                ll_release_node(parunits[i], n);
            }
		}
		ssd_power_flash_calculate(SSD_POWER_FLASH_BUS_DATA_TRANSFER, read_xfer_cost, power_stat, s);
		ssd_power_flash_calculate(SSD_POWER_FLASH_BUS_DATA_TRANSFER, write_xfer_cost, power_stat, s);

        // we can start the next round of operations only after all
        // the operations in the first round are over because we're
        // limited by the one set of pins to all the parunits
        for (i = 0; i < SSD_PARUNITS_PER_ELEM(s); i ++) {
            parunit_tot_cost[i] = max_cost;
        }
    }

    for (i = 0; i < SSD_PARUNITS_PER_ELEM(s); i ++) {
        ll_release(parunits[i]);
    }
    free(parunits);

	power_stat->acc_time += max_cost;

    return max_cost;
}
Beispiel #3
0
/*
 * vp
 * description: this routine allocates and initializes the ssd element metadata
 * structures. FIXME: if the systems is powered up, this init routine has to
 * populate the structures by scanning the summary pages (to implement this,
 * we can read from a disk checkpoint file). but, this is future work.
*/
void ssd_element_metadata_init(int elem_number, ssd_element_metadata *metadata, ssd_t *currdisk)
{
    gang_metadata *g;
    unsigned int ppage;
    unsigned int i;
    unsigned int bytes_to_alloc;
    unsigned int tot_blocks = currdisk->params.blocks_per_element;
    unsigned int tot_pages = tot_blocks * currdisk->params.pages_per_block;
    unsigned int reserved_blocks, usable_blocks, export_size;
    unsigned int reserved_blocks_per_plane, usable_blocks_per_plane;
    unsigned int bitpos;
    unsigned int active_block;
    unsigned int elem_index;
    unsigned int bsn = 1;
    int plane_block_mapping = currdisk->params.plane_block_mapping;

    //////////////////////////////////////////////////////////////////////////////
    // active page starts at the 1st page on the reserved section
    reserved_blocks_per_plane = (currdisk->params.reserve_blocks * currdisk->params.blocks_per_plane) / 100;
    usable_blocks_per_plane = currdisk->params.blocks_per_plane - reserved_blocks_per_plane;
    reserved_blocks = reserved_blocks_per_plane * currdisk->params.planes_per_pkg;
    usable_blocks = usable_blocks_per_plane * currdisk->params.planes_per_pkg;

    //////////////////////////////////////////////////////////////////////////////
    // initialize the free blocks and free pages
    metadata->tot_free_blocks = reserved_blocks;

    //////////////////////////////////////////////////////////////////////////////
    // assign the gang and init the element's free pages
    metadata->gang_num = elem_number / currdisk->params.elements_per_gang;
    currdisk->gang_meta[metadata->gang_num].elem_free_pages[elem_number] = \
        metadata->tot_free_blocks * SSD_DATA_PAGES_PER_BLOCK(currdisk);
    g = &currdisk->gang_meta[metadata->gang_num];
    elem_index = elem_number % currdisk->params.elements_per_gang;

    //////////////////////////////////////////////////////////////////////////////
    // let's begin cleaning with the first plane
    metadata->plane_to_clean = 0;
    metadata->plane_to_write = 0;
    metadata->block_alloc_pos = 0;
    metadata->reqs_waiting = 0;
    metadata->tot_migrations = 0;
    metadata->tot_pgs_migrated = 0;
    metadata->mig_cost = 0;

    //////////////////////////////////////////////////////////////////////////////
    // init the plane metadata
    for (i = 0; i < (unsigned int)currdisk->params.planes_per_pkg; i ++) {
        int blocks_to_skip;

        switch(plane_block_mapping) {
            case PLANE_BLOCKS_CONCAT:
                blocks_to_skip = (i*currdisk->params.blocks_per_plane + usable_blocks_per_plane);
                break;

            case PLANE_BLOCKS_PAIRWISE_STRIPE:
                blocks_to_skip = (i/2)*(2*currdisk->params.blocks_per_plane) + (2*usable_blocks_per_plane) + i%2;
                break;

            case PLANE_BLOCKS_FULL_STRIPE:
                blocks_to_skip = (currdisk->params.planes_per_pkg * usable_blocks_per_plane) + i;
                break;

            default:
                fprintf(stderr, "Error: unknown plane_block_mapping %d\n", plane_block_mapping);
                exit(1);
        }

        metadata->plane_meta[i].active_page = blocks_to_skip*currdisk->params.pages_per_block;
        metadata->plane_meta[i].free_blocks = reserved_blocks_per_plane;
        metadata->plane_meta[i].valid_pages = 0;
        metadata->plane_meta[i].clean_in_progress = 0;
        metadata->plane_meta[i].clean_in_block = -1;
        metadata->plane_meta[i].block_alloc_pos = i*currdisk->params.blocks_per_plane;
        metadata->plane_meta[i].parunit_num = i / SSD_PLANES_PER_PARUNIT(currdisk);
        metadata->plane_meta[i].num_cleans = 0;
    }

    //////////////////////////////////////////////////////////////////////////////
    // init the next plane to clean in a parunit
    for (i = 0; i < (unsigned int) SSD_PARUNITS_PER_ELEM(currdisk); i ++) {
        metadata->parunits[i].plane_to_clean = SSD_PLANES_PER_PARUNIT(currdisk)*i;
    }

    //////////////////////////////////////////////////////////////////////////////
    // init the element's active page
    switch(plane_block_mapping) {
        case PLANE_BLOCKS_CONCAT:
            metadata->active_page = usable_blocks_per_plane * currdisk->params.pages_per_block;
            break;

        case PLANE_BLOCKS_PAIRWISE_STRIPE:
            metadata->active_page = (2 * usable_blocks_per_plane) * currdisk->params.pages_per_block;
            break;

        case PLANE_BLOCKS_FULL_STRIPE:
            metadata->active_page = (currdisk->params.planes_per_pkg * usable_blocks_per_plane) * currdisk->params.pages_per_block;
            break;

        default:
            fprintf(stderr, "Error: unknown plane_block_mapping %d\n", plane_block_mapping);
            exit(1);
    }

    ASSERT(metadata->active_page == metadata->plane_meta[0].active_page);
    active_block = metadata->active_page / currdisk->params.pages_per_block;

    // since we reserve one page out of every block to store the summary info,
    // the size exported by the flash disk is little less.
    export_size = usable_blocks * SSD_DATA_PAGES_PER_BLOCK(currdisk);
    currdisk->data_pages_per_elem = export_size;
    //printf("res blks = %d, use blks = %d act page = %d exp size = %d\n",
    //  reserved_blocks, usable_blocks, metadata->active_page, export_size);

    //////////////////////////////////////////////////////////////////////////////
    // allocate the lba table
    if ((metadata->lba_table = (int *)malloc(export_size * sizeof(int))) == NULL) {
        fprintf(stderr, "Error: malloc to lba table in ssd_element_metadata_init failed\n");
        fprintf(stderr, "Allocation size = %d\n", export_size * sizeof(int));
        exit(1);
    }

    //////////////////////////////////////////////////////////////////////////////
    // allocate the free blocks bit map
    // what if the no of blocks is not divisible by 8?
    if ((tot_blocks % (sizeof(unsigned char) * 8)) != 0) {
        fprintf(stderr, "This case is not yet handled\n");
        exit(1);
    }

    bytes_to_alloc = tot_blocks / (sizeof(unsigned char) * 8);
    if (!(metadata->free_blocks = (unsigned char *)malloc(bytes_to_alloc))) {
        fprintf(stderr, "Error: malloc to free_blocks in ssd_element_metadata_init failed\n");
        fprintf(stderr, "Allocation size = %d\n", bytes_to_alloc);
        exit(1);
    }
    bzero(metadata->free_blocks, bytes_to_alloc);

    //////////////////////////////////////////////////////////////////////////////
    // allocate the block usage array and initialize it
    if (!(metadata->block_usage = (block_metadata *)malloc(tot_blocks * sizeof(block_metadata)))) {
        fprintf(stderr, "Error: malloc to block_usage in ssd_element_metadata_init failed\n");
        fprintf(stderr, "Allocation size = %d\n", tot_blocks * sizeof(block_metadata));
        exit(1);
    }
    bzero(metadata->block_usage, tot_blocks * sizeof(block_metadata));

    for (i = 0; i < tot_blocks; i ++) {
        int j;

        metadata->block_usage[i].block_num = i;
        metadata->block_usage[i].page = (int*)malloc(sizeof(int) * currdisk->params.pages_per_block);

        for (j = 0; j < currdisk->params.pages_per_block; j ++) {
            metadata->block_usage[i].page[j] = -1;
        }

        // assign the plane number to each block
        switch(plane_block_mapping) {
            case PLANE_BLOCKS_CONCAT:
                metadata->block_usage[i].plane_num = i / currdisk->params.blocks_per_plane;
                break;

            case PLANE_BLOCKS_PAIRWISE_STRIPE:
                metadata->block_usage[i].plane_num = (i/(2*currdisk->params.blocks_per_plane))*2 + i%2;
                break;

            case PLANE_BLOCKS_FULL_STRIPE:
                metadata->block_usage[i].plane_num = i % currdisk->params.planes_per_pkg;
                break;

            default:
                fprintf(stderr, "Error: unknown plane_block_mapping %d\n", plane_block_mapping);
                exit(1);
        }

        // set the remaining life time and time of last erasure
        metadata->block_usage[i].rem_lifetime = SSD_MAX_ERASURES;
        metadata->block_usage[i].time_of_last_erasure = simtime;

        // set the block state
        metadata->block_usage[i].state = SSD_BLOCK_CLEAN;

        // init the bsn to be zero
        metadata->block_usage[i].bsn = 0;
    }

    //////////////////////////////////////////////////////////////////////////////
    // initially, we assume that every logical page is mapped
    // onto a physical page. we start from the first phy page
    // and continue to map, leaving the last page of every block
    // to store the summary information.
    ppage = 0;
    i = 0;
    while (i < export_size) {
        int pgnum_in_gang;
        int pp_index;
        int plane_num;
        unsigned int block = SSD_PAGE_TO_BLOCK(ppage, currdisk);

        ASSERT(block < (unsigned int)currdisk->params.blocks_per_element);

        // if this is the last page in the block
        if (ssd_last_page_in_block(ppage, currdisk)) {
            // leave this physical page for summary page and
            // seal the block
            metadata->block_usage[block].state = SSD_BLOCK_SEALED;

            // go to next block
            ppage ++;
            block = SSD_PAGE_TO_BLOCK(ppage, currdisk);
        }

        // if this block is in the reserved section, skip it
        // and go to the next block.
        switch(plane_block_mapping) {
            case PLANE_BLOCKS_CONCAT:
            {
                unsigned int block_index = block % currdisk->params.blocks_per_plane;
                if ((block_index >= usable_blocks_per_plane) && (block_index < currdisk->params.blocks_per_plane)) {
                    // go to next block
                    ppage = ssd_first_page_in_next_block(ppage, currdisk);
                    continue;
                }
            }
            break;

            case PLANE_BLOCKS_PAIRWISE_STRIPE:
            {
                unsigned int block_index = block % (2*currdisk->params.blocks_per_plane);
                if ((block_index >= 2*usable_blocks_per_plane) && (block_index < 2*currdisk->params.blocks_per_plane)) {
                    ppage = ssd_first_page_in_next_block(ppage, currdisk);
                    continue;
                }
            }
            break;

            case PLANE_BLOCKS_FULL_STRIPE:
                // ideally the control should not come here ...
                if ((block >= usable_blocks) && (block < (unsigned int)currdisk->params.blocks_per_element)) {
                    printf("Error: the control should not come here ...\n");
                    ppage = ssd_first_page_in_next_block(ppage, currdisk);
                    continue;
                }
            break;

            default:
                fprintf(stderr, "Error: unknown plane_block_mapping %d\n", plane_block_mapping);
                exit(1);
        }

        // when the control comes here, 'ppage' contains the next page
        // that can be assigned to a logical page.
        // find the index of the phy page within the block
        pp_index = ppage % currdisk->params.pages_per_block;

        // populate the lba table
        metadata->lba_table[i] = ppage;
        pgnum_in_gang = elem_index * export_size + i;
        g->pg2elem[pgnum_in_gang].e = elem_number;

        // mark this block as not free and its state as 'in use'.
        // note that a block could be not free and its state be 'sealed'.
        // it is enough if we set it once while working on the first phy page.
        // also increment the block sequence number.
        if (pp_index == 0) {
            bitpos = ssd_block_to_bitpos(currdisk, block);
            ssd_set_bit(metadata->free_blocks, bitpos);
            metadata->block_usage[block].state = SSD_BLOCK_INUSE;
            metadata->block_usage[block].bsn = bsn ++;
        }

        // increase the usage count per block
        plane_num = metadata->block_usage[block].plane_num;
        metadata->block_usage[block].page[pp_index] = i;
        metadata->block_usage[block].num_valid ++;
        metadata->plane_meta[plane_num].valid_pages ++;

        // go to the next physical page
        ppage ++;

        // go to the next logical page
        i ++;
    }

    //////////////////////////////////////////////////////////////////////////////
    // mark the block that corresponds to the active page
    // as not free and 'in_use'.
    switch(currdisk->params.copy_back) {
        case SSD_COPY_BACK_DISABLE:
            bitpos = ssd_block_to_bitpos(currdisk, active_block);
            ssd_set_bit(metadata->free_blocks, bitpos);
            metadata->block_usage[active_block].state = SSD_BLOCK_INUSE;
            metadata->block_usage[active_block].bsn = bsn ++;
        break;

        case SSD_COPY_BACK_ENABLE:
            for (i = 0; i < (unsigned int)currdisk->params.planes_per_pkg; i ++) {
                int plane_active_block = SSD_PAGE_TO_BLOCK(metadata->plane_meta[i].active_page, currdisk);

                bitpos = ssd_block_to_bitpos(currdisk, plane_active_block);
                ssd_set_bit(metadata->free_blocks, bitpos);
                metadata->block_usage[plane_active_block].state = SSD_BLOCK_INUSE;
                metadata->block_usage[plane_active_block].bsn = bsn ++;
                metadata->tot_free_blocks --;
                metadata->plane_meta[i].free_blocks --;
            }
        break;

        default:
            fprintf(stderr, "Error: invalid copy back policy %d\n",
                currdisk->params.copy_back);
            exit(1);
    }

    //////////////////////////////////////////////////////////////////////////////
    // set the bsn for the ssd element
    metadata->bsn = bsn;
    //printf("set the bsn to %d\n", bsn);
}
Beispiel #4
0
/*
 * vp
 * description: this routine allocates and initializes the ssd element metadata
 * structures. FIXME: if the systems is powered up, this init routine has to
 * populate the structures by scanning the summary pages (to implement this,
 * we can read from a disk checkpoint file). but, this is future work.
*/
void ssd_element_metadata_init(int elem_number, ssd_element_metadata *metadata, ssd_t *currdisk)
{
    gang_metadata *g;
    unsigned int ppage;
    unsigned int i;
    unsigned int bytes_to_alloc;
    unsigned int tot_blocks = currdisk->params.blocks_per_element;
    unsigned int tot_pages = tot_blocks * currdisk->params.pages_per_block;
    unsigned int reserved_blocks, usable_blocks, export_size;
    unsigned int reserved_blocks_per_plane, usable_blocks_per_plane;
    unsigned int bitpos;
    unsigned int active_block;
    unsigned int elem_index;
    unsigned int bsn = 1;
    int plane_block_mapping = currdisk->params.plane_block_mapping;

    //////////////////////////////////////////////////////////////////////////////
    // active page starts at the 1st page on the reserved section
    reserved_blocks_per_plane = (currdisk->params.reserve_blocks * currdisk->params.blocks_per_plane) / 100;
    usable_blocks_per_plane = currdisk->params.blocks_per_plane - reserved_blocks_per_plane;
    reserved_blocks = reserved_blocks_per_plane * currdisk->params.planes_per_pkg;
    usable_blocks = usable_blocks_per_plane * currdisk->params.planes_per_pkg;

    //////////////////////////////////////////////////////////////////////////////
    // initialize the free blocks and free pages
    metadata->tot_free_blocks = reserved_blocks;

    //////////////////////////////////////////////////////////////////////////////
    // assign the gang and init the element's free pages
    metadata->gang_num = elem_number / currdisk->params.elements_per_gang;
    currdisk->gang_meta[metadata->gang_num].elem_free_pages[elem_number] = \
        metadata->tot_free_blocks * SSD_DATA_PAGES_PER_BLOCK(currdisk);
    g = &currdisk->gang_meta[metadata->gang_num];
    elem_index = elem_number % currdisk->params.elements_per_gang;

    //////////////////////////////////////////////////////////////////////////////
    // let's begin cleaning with the first plane
    metadata->plane_to_clean = 0;
    metadata->plane_to_write = 0;
    metadata->block_alloc_pos = 0;
    metadata->reqs_waiting = 0;
    metadata->tot_migrations = 0;
    metadata->tot_pgs_migrated = 0;
    metadata->mig_cost = 0;

    //////////////////////////////////////////////////////////////////////////////
    // init the plane metadata
    for (i = 0; i < (unsigned int)currdisk->params.planes_per_pkg; i ++) {
        int blocks_to_skip;

        switch(plane_block_mapping) {
            case PLANE_BLOCKS_CONCAT:
                assert(!"Refresh Operations not supported with PLANE_BLOCKS_CONCAT mapping");
                blocks_to_skip = (i*currdisk->params.blocks_per_plane + usable_blocks_per_plane);
                break;

            case PLANE_BLOCKS_PAIRWISE_STRIPE:
                assert(!"Refresh Operations not supported with PLANE_BLOCKS_PAIRWISE_STRIPE mapping");
                blocks_to_skip = (i/2)*(2*currdisk->params.blocks_per_plane) + (2*usable_blocks_per_plane) + i%2;
                break;

            case PLANE_BLOCKS_FULL_STRIPE:
                blocks_to_skip = (currdisk->params.planes_per_pkg * usable_blocks_per_plane) + i;
                break;

            default:
                fprintf(stderr, "Error: unknown plane_block_mapping %d\n", plane_block_mapping);
                exit(1);
        }

        //metadata->plane_meta[i].active_page = blocks_to_skip*currdisk->params.pages_per_block;
        metadata->plane_meta[i].free_blocks = reserved_blocks_per_plane;
        metadata->plane_meta[i].valid_pages = 0;
        metadata->plane_meta[i].clean_in_progress = 0;
        metadata->plane_meta[i].clean_in_block = -1;
        metadata->plane_meta[i].block_alloc_pos = i*currdisk->params.blocks_per_plane;
        metadata->plane_meta[i].parunit_num = i / SSD_PLANES_PER_PARUNIT(currdisk);
        metadata->plane_meta[i].num_cleans = 0;
        metadata->plane_meta[i].dead_blocks = 0;
    }

    //////////////////////////////////////////////////////////////////////////////
    // init the next plane to clean in a parunit
    for (i = 0; i < (unsigned int) SSD_PARUNITS_PER_ELEM(currdisk); i ++) {
        metadata->parunits[i].plane_to_clean = SSD_PLANES_PER_PARUNIT(currdisk)*i;
    }

    // since we reserve one page out of every block to store the summary info,
    // the size exported by the flash disk is little less.
    export_size = usable_blocks * SSD_DATA_PAGES_PER_BLOCK(currdisk);
    currdisk->data_pages_per_elem = export_size;
    //printf("res blks = %d, use blks = %d act page = %d exp size = %d\n",
    //  reserved_blocks, usable_blocks, metadata->active_page, export_size);

    //////////////////////////////////////////////////////////////////////////////
    // allocate the lba table
    if ((metadata->lba_table = (int *)malloc(export_size * sizeof(int))) == NULL) {
        fprintf(stderr, "Error: malloc to lba table in ssd_element_metadata_init failed\n");
#ifdef __x86_64__
        fprintf(stderr, "Allocation size = %lu\n", export_size * sizeof(int));
#else
        fprintf(stderr, "Allocation size = %u\n", export_size * sizeof(int));
#endif
        exit(1);
    }

    //////////////////////////////////////////////////////////////////////////////
    // allocate the free blocks bit map
    // what if the no of blocks is not divisible by 8?
    if ((tot_blocks % (sizeof(unsigned char) * 8)) != 0) {
        fprintf(stderr, "This case is not yet handled\n");
        exit(1);
    }

    bytes_to_alloc = tot_blocks / (sizeof(unsigned char) * 8);
    if (!(metadata->free_blocks = (unsigned char *)malloc(bytes_to_alloc))) {
        fprintf(stderr, "Error: malloc to free_blocks in ssd_element_metadata_init failed\n");
        fprintf(stderr, "Allocation size = %d\n", bytes_to_alloc);
        exit(1);
    }
    bzero(metadata->free_blocks, bytes_to_alloc);

    //////////////////////////////////////////////////////////////////////////////
    // allocate the block usage array and initialize it
    if (!(metadata->block_usage = (block_metadata *)malloc(tot_blocks * sizeof(block_metadata)))) {
        fprintf(stderr, "Error: malloc to block_usage in ssd_element_metadata_init failed\n");
#ifdef __x86_64__
        fprintf(stderr, "Allocation size = %lu\n", tot_blocks * sizeof(block_metadata));
#else
        fprintf(stderr, "Allocation size = %u\n", tot_blocks * sizeof(block_metadata));
#endif
        exit(1);
    }
    bzero(metadata->block_usage, tot_blocks * sizeof(block_metadata));

    for (i = 0; i < tot_blocks; i ++) {
        int j;
        metadata->block_usage[i].block_num = i;
        metadata->block_usage[i].elem_num = elem_number;
        metadata->block_usage[i].page = (ssd_page_metadata*)malloc(sizeof(ssd_page_metadata) * currdisk->params.pages_per_block);
	// KJ: initialize all the page metadata
	bzero(metadata->block_usage[i].page, currdisk->params.pages_per_block * sizeof(ssd_page_metadata));
		    metadata->block_usage[i].entry_in_refresh_queue= 0;
        metadata->block_usage[i].total_pages_written = INITIAL_STRESSES*currdisk->params.pages_per_block;
				metadata->block_usage[i].least_retention_page = &metadata->block_usage[i].page[0];
        metadata->block_usage[i].logical_stresses =  INITIAL_STRESSES*currdisk->params.pages_per_block;
        metadata->block_usage[i].physical_stresses =  INITIAL_STRESSES*currdisk->params.pages_per_block;        
	      assert(metadata->block_usage[i].page); 
        
    for (j = 0; j < currdisk->params.pages_per_block; j ++) {
            metadata->block_usage[i].page[j].lpn = -1;
            metadata->block_usage[i].page[j].time_of_last_stress = 0;
            metadata->block_usage[i].page[j].retention_period = 1e10;
            metadata->block_usage[i].page[j].logical_stresses= INITIAL_STRESSES;
            metadata->block_usage[i].page[j].physical_stresses = INITIAL_STRESSES;
            metadata->block_usage[i].page[j].eqn_cycle =  INITIAL_STRESSES;
            metadata->block_usage[i].page[j].stress_increment = 1;
            metadata->block_usage[i].page[j].recovery_period_total = 0;
        }

        // assign the plane number to each block
        switch(plane_block_mapping) {
            case PLANE_BLOCKS_CONCAT:
                metadata->block_usage[i].plane_num = i / currdisk->params.blocks_per_plane;
                break;

            case PLANE_BLOCKS_PAIRWISE_STRIPE:
                metadata->block_usage[i].plane_num = (i/(2*currdisk->params.blocks_per_plane))*2 + i%2;
                break;

            case PLANE_BLOCKS_FULL_STRIPE:
                metadata->block_usage[i].plane_num = i % currdisk->params.planes_per_pkg;
                break;

            default:
                fprintf(stderr, "Error: unknown plane_block_mapping %d\n", plane_block_mapping);
                exit(1);
        }

        // set the remaining life time and time of last erasure
        metadata->block_usage[i].rem_lifetime = SSD_MAX_ERASURES;
        metadata->block_usage[i].time_of_last_erasure = simtime;
        // set the block state
        metadata->block_usage[i].state = SSD_BLOCK_CLEAN;

        // init the bsn to be zero
        metadata->block_usage[i].bsn = 0;
    }

    //load the ssd state from the snapshot provided by trace_analyzer.
    if(ta_snapshotfile)
      ssd_init_stress_info_ta(currdisk,metadata,elem_number);
    else if(ds_snapshotfile)
      ssd_init_stress_info_ds(currdisk,metadata,elem_number);

    //check for dead block status.
    int dead_block_count =  0;
    for (i=0;i<currdisk->params.blocks_per_element;i++) {
      if (i < usable_blocks) //temporarily mark blocks as in use.
        metadata->block_usage[i].state = SSD_BLOCK_INUSE;
      if (ssd_block_dead(&metadata->block_usage[i],currdisk))
        dead_block_count++;
      else
        metadata->block_usage[i].state = SSD_BLOCK_CLEAN;
    }
    fprintf(stderr,"Dead blocks in element #%d : %d\n",elem_number,dead_block_count);

    if (dead_block_count >= reserved_blocks) { //if dead blocks more than overprovisioned blocks, then simulation cannot proceed further.
      fprintf(stderr,"Total reserved blocks : %d\n",reserved_blocks);
      fprintf(stderr,"Unable to proceed further as dead blocks more than reserved blocks\n");
      fprintf(outputfile,"Total reserved blocks : %d\n",reserved_blocks);
      fprintf(outputfile,"Unable to proceed further as dead blocks more than reserved blocks\n");
      fclose(outputfile);
      exit(1);
    }
    ssd_assert_free_blocks(currdisk,metadata); //////////////////////////////////////////////////////////////////////////////
    // initially, we assume that every logical page is mapped
    // onto a physical page. we start from the first phy page
    // and continue to map, leaving the last page of every block
    // to store the summary information.
    ppage = 0;
    i = 0;
    while (i < export_size) {
        int pgnum_in_gang;
        int pp_index;
        int plane_num;
        unsigned int block = SSD_PAGE_TO_BLOCK(ppage, currdisk);

        ASSERT(block < (unsigned int)currdisk->params.blocks_per_element);

        if (metadata->block_usage[block].state == SSD_BLOCK_DEAD) {
          //block dead. dont use this block for future.
          bitpos = ssd_block_to_bitpos(currdisk, block);
          ssd_set_bit(metadata->free_blocks, bitpos);
          ppage+=currdisk->params.pages_per_block;
          continue;
        }

        // if this is the last page in the block
        if (ssd_last_page_in_block(ppage, currdisk)) {
            // leave this physical page for summary page and
            // seal the block
            metadata->block_usage[block].state = SSD_BLOCK_SEALED;
            //metadata->block_usage[block].page[currdisk->params.pages_per_block-1].logical_stresses++;
            //metadata->block_usage[block].total_pages_written++;
            // go to next block
            ppage ++;
            block = SSD_PAGE_TO_BLOCK(ppage, currdisk);
        }

        // if this block is in the reserved section, skip it
        // and go to the next block.
        switch(plane_block_mapping) {
            case PLANE_BLOCKS_CONCAT:
            {
                assert(!"Unsupported plane block mapping PLANE_BLOCKS_CONCAT");
                unsigned int block_index = block % currdisk->params.blocks_per_plane;
                if ((block_index >= usable_blocks_per_plane) && (block_index < currdisk->params.blocks_per_plane)) {
                    // go to next block
                    ppage = ssd_first_page_in_next_block(ppage, currdisk);
                    continue;
                }
            }
            break;

            case PLANE_BLOCKS_PAIRWISE_STRIPE:
            {
                assert(!"Unsupported plane block mapping PLANE_BLOCKS_PAIRWISE_STRIPE");
                unsigned int block_index = block % (2*currdisk->params.blocks_per_plane);
                if ((block_index >= 2*usable_blocks_per_plane) && (block_index < 2*currdisk->params.blocks_per_plane)) {
                    ppage = ssd_first_page_in_next_block(ppage, currdisk);
                    continue;
                }
            }
            break;

            case PLANE_BLOCKS_FULL_STRIPE:
                if ((block >= usable_blocks+dead_block_count) && (block < (unsigned int)currdisk->params.blocks_per_element)) {
                    printf("Error: the control should not come here ...\n");
                    ppage = ssd_first_page_in_next_block(ppage, currdisk);
                    continue;
                }
            break;

            default:
                fprintf(stderr, "Error: unknown plane_block_mapping %d\n", plane_block_mapping);
                exit(1);
        }

        // when the control comes here, 'ppage' contains the next page
        // that can be assigned to a logical page.
        // find the index of the phy page within the block
        pp_index = ppage % currdisk->params.pages_per_block;

        
	// populate the lba table
        metadata->lba_table[i] = ppage;
        pgnum_in_gang = elem_index * export_size + i;
        g->pg2elem[pgnum_in_gang].e = elem_number;

        // mark this block as not free and its state as 'in use'.
        // note that a block could be not free and its state be 'sealed'.
        // it is enough if we set it once while working on the first phy page.
        // also increment the block sequence number.
        if (pp_index == 0) {
            bitpos = ssd_block_to_bitpos(currdisk, block);
            ssd_set_bit(metadata->free_blocks, bitpos);
            metadata->block_usage[block].state = SSD_BLOCK_INUSE;
            metadata->block_usage[block].bsn = bsn ++;
        }

        // increase the usage count per block
        plane_num = metadata->block_usage[block].plane_num;
        metadata->block_usage[block].page[pp_index].lpn = i;
        metadata->block_usage[block].page[pp_index].time_of_last_stress = simtime;
        metadata->block_usage[block].num_valid ++;
        metadata->plane_meta[plane_num].valid_pages ++;

        // go to the next physical page

        ppage ++;

        // go to the next logical page
        i ++;
    }


   
    ssd_assert_free_blocks(currdisk,metadata);   //////////////////////////////////////////////////////////////////////////////
    // init the element's active page as well as the plane's active page.
    int total_blocks = currdisk->params.blocks_per_plane * currdisk->params.planes_per_pkg;
    for (i = 0; i < (unsigned int)currdisk->params.planes_per_pkg; i ++) {
        int blocks_to_skip;
        switch(plane_block_mapping) {
            case PLANE_BLOCKS_CONCAT:
                assert(!"Refresh Operations not supported with PLANE_BLOCKS_CONCAT mapping");
                blocks_to_skip = (i*currdisk->params.blocks_per_plane + usable_blocks_per_plane);
                break;

            case PLANE_BLOCKS_PAIRWISE_STRIPE:
                assert(!"Refresh Operations not supported with PLANE_BLOCKS_PAIRWISE_STRIPE mapping");
                blocks_to_skip = (i/2)*(2*currdisk->params.blocks_per_plane) + (2*usable_blocks_per_plane) + i%2;
                break;

            case PLANE_BLOCKS_FULL_STRIPE:
                /*blocks_to_skip = (currdisk->params.planes_per_pkg * usable_blocks_per_plane) + i + 
                                  metadata->plane_meta[i].dead_blocks;*/
                blocks_to_skip = i;
                for (;blocks_to_skip<total_blocks;blocks_to_skip+=currdisk->params.planes_per_pkg)
                    if(metadata->block_usage[blocks_to_skip].state==SSD_BLOCK_CLEAN)
                      break;
                break;

            default:
                fprintf(stderr, "Error: unknown plane_block_mapping %d\n", plane_block_mapping);
                exit(1);
        }

        metadata->plane_meta[i].active_page = blocks_to_skip*currdisk->params.pages_per_block;
        //metadata->plane_meta[i].free_blocks = reserved_blocks_per_plane-metadata->plane_meta[i].dead_blocks;
    }
    switch(plane_block_mapping) {
        case PLANE_BLOCKS_CONCAT:
            assert(!"Refresh Operations not supported with PLANE_BLOCKS_CONCAT mapping");
            metadata->active_page = usable_blocks_per_plane * currdisk->params.pages_per_block;
            break;

        case PLANE_BLOCKS_PAIRWISE_STRIPE:
            assert(!"Refresh Operations not supported with PLANE_BLOCKS_PAIRWISE_STRIPE mapping");
            metadata->active_page = (2 * usable_blocks_per_plane) * currdisk->params.pages_per_block;
            break;

        case PLANE_BLOCKS_FULL_STRIPE:
            //metadata->active_page = currdisk->params.planes_per_pkg * (usable_blocks_per_plane+metadata->plane_meta[0].dead_blocks) * currdisk->params.pages_per_block;
            metadata->active_page = metadata->plane_meta[0].active_page;
            break;

        default:
            fprintf(stderr, "Error: unknown plane_block_mapping %d\n", plane_block_mapping);
            exit(1);
    }

    //ASSERT(metadata->active_page == metadata->plane_meta[0].active_page);
    active_block = metadata->active_page / currdisk->params.pages_per_block;

    //////////////////////////////////////////////////////////////////////////////
    // mark the block that corresponds to the active page
    // as not free and 'in_use'.
    ssd_assert_free_blocks(currdisk,metadata);
    switch(currdisk->params.copy_back) {
        case SSD_COPY_BACK_DISABLE:
            assert(!"Refresh Operation not supported for copy back disabled parameter");
            bitpos = ssd_block_to_bitpos(currdisk, active_block);
            ssd_set_bit(metadata->free_blocks, bitpos);
            metadata->block_usage[active_block].state = SSD_BLOCK_INUSE;
            metadata->block_usage[active_block].bsn = bsn ++;
        break;

        case SSD_COPY_BACK_ENABLE:
            for (i = 0; i < (unsigned int)currdisk->params.planes_per_pkg; i ++) {
                int plane_active_block = SSD_PAGE_TO_BLOCK(metadata->plane_meta[i].active_page, currdisk);

                bitpos = ssd_block_to_bitpos(currdisk, plane_active_block);
                ssd_set_bit(metadata->free_blocks, bitpos);
                metadata->block_usage[plane_active_block].state = SSD_BLOCK_INUSE;
                metadata->block_usage[plane_active_block].bsn = bsn ++;
                metadata->tot_free_blocks --;
                metadata->plane_meta[i].free_blocks --;
            }
            ssd_assert_free_blocks(currdisk,metadata);
        break;

        default:
            fprintf(stderr, "Error: invalid copy back policy %d\n",
                currdisk->params.copy_back);
            exit(1);
    }

    //////////////////////////////////////////////////////////////////////////////
    // set the bsn for the ssd element
    metadata->bsn = bsn;
    //printf("set the bsn to %d\n", bsn);
}
Beispiel #5
0
static double ssd_issue_overlapped_ios(ssd_req **reqs, int total, int elem_num, ssd_t *s)
{
    double max_cost = 0;
    double parunit_op_cost[SSD_MAX_PARUNITS_PER_ELEM];
    double parunit_tot_cost[SSD_MAX_PARUNITS_PER_ELEM];
    ssd_element_metadata *metadata;
    int lpn;
    int i;
    int read_cycle = 0;
    listnode **parunits;

    // all the requests must be of the same type
    for (i = 1; i < total; i ++) {
        ASSERT(reqs[i]->is_read == reqs[0]->is_read);
    }

    // is this a set of read requests?
    if (reqs[0]->is_read) {
        read_cycle = 1;
    }

    memset(parunit_tot_cost, 0, sizeof(double)*SSD_MAX_PARUNITS_PER_ELEM);

    // find the planes to which the reqs are to be issued
    metadata = &(s->elements[elem_num].metadata);
    parunits = ssd_pick_parunits(reqs, total, elem_num, metadata, s);

    // repeat until we've served all the requests
    while (1) {
        //double tot_xfer_cost = 0;
        double max_op_cost = 0;
        int active_parunits = 0;
        int op_count = 0;

        // do we still have any request to service?
        for (i = 0; i < SSD_PARUNITS_PER_ELEM(s); i ++) {
            if (ll_get_size(parunits[i]) > 0) {
                active_parunits ++;
            }
        }

        // no more requests -- get out
        if (active_parunits == 0) {
            break;
        }

        // clear this arrays for storing costs
        memset(parunit_op_cost, 0, sizeof(double)*SSD_MAX_PARUNITS_PER_ELEM);

        // begin a round of serving. we serve one request per
        // parallel unit. if an unit has more than one request
        // in the list, they have to be serialized.
        max_cost = 0;
        for (i = 0; i < SSD_PARUNITS_PER_ELEM(s); i ++) {
            int size;

            size = ll_get_size(parunits[i]);
            if (size > 0) {
                // this parallel unit has a request to serve
                ssd_req *r;
                listnode *n = ll_get_nth_node(parunits[i], 0);

                op_count ++;
                ASSERT(op_count <= active_parunits);

                // get the request
                r = (ssd_req *)n->data;
                lpn = ssd_logical_pageno(r->blk, s);

                if (r->is_read) {
                    parunit_op_cost[i] = s->params.page_read_latency;
                } else {
                    int plane_num = r->plane_num;
                    // if this is the last page on the block, allocate a new block
                    if (ssd_last_page_in_block(metadata->plane_meta[plane_num].active_page, s)) {
                        _ssd_alloc_active_block(plane_num, elem_num, s);
                    }

                    // issue the write to the current active page.
                    // we need to transfer the data across the serial pins for write.
                    metadata->active_page = metadata->plane_meta[plane_num].active_page;
                    //printf("elem %d plane %d ", elem_num, plane_num);
                    parunit_op_cost[i] = _ssd_write_page_osr(s, metadata, lpn);
                }

                ASSERT(r->count <= s->params.page_size);

                // calc the cost: the access time should be something like this
                // for read
                if (read_cycle) {
                    if (SSD_PARUNITS_PER_ELEM(s) > 4) {
                        printf("modify acc time here ...\n");
                        ASSERT(0);
                    }
                    if (op_count == 1) {
                        r->acctime = parunit_op_cost[i] + ssd_data_transfer_cost(s,s->params.page_size);
                        r->schtime = parunit_tot_cost[i] + (op_count-1)*ssd_data_transfer_cost(s,s->params.page_size) + r->acctime;
                    } else {
                        r->acctime = ssd_data_transfer_cost(s,s->params.page_size);
                        r->schtime = parunit_tot_cost[i] + op_count*ssd_data_transfer_cost(s,s->params.page_size) + parunit_op_cost[i];
                    }
                } else {
                    // for write
                    r->acctime = parunit_op_cost[i] + ssd_data_transfer_cost(s,s->params.page_size);
                    r->schtime = parunit_tot_cost[i] + (op_count-1)*ssd_data_transfer_cost(s,s->params.page_size) + r->acctime;
                }


                // find the maximum cost for this round of operations
                if (max_cost < r->schtime) {
                    max_cost = r->schtime;
                }

                // release the node from the linked list
                ll_release_node(parunits[i], n);
            }
        }

        // we can start the next round of operations only after all
        // the operations in the first round are over because we're
        // limited by the one set of pins to all the parunits
        for (i = 0; i < SSD_PARUNITS_PER_ELEM(s); i ++) {
            parunit_tot_cost[i] = max_cost;
        }
    }

    for (i = 0; i < SSD_PARUNITS_PER_ELEM(s); i ++) {
        ll_release(parunits[i]);
    }
    free(parunits);

    return max_cost;
}