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 + -
显示快捷键?