mems_event.c
来自「disksim是一个非常优秀的磁盘仿真工具」· C语言 代码 · 共 1,946 行 · 第 1/4 页
C
1,946 行
/* ...and energy consumed during sled startup. */ energy_j = (sled->active_power_mw * sled->startup_time_ms) / 1000000.0; sled->dev->stat.total_energy_j += energy_j; sled->stat.total_energy_j += energy_j; sled->dev->stat.startup_energy_j += energy_j; sled->stat.startup_energy_j += energy_j; /* FIXME: Should request_energy be updated with startup energy? */}voidmems_energy_update_device_overhead_complete_active(mems_sled_t *sled, double elapsed_time){ double energy_j = (sled->active_power_mw * elapsed_time) / 1000000.0; sled->dev->stat.total_energy_j += energy_j; sled->stat.total_energy_j += energy_j; sled->dev->stat.idle_energy_j += energy_j; sled->stat.idle_energy_j += energy_j;}voidmems_energy_update_sled_seek(mems_sled_t *sled, double timedelta){ double energy_j = (sled->active_power_mw * timedelta) / 1000000.0; sled->dev->stat.total_energy_j += energy_j; sled->stat.total_energy_j += energy_j; if (sled->active_request) { mems_reqinfo_t *reqinfo = sled->active_request->mems_reqinfo; reqinfo->request_energy_uj += energy_j * 1000000.0; } if (sled->active_request || sled->prefetch_info) { sled->dev->stat.servicing_energy_j += energy_j; sled->stat.servicing_energy_j += energy_j; } else { sled->dev->stat.idle_energy_j += energy_j; sled->stat.idle_energy_j += energy_j; }}voidmems_energy_update_sled_servo(mems_sled_t *sled, double timedelta){ /* Account for both sled positioning energy and tip dissipation. */ // int num_tips = sled->tipset.tip_end - sled->tipset.tip_start + 1; int num_tips = sled->tipset.num_tips; double energy_j = ((sled->active_power_mw * timedelta) + (sled->tip_power_mw * num_tips * timedelta)) / 1000000.0; sled->dev->stat.total_energy_j += energy_j; sled->stat.total_energy_j += energy_j; if (sled->active_request) { mems_reqinfo_t *reqinfo = sled->active_request->mems_reqinfo; int num_tips_req = sled->tip_sectors_per_lbn * (reqinfo->next_block_end - reqinfo->next_block_start + 1); double energy_j_req = ((sled->active_power_mw * timedelta) + (sled->tip_power_mw * num_tips_req * timedelta)) / 1000000.0; reqinfo->request_energy_uj += energy_j_req * 1000000.0; } if (sled->active_request || sled->prefetch_info) { sled->dev->stat.servicing_energy_j += energy_j; sled->stat.servicing_energy_j += energy_j; } else { sled->dev->stat.idle_energy_j += energy_j; sled->stat.idle_energy_j += energy_j; }}voidmems_energy_update_sled_data(mems_sled_t *sled, double timedelta){ /* Account for both sled positioning energy and tip dissipation. */ // int num_tips = sled->tipset.tip_end - sled->tipset.tip_start + 1; int num_tips = sled->tipset.num_tips; double energy_j = ((sled->active_power_mw * timedelta) + (sled->tip_power_mw * num_tips * timedelta)) / 1000000.0; sled->dev->stat.total_energy_j += energy_j; sled->stat.total_energy_j += energy_j; if (sled->active_request) { mems_reqinfo_t *reqinfo = sled->active_request->mems_reqinfo; int num_tips_req = sled->tip_sectors_per_lbn * (reqinfo->next_block_end - reqinfo->next_block_start + 1); double energy_j_req = ((sled->active_power_mw * timedelta) + (sled->tip_power_mw * num_tips_req * timedelta)) / 1000000.0; reqinfo->request_energy_uj += energy_j_req * 1000000.0; } sled->dev->stat.servicing_energy_j += energy_j; sled->stat.servicing_energy_j += energy_j;}/************************************************************************ * Event handling functions ************************************************************************/voidmems_io_access_arrive(ioreq_event *curr){ mems_sled_t *sled = curr->mems_sled; mems_t *dev = getmems(curr->devno);#ifdef VERBOSE_EVENTLOOP printf("\nIO_ACCESS_ARRIVE: %f -- %s for %d(%d), batchno = %d, batch_complete = %d\n", simtime, (curr->flags & READ) ? "R" : "W", curr->blkno, curr->bcount, curr->batchno, curr->batch_complete); fflush(stdout);#endif /* A new request! * - Initialize the per-request mems info structure. * - Map the request to the appropriate sled. */ curr->batch_next = NULL; curr->batch_prev = NULL; curr->batch_size = 0; curr->mems_sled = mems_lbn_to_sled(dev, curr->blkno); curr->mems_reqinfo = mems_get_new_reqinfo(curr); dev->busowned = mems_get_busno(curr); curr->time = simtime + dev->overhead; curr->type = DEVICE_OVERHEAD_COMPLETE; addtointq((event *)curr);}voidmems_device_overhead_complete(ioreq_event *curr){ mems_sled_t *sled = curr->mems_sled; mems_t *dev = getmems(curr->devno);#ifdef VERBOSE_EVENTLOOP printf("\nDEVICE_OVERHEAD_COMPLETE: %f\n", simtime); fflush(stdout);#endif /* - Add the request to sled's/device's incoming request queue. */ ioqueue_add_new_request(sled->queue, curr); // ioqueue_add_new_request(sled->dev->queue, curr); // if (curr->batchno == 0) if (1) { /* If it's a write request, go ahead and keep the bus to start * transferring blocks into the buffer */ if (!(curr->flags & READ)) { ioreq_event *busreq = ioreq_copy(curr);#ifdef VERBOSE_EVENTLOOP printf("\n adding a MEMS_BUS_INITIATE event to the intq: %f\n", simtime); fflush(stdout);#endif busreq->type = MEMS_BUS_INITIATE; busreq->time = simtime; addtointq((event *)busreq); ((mems_reqinfo_t *)(curr->mems_reqinfo))->bus_pending = TRUE; } else { /* Special case: If all the blocks for this request are already * buffered, no need to add request to sled active queue (or even * notify sled at all) -- instead, just put the busxfer event on * the queue. */ // I need to decide whether I can respond to a single request // of a batch if it is buffered, or if I have to check the whole // thing. // A case which would cause problems would be if only the last // request of the batch was cached, but other requests in the // batch were not. In this case, the batch would never come out // of the ioqueue, since it would never be completed. The hope // is that if one request of the batch is cached, then the rest // are as well. I may need to make that explicit. mems_reqinfo_t *reqinfo = curr->mems_reqinfo; mems_extent_t *extent_ptr = reqinfo->extents; if (mems_buffer_check(extent_ptr->firstblock, extent_ptr->lastblock, sled->dev)) { // ioqueue_get_specific_request(sled->dev->queue, curr); ioqueue_get_specific_request(sled->queue, curr); extent_ptr->completed_block_media = extent_ptr->lastblock; extent_ptr->media_done = TRUE; { ioreq_event *busreq = ioreq_copy(curr); busreq->type = MEMS_BUS_INITIATE; busreq->time = simtime; addtointq((event *)busreq); reqinfo->bus_pending = TRUE; } addtoextraq((event *)curr); // I think curr gets freed later... return; } /* Release the bus if there's no dataxfer_req holding it */ if (!sled->dev->dataxfer_req) { send_disconnect(curr, 0.0); } } } /* else if ((curr->batchno != 0) && (curr->batch_complete == TRUE)) { if (!(curr->flags & READ)) { ioreq_event *busreq = ioreq_copy(curr); busreq->type = MEMS_BUS_INITIATE; busreq->time = simtime; addtointq((event *)busreq); ((mems_reqinfo_t *)(curr->mems_reqinfo))->bus_pending = TRUE; } } */ else { if (!sled->dev->dataxfer_req) { send_disconnect(curr, 0.0); } } // don't move to the scheduling state unless a batch is complete. // in theory, this should work even when issuing interleaved // requests from multiple batches. when a batch (any batch) is // complete, then MEMS_SLED_SCHEDULE will pull it out of the ioqueue // and start crunching on it. if ((curr->batchno == 0) || (curr->batch_complete == TRUE)) { /* If the sled is in the inactive power-saving state, reactivate it */ if (sled->active == MEMS_SLED_INACTIVE) { ioreq_event *r = (ioreq_event *)getfromextraq(); // fflush(stdout); // printf("GETFROMEXTRAQ - first\n"); r->devno = curr->devno; /* FIXME: Crashes without above line. Why? Use ioreq_copy? */ r->type = MEMS_SLED_SCHEDULE; r->time = simtime + sled->startup_time_ms; /* FIXME: curr->time doesn't work (for simtime). Why? */ r->mems_sled = sled; addtointq((event *)r); sled->active = MEMS_SLED_ACTIVE; /* Spindown/spinup statistics */ sled->stat.num_spinups++; sled->dev->stat.num_spinups++; stat_update(&sled->stat.inactive_time, (simtime - sled->lastreq_comptime)); stat_update(&sled->dev->stat.inactive_time, (simtime - sled->lastreq_comptime)); /* Energy statistics -- only if resuming from inactive */ mems_energy_update_device_overhead_complete_inactive(sled); } else if (sled->active == MEMS_SLED_IDLE) { /* the sled is idle, but not spun down */ coord_t *update_coord; double elapsed_time; double sweep_time; double leftover_time; double extra_sweeps; int extra_distance; int sled_length_bits; ioreq_event *r = (ioreq_event *)getfromextraq(); // printf("GETFROMEXTRAQ - second\n"); r->devno = curr->devno; /* FIXME: Crashes without above line. Why? Use ioreq_copy? */ r->type = MEMS_SLED_SCHEDULE; r->time = simtime; /* FIXME: curr->time doesn't work (for simtime). Why? */ removefromintq((event *)sled->active_request); sled->active_request = NULL; /* figure out where the sled should be at this point */ update_coord = mems_get_current_position(sled); elapsed_time = simtime - sled->lastreq_comptime; sweep_time = find_turnaround_time((sled->y_length_nm / 2), sled->y_access_speed_bit_s * sled->bit_length_nm, sled->x_accel_nm_s2, sled->spring_factor, sled->y_length_nm); sweep_time += sled->y_length_nm / sled->y_access_speed_bit_s * sled->bit_length_nm; leftover_time = fmod(elapsed_time, sweep_time); extra_sweeps = (double)(leftover_time / sweep_time); sled_length_bits = sled->y_length_nm / sled->bit_length_nm; extra_distance = (int)(extra_sweeps * (double)(sled->y_length_nm)) / sled->bit_length_nm; if (update_coord->y_vel > 0) { /* if we're moving up */ update_coord->y_pos += extra_distance; if (abs(update_coord->y_pos) > (sled_length_bits / 2)) { /* if we've gone too far... */ update_coord->y_pos = ((sled_length_bits / 2) - (update_coord->y_pos - (sled_length_bits / 2))); update_coord->y_vel = -update_coord->y_vel; } } else { /* we're moving down */ update_coord->y_pos -= extra_distance; if (abs(update_coord->y_pos) > (sled_length_bits / 2)) { /* if we've gone too far... */ update_coord->y_pos = ((-sled_length_bits / 2) + (abs(update_coord->y_pos) - (sled_length_bits / 2))); update_coord->y_vel = -update_coord->y_vel; } } mems_commit_move(sled, update_coord); r->mems_sled = sled; addtointq((event *)r); sled->active = MEMS_SLED_ACTIVE; mems_energy_update_device_overhead_complete_active(sled, elapsed_time); } }}voidmems_sled_schedule(ioreq_event *curr){ mems_sled_t *sled = curr->mems_sled; mems_t *dev = getmems(curr->devno); ioreq_event *old_active_request; #ifdef VERBOSE_EVENTLOOP printf("MEMS_SLED_SCHEDULE: %f\n", simtime); fflush(stdout);#endif if ((sled->active == MEMS_SLED_IDLE) && (curr->time >= sled->lastreq_comptime + sled->inactive_delay_ms)) { /* the sled has been idle and should now spin down */ // printf("Sled was idle, now it's spun down.\n"); sled->lastreq_comptime = curr->time; // sled->lastreq_lbn = mems_centermost_lbn(sled); /* Initialize sled position, velocity at centermost LBN */ mems_lbn_to_position(mems_centermost_lbn(sled), sled, &sled->coordset_up, &sled->coordset_dn, &sled->tipset, NULL, NULL, NULL); mems_coord_t_copy(&sled->coordset_up.servo_start, &sled->pos); sled->active = MEMS_SLED_INACTIVE; sled->active_request = NULL; addtoextraq((event *)curr); /* Spindown/spinup statistics */ sled->stat.num_spindowns++; sled->dev->stat.num_spindowns++; // printf("Hello!! curr->type = %d, curr->time = %f\n", curr->type, curr->time); return; } else if ((sled->active == MEMS_SLED_IDLE) && (curr->time < sled->lastreq_comptime + sled->inactive_delay_ms)) { /* the sled is idle, but now there's a new request */ // printf("Sled was idle, but there's a new request coming in.\n"); sled->active = MEMS_SLED_ACTIVE; removefromintq((event *)sled->active_request); sled->active_request = NULL; } /* First check if there's no active request, and try to find one. */ if (!sled->active_request) { sled->active_request = ioqueue_get_next_request(sled->queue); if (sled->active_request) { // ioqueue_get_specific_request(sled->dev->queue, sled->active_request); // i think that this is only done for stats. -schlos // a single ioreq_event can have multiple ioreq_events chained off of it // in the extents. ioqueue_get_next_request returns a pointer to a chain // of ioreq_events, if the request is part of a batch. those requests get // put into the mems_reqinfo extents, each with a pointer to the ioreq_event // which originally generated that extent. however, ioqueue_get_next_request // returns the ioreq_event of the first request in the batch. so if that // request finishes before the others in the batch, it will hose the entire // batch and all of its extents. i need to make a copy of the ioreq_event // and use that to execute this batch. and make sure i free it when all of // the extents are complete. // // i think... if (sled->active_request->batch_next != NULL) { // printf("more than one request was returned!\n"); mems_update_reqinfo(sled->active_request);#ifdef VERBOSE_EVENTLOOP print_extent_info(sled->active_request->mems_reqinfo);#endif } old_active_request = sled->active_request; sled->active_request = ioreq_copy(sled->active_request); old_active_request->mems_reqinfo = NULL; /* Just got a new active request, so throw out old prefetch info */ /* if (sled->prefetch_info) { if (sled->prefetch_info->completed_block != -1) { int fetched_blocks = sled->prefetch_info->completed_block - sled->prefetch_info->firstblock + 1; stat_update(&sled->stat.prefetched_blocks, fetched_blocks); stat_update(&sled->dev->stat.prefetched_blocks, fetched_blocks); } // addtoextraq((event *)sled->prefetch_info); sled->prefetch_info = NULL; } */ /* If new request is a read, get new prefetch info */ if (sled->active_request->flags & READ) { // sled->prefetch_info = mems_get_prefetch_info(sled->active_request); } } } /* Now, if there's an active request, figure out which position to seek * to, and which blocks to access once we're there. */ if (sled->active_request) { int extent; int block;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?