summaryrefslogtreecommitdiff
path: root/src/gpgpu-sim/dram.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/gpgpu-sim/dram.cc')
-rw-r--r--src/gpgpu-sim/dram.cc604
1 files changed, 604 insertions, 0 deletions
diff --git a/src/gpgpu-sim/dram.cc b/src/gpgpu-sim/dram.cc
new file mode 100644
index 0000000..9f76b32
--- /dev/null
+++ b/src/gpgpu-sim/dram.cc
@@ -0,0 +1,604 @@
+/*
+ * dram.c
+ *
+ * Copyright (c) 2009 by Tor M. Aamodt, Wilson W. L. Fung, George L. Yuan,
+ * Ivan Sham, Justin Kwong, Dan O'Connor and the
+ * University of British Columbia
+ * Vancouver, BC V6T 1Z4
+ * All Rights Reserved.
+ *
+ * THIS IS A LEGAL DOCUMENT BY DOWNLOADING GPGPU-SIM, YOU ARE AGREEING TO THESE
+ * TERMS AND CONDITIONS.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNERS OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * NOTE: The files libcuda/cuda_runtime_api.c and src/cuda-sim/cuda-math.h
+ * are derived from the CUDA Toolset available from http://www.nvidia.com/cuda
+ * (property of NVIDIA). The files benchmarks/BlackScholes/ and
+ * benchmarks/template/ are derived from the CUDA SDK available from
+ * http://www.nvidia.com/cuda (also property of NVIDIA). The files from
+ * src/intersim/ are derived from Booksim (a simulator provided with the
+ * textbook "Principles and Practices of Interconnection Networks" available
+ * from http://cva.stanford.edu/books/ppin/). As such, those files are bound by
+ * the corresponding legal terms and conditions set forth separately (original
+ * copyright notices are left in files from these sources and where we have
+ * modified a file our copyright notice appears before the original copyright
+ * notice).
+ *
+ * Using this version of GPGPU-Sim requires a complete installation of CUDA
+ * which is distributed seperately by NVIDIA under separate terms and
+ * conditions. To use this version of GPGPU-Sim with OpenCL requires a
+ * recent version of NVIDIA's drivers which support OpenCL.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the University of British Columbia nor the names of
+ * its contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * 4. This version of GPGPU-SIM is distributed freely for non-commercial use only.
+ *
+ * 5. No nonprofit user may place any restrictions on the use of this software,
+ * including as modified by the user, by any other authorized user.
+ *
+ * 6. GPGPU-SIM was developed primarily by Tor M. Aamodt, Wilson W. L. Fung,
+ * Ali Bakhoda, George L. Yuan, at the University of British Columbia,
+ * Vancouver, BC V6T 1Z4
+ */
+
+//#include "gpu-sim.h"
+#include "gpu-misc.h"
+//#include "shader.h"
+#include "dram.h"
+
+extern unsigned long long gpu_sim_cycle;
+extern signed long long gpu_tot_sim_cycle;
+extern int gpgpu_memlatency_stat;
+extern unsigned max_dq_latency;
+extern unsigned dq_lat_table[24];
+extern unsigned max_dq_latency;
+extern unsigned dq_lat_table[24];
+unsigned int gpu_n_warps;
+extern unsigned int gpu_n_mem_per_ctrlr;
+extern unsigned int recent_dram_util;
+
+#ifdef DRAM_VERIFY
+int PRINT_CYCLE = 0;
+#endif
+
+dram_t* dram_create( unsigned int id, unsigned int nbk,
+ unsigned int tCCD, unsigned int tRRD,
+ unsigned int tRCD, unsigned int tRAS,
+ unsigned int tRP, unsigned int tRC,
+ unsigned int CL, unsigned int WL,
+ unsigned int BL, unsigned int tWTR,
+ unsigned int busW, unsigned int queue_limit,
+ unsigned char scheduler_type )
+{
+ dram_t *dm;
+ unsigned i;
+
+ dm = (dram_t*)calloc(1,sizeof(dram_t));
+
+ dm->id = id;
+
+ dm->nbk = nbk;
+ dm->tCCD = tCCD;
+ dm->tRRD = tRRD;
+ dm->tRCD = tRCD;
+ dm->tRCDWR = tRCD - (WL + 1); //formula given in datasheet
+ dm->tRAS = tRAS;
+ dm->tRP = tRP;
+ dm->tRC = tRC;
+ dm->CL = CL;
+ dm->WL = WL;
+ dm->BL = BL;
+
+ dm->tRTW = (CL+(BL/2)+2-WL); //read to write time according to datasheet
+ dm->tWTR = tWTR;
+
+ dm->busW = busW;
+
+ dm->CCDc = 0;
+ dm->RRDc = 0;
+ dm->RTWc = 0;
+ dm->WTRc = 0;
+
+ dm->rw = READ; //read mode is default
+
+ dm->bk = (bank_t**) calloc(sizeof(bank_t*),dm->nbk);
+ dm->bk[0] = (bank_t*) calloc(sizeof(bank_t),dm->nbk);
+ for (i=1;i<dm->nbk;i++) {
+ dm->bk[i] = dm->bk[0] + i;
+ }
+ for (i=0;i<dm->nbk;i++) {
+ dm->bk[i]->state = BANK_IDLE;
+ }
+ dm->prio = 0;
+ dm->rwq = dq_create("rwq",0,dm->CL,dm->CL+1);
+ dm->mrqq = dq_create("mrqq",0,0,0);
+ dm->queue_limit = queue_limit;
+
+ dm->returnq = dq_create("dramreturnq",0,0, queue_limit);
+
+ dm->m_fast_ideal_scheduler = NULL;
+ if ( scheduler_type == DRAM_IDEAL_FAST )
+ dm->m_fast_ideal_scheduler = alloc_fast_ideal_scheduler(dm);
+
+
+ dm->n_cmd = 0;
+ dm->n_activity = 0;
+ dm->n_nop = 0;
+ dm->n_act = 0;
+ dm->n_pre = 0;
+ dm->n_rd = 0;
+ dm->n_wr = 0;
+ dm->n_req = 0;
+ dm->max_mrqs_temp = 0;
+
+ dm->bwutil = 0;
+
+ dm->max_mrqs = 0;
+
+ dm->scheduler_type = scheduler_type;
+
+ dm->realistic_scheduler_mode = READ; //realistic scheduler defaults to read
+ for (i=0;i<10;i++) {
+ dm->dram_util_bins[i]=0;
+ dm->dram_eff_bins[i]=0;
+ }
+ dm->last_n_cmd = dm->last_n_activity = dm->last_bwutil = 0;
+
+ dm->n_cmd_partial = 0;
+ dm->n_activity_partial = 0;
+ dm->n_nop_partial = 0;
+ dm->n_act_partial = 0;
+ dm->n_pre_partial = 0;
+ dm->n_req_partial = 0;
+ dm->ave_mrqs_partial = 0;
+ dm->bwutil_partial = 0;
+ return dm;
+}
+
+void dram_free( dram_t *dm )
+{
+ dq_free(dm->mrqq);
+ dq_free(dm->rwq);
+ dq_free( dm->returnq );
+
+ free(dm->bk[0]);
+ free(dm->bk);
+ free(dm);
+}
+
+int dram_full( dram_t *dm )
+{
+ int full = 0;
+ if ( dm->queue_limit == 0 ) return 0;
+ if ( dm->scheduler_type == DRAM_IDEAL_FAST ) {
+ unsigned nreqs = fast_scheduler_queue_length(dm) + dq_n_element(dm->mrqq);
+ full = (nreqs >= dm->queue_limit);
+ } else {
+ full = (dm->mrqq->length >= dm->queue_limit);
+ }
+
+ return full;
+}
+
+unsigned int dram_que_length( dram_t *dm )
+{
+ unsigned nreqs = 0;
+ if (dm->scheduler_type == DRAM_IDEAL_FAST ) {
+ nreqs = fast_scheduler_queue_length(dm);
+ } else {
+ nreqs = dm->mrqq->length ;
+ }
+ return nreqs;
+}
+
+void dram_push( dram_t *dm, unsigned int bank,
+ unsigned int row, unsigned int col,
+ unsigned int nbytes, unsigned int write,
+ unsigned int wid,
+ unsigned int sid, int cache_hits_waiting, unsigned long long addr,
+ void *data )
+{
+ dram_req_t *mrq;
+
+ if (bank>=dm->nbk) printf("ERROR: no such bank exist in DRAM %d\n", bank);
+
+ mrq = (dram_req_t *) malloc(sizeof(dram_req_t));
+
+ mrq->bk = bank;
+ mrq->row = row;
+ mrq->col = col;
+ mrq->nbytes = nbytes;
+ mrq->txbytes = 0;
+ mrq->dqbytes = 0;
+ mrq->data = data;
+ mrq->timestamp = gpu_tot_sim_cycle + gpu_sim_cycle;
+ mrq->cache_hits_waiting = cache_hits_waiting;
+ mrq->addr = addr;
+ mrq->insertion_time = (unsigned) gpu_sim_cycle;
+
+ if (!write) {
+ mrq->rw = READ; //request is a read
+ } else {
+ mrq->rw = WRITE; //request is a write
+ }
+
+ dq_push(dm->mrqq,mrq);
+ dm->n_req += 1;
+ dm->n_req_partial += 1;
+
+ if ( dm->scheduler_type == DRAM_IDEAL_FAST ) {
+ unsigned nreqs = fast_scheduler_queue_length(dm);
+ if ( nreqs > dm->max_mrqs_temp)
+ dm->max_mrqs_temp = nreqs;
+ } else {
+ dm->max_mrqs_temp = (dm->max_mrqs_temp > dm->mrqq->length)? dm->max_mrqs_temp : dm->mrqq->length;
+ }
+}
+
+void scheduler_fifo(dram_t* dm)
+{
+ if (dm->mrqq->head) {
+ dram_req_t *head_mrqq;
+ unsigned int bkn;
+ head_mrqq = (dram_req_t *)dm->mrqq->head->data;
+ bkn = head_mrqq->bk;
+ if (!dm->bk[bkn]->mrq) {
+ dm->bk[bkn]->mrq = (dram_req_t*) dq_pop(dm->mrqq);
+ }
+ }
+}
+
+
+#define DEC2ZERO(x) x = (x)? (x-1) : 0;
+#define SWAP(a,b) a ^= b; b ^= a; a ^= b;
+
+void dram_issueCMD (dram_t* dm)
+{
+ unsigned i,j,k;
+ unsigned char issued;
+ issued = 0;
+
+ /* check if the upcoming request is on an idle bank */
+ /* Should we modify this so that multiple requests are checked? */
+
+ switch (dm->scheduler_type) {
+ case DRAM_FIFO:
+ scheduler_fifo(dm);
+ break;
+ case DRAM_IDEAL_FAST:
+ fast_scheduler_ideal(dm);
+ break;
+ default:
+ printf("Error: Unknown DRAM scheduler type\n");
+ assert(0);
+ }
+ if ( dm->scheduler_type == DRAM_IDEAL_FAST ) {
+ unsigned nreqs = fast_scheduler_queue_length(dm);
+ if ( nreqs > dm->max_mrqs) {
+ dm->max_mrqs = nreqs;
+ }
+ dm->ave_mrqs += nreqs;
+ dm->ave_mrqs_partial += nreqs;
+ } else {
+ if (dm->mrqq->length > dm->max_mrqs) {
+ dm->max_mrqs = dm->mrqq->length;
+ }
+ dm->ave_mrqs += dm->mrqq->length;
+ dm->ave_mrqs_partial += dm->mrqq->length;
+ }
+ k=dm->nbk;
+ // check if any bank is ready to issue a new read
+ for (i=0;i<dm->nbk;i++) {
+ j = (i + dm->prio) % dm->nbk;
+ if (dm->bk[j]->mrq) { //if currently servicing a memory request
+ // correct row activated for a READ
+ if ( !issued && !dm->CCDc && !dm->bk[j]->RCDc &&
+ (dm->bk[j]->curr_row == dm->bk[j]->mrq->row) &&
+ (dm->bk[j]->mrq->rw == READ) && (dm->WTRc == 0 ) &&
+ (dm->bk[j]->state == BANK_ACTIVE) &&
+ !dq_full(dm->rwq) ) {
+ if (dm->rw==WRITE) {
+ dm->rw=READ;
+ dq_set_min_length(dm->rwq, dm->CL);
+ }
+ dq_push(dm->rwq,(void*)dm->bk[j]->mrq); //only push when rwq empty?
+ dm->bk[j]->mrq->txbytes += dm->BL * dm->busW * gpu_n_mem_per_ctrlr; //16 bytes
+ dm->CCDc = dm->tCCD;
+ dm->RTWc = dm->tRTW;
+ issued = 1;
+ dm->n_rd++;
+ //printf("\tn_rd++ Bank: %d Row: %d Col: %d\n", j, dm->bk[j]->mrq->row, dm->bk[j]->mrq->col);
+ dm->bwutil+= dm->BL/2;
+ dm->bwutil_partial += dm->BL/2;
+ dm->bk[j]->n_access++;
+#ifdef DRAM_VERIFY
+ PRINT_CYCLE=1;
+ printf("\tRD Bk:%d Row:%03x Col:%03x \n",
+ j, dm->bk[j]->curr_row,
+ dm->bk[j]->mrq->col+dm->bk[j]->mrq->txbytes-dm->BL*dm->busW);
+#endif
+ // transfer done
+ if ( !(dm->bk[j]->mrq->txbytes < dm->bk[j]->mrq->nbytes) ) {
+ dm->bk[j]->mrq = NULL;
+ }
+ } else
+ // correct row activated for a WRITE
+ if ( !issued && !dm->CCDc && !dm->bk[j]->RCDWRc &&
+ (dm->bk[j]->curr_row == dm->bk[j]->mrq->row) &&
+ (dm->bk[j]->mrq->rw == WRITE) && (dm->RTWc == 0 ) &&
+ (dm->bk[j]->state == BANK_ACTIVE) &&
+ !dq_full(dm->rwq) ) {
+ if (dm->rw==READ) {
+ dm->rw=WRITE;
+ dq_set_min_length(dm->rwq, dm->WL);
+ }
+ dq_push(dm->rwq,(void*)dm->bk[j]->mrq);
+
+ dm->bk[j]->mrq->txbytes += dm->BL * dm->busW * gpu_n_mem_per_ctrlr; /*16 bytes*/
+ dm->CCDc = dm->tCCD;
+ issued = 1;
+ dm->n_wr++;
+ dm->bwutil+=2;
+ dm->bwutil_partial += dm->BL/2;
+#ifdef DRAM_VERIFY
+ PRINT_CYCLE=1;
+ printf("\tWR Bk:%d Row:%03x Col:%03x \n",
+ j, dm->bk[j]->curr_row,
+ dm->bk[j]->mrq->col+dm->bk[j]->mrq->txbytes-dm->BL*dm->busW);
+#endif
+ // transfer done
+ if ( !(dm->bk[j]->mrq->txbytes < dm->bk[j]->mrq->nbytes) ) {
+ dm->bk[j]->mrq = NULL;
+ }
+ }
+
+ else
+ // bank is idle
+ if ( !issued && !dm->RRDc &&
+ (dm->bk[j]->state == BANK_IDLE) &&
+ !dm->bk[j]->RPc && !dm->bk[j]->RCc ) {
+#ifdef DRAM_VERIFY
+ PRINT_CYCLE=1;
+ printf("\tACT BK:%d NewRow:%03x From:%03x \n",
+ j,dm->bk[j]->mrq->row,dm->bk[j]->curr_row);
+#endif
+ // activate the row with current memory request
+ dm->bk[j]->curr_row = dm->bk[j]->mrq->row;
+ dm->bk[j]->state = BANK_ACTIVE;
+ dm->RRDc = dm->tRRD;
+ dm->bk[j]->RCDc = dm->tRCD;
+ dm->bk[j]->RCDWRc = dm->tRCDWR;
+ dm->bk[j]->RASc = dm->tRAS;
+ dm->bk[j]->RCc = dm->tRC;
+ dm->prio = (j + 1) % dm->nbk;
+ issued = 1;
+ dm->n_act_partial++;
+ dm->n_act++;
+ }
+
+ else
+ // different row activated
+ if ( (!issued) &&
+ (dm->bk[j]->curr_row != dm->bk[j]->mrq->row) &&
+ (dm->bk[j]->state == BANK_ACTIVE) &&
+ (!dm->bk[j]->RASc) ) {
+ //printf("\tRASc: %d \n", dm->bk[j]->RASc);
+ // make the bank idle again
+ dm->bk[j]->state = BANK_IDLE;
+ dm->bk[j]->RPc = dm->tRP;
+ dm->prio = (j + 1) % dm->nbk;
+ issued = 1;
+ dm->n_pre++;
+ dm->n_pre_partial++;
+#ifdef DRAM_VERIFY
+ PRINT_CYCLE=1;
+ printf("\tPRE BK:%d Row:%03x \n", j,dm->bk[j]->curr_row);
+ //printf("\tRASc: %d \n", dm->bk[j]->RASc);
+#endif
+ }
+ } else {
+ if (!dm->CCDc && !dm->RRDc && !dm->RTWc && !dm->WTRc && !dm->bk[j]->RCDc && !dm->bk[j]->RASc
+ && !dm->bk[j]->RCc && !dm->bk[j]->RPc && !dm->bk[j]->RCDWRc) k--;
+ dm->bk[i]->n_idle++;
+ }
+ }
+ if (!issued) {
+ dm->n_nop++;
+ dm->n_nop_partial++;
+#ifdef DRAM_VIEWCMD
+ printf("\tNOP ");
+#endif
+ }
+ if (k) {
+ dm->n_activity++;
+ dm->n_activity_partial++;
+ }
+ dm->n_cmd++;
+ dm->n_cmd_partial++;
+
+ // decrements counters once for each time dram_issueCMD is called
+ DEC2ZERO(dm->RRDc);
+ DEC2ZERO(dm->CCDc);
+ DEC2ZERO(dm->RTWc);
+ DEC2ZERO(dm->WTRc);
+ for (j=0;j<dm->nbk;j++) {
+ DEC2ZERO(dm->bk[j]->RCDc);
+ DEC2ZERO(dm->bk[j]->RASc);
+ DEC2ZERO(dm->bk[j]->RCc);
+ DEC2ZERO(dm->bk[j]->RPc);
+ DEC2ZERO(dm->bk[j]->RCDWRc);
+ }
+
+#ifdef DRAM_VISUALIZE
+ dram_visualize(dm);
+#endif
+}
+
+//if mrq is being serviced by dram, gets popped after CL latency fulfilled
+void* dram_pop( dram_t *dm )
+{
+ dram_req_t *mrq;
+ void *data;
+ unsigned dq_latency;
+
+ data = NULL;
+ mrq = (dram_req_t*)dq_pop(dm->rwq);
+ if (mrq) {
+ // data = mrq->data;
+#ifdef DRAM_VIEWCMD
+ printf("\tDQ: BK%d Row:%03x Col:%03x",
+ mrq->bk, mrq->row, mrq->col + mrq->dqbytes);
+#endif
+ mrq->dqbytes += dm->BL * dm->busW * gpu_n_mem_per_ctrlr; /*16 bytes*/
+ if (mrq->dqbytes >= mrq->nbytes) {
+
+ if (gpgpu_memlatency_stat) {
+ dq_latency = gpu_sim_cycle + gpu_tot_sim_cycle - mrq->timestamp;
+ dq_lat_table[LOGB2(dq_latency)]++;
+ if (dq_latency > max_dq_latency)
+ max_dq_latency = dq_latency;
+ }
+ data = mrq->data;
+
+ free(mrq);
+ }
+ }
+#ifdef DRAM_VIEWCMD
+ printf("\n");
+#endif
+
+ return data;
+}
+
+// a hack to allow peeking into what memory request will be serviced.
+void* dram_top( dram_t *dm )
+{
+ dram_req_t *mrq;
+ void *data;
+
+ data = NULL;
+ mrq = (dram_req_t*)dq_top(dm->rwq);
+ if (mrq) {
+ // number of bytes returned from dram if this is ever popped
+ unsigned tobe_dqbytes = mrq->dqbytes + dm->BL * dm->busW * gpu_n_mem_per_ctrlr;
+ if (tobe_dqbytes >= mrq->nbytes) {
+ data = mrq->data;
+ }
+ }
+
+ return data;
+}
+
+void dram_print( dram_t* dm, FILE* simFile)
+{
+ unsigned i;
+ fprintf(simFile,"DRAM[%d]: %d bks, busW=%d BL=%d CL=%d, ",
+ dm->id, dm->nbk, dm->busW, dm->BL, dm->CL );
+ fprintf(simFile,"tRRD=%d tCCD=%d, tRCD=%d tRAS=%d tRP=%d tRC=%d\n",
+ dm->tCCD, dm->tRRD, dm->tRCD, dm->tRAS, dm->tRP, dm->tRC );
+ fprintf(simFile,"n_cmd=%d n_nop=%d n_act=%d n_pre=%d n_req=%d n_rd=%d n_write=%d bw_util=%.4g\n",
+ dm->n_cmd, dm->n_nop, dm->n_act, dm->n_pre, dm->n_req, dm->n_rd, dm->n_wr,
+ (float)dm->bwutil/dm->n_cmd);
+ fprintf(simFile,"n_activity=%d dram_eff=%.4g\n",
+ dm->n_activity, (float)dm->bwutil/dm->n_activity);
+ for (i=0;i<dm->nbk;i++) {
+ fprintf(simFile, "bk%d: %da %di ",i,dm->bk[i]->n_access,dm->bk[i]->n_idle);
+ }
+ fprintf(simFile, "\n");
+ fprintf(simFile, "dram_util_bins:");
+ for (i=0;i<10;i++) fprintf(simFile, " %d", dm->dram_util_bins[i]);
+ fprintf(simFile, "\ndram_eff_bins:");
+ for (i=0;i<10;i++) fprintf(simFile, " %d", dm->dram_eff_bins[i]);
+ fprintf(simFile, "\n");
+ /*
+ {
+ delay_data* mrq;
+ mrq = dm->mrqq->head;
+ while (mrq) {
+ printf("%d",((dram_req_t*)mrq->data)->bk);
+ mrq = mrq->next;
+ }
+ printf("\n");
+ }
+ */
+ fprintf(simFile, "mrqq: max=%d avg=%g\n", dm->max_mrqs, (float)dm->ave_mrqs/dm->n_cmd);
+}
+
+void dram_visualize( dram_t* dm )
+{
+ unsigned i;
+
+ printf("RRDc=%d CCDc=%d mrqq.Length=%d rwq.Length=%d\n",
+ dm->RRDc, dm->CCDc, dm->mrqq->length,dm->rwq->length);
+ for (i=0;i<dm->nbk;i++) {
+ printf("BK%d: state=%c curr_row=%03x, %2d %2d %2d %2d %p ",
+ i, dm->bk[i]->state, dm->bk[i]->curr_row,
+ dm->bk[i]->RCDc, dm->bk[i]->RASc,
+ dm->bk[i]->RPc, dm->bk[i]->RCc,
+ dm->bk[i]->mrq );
+ if (dm->bk[i]->mrq)
+ printf("txf: %d %d", dm->bk[i]->mrq->nbytes, dm->bk[i]->mrq->txbytes);
+ printf("\n");
+ }
+ if ( dm->m_fast_ideal_scheduler ) {
+ dump_fast_ideal_scheduler( dm );
+ }
+
+}
+
+void dram_print_stat( dram_t* dm, FILE* simFile )
+{
+ int i;
+ fprintf(simFile,"DRAM (%d): n_cmd=%d n_nop=%d n_act=%d n_pre=%d n_req=%d n_rd=%d n_write=%d bw_util=%.4g ",
+ dm->id, dm->n_cmd, dm->n_nop, dm->n_act, dm->n_pre, dm->n_req, dm->n_rd, dm->n_wr,
+ (float)dm->bwutil/dm->n_cmd);
+ fprintf(simFile, "mrqq: %d %.4g mrqsmax=%d ", dm->max_mrqs, (float)dm->ave_mrqs/dm->n_cmd, dm->max_mrqs_temp);
+ fprintf(simFile, "\n");
+ fprintf(simFile, "dram_util_bins:");
+ for (i=0;i<10;i++) fprintf(simFile, " %d", dm->dram_util_bins[i]);
+ fprintf(simFile, "\ndram_eff_bins:");
+ for (i=0;i<10;i++) fprintf(simFile, " %d", dm->dram_eff_bins[i]);
+ fprintf(simFile, "\n");
+ dm->max_mrqs_temp = 0;
+}
+
+
+unsigned dram_busy( dram_t* dm)
+{
+ unsigned busy = 0;
+
+ switch (dm->scheduler_type) {
+ case DRAM_FIFO:
+ busy = (dm->mrqq->length > 0);
+ break;
+ case DRAM_IDEAL_FAST:
+ busy = (fast_scheduler_queue_length(dm) > 0) || (dm->mrqq->length > 0);
+ break;
+ }
+
+ return busy;
+}
+