Exemplo n.º 1
0
NVMainMemory::NVMainMemory(std::string& nvmainTechIni, std::string& outputFile, std::string& traceName, uint32_t capacityMB, uint64_t _minLatency, uint32_t _domain, const g_string& _name , std::string fetcher_name) {
    nvmainConfig = new NVM::Config();
	mm = NULL;
    nvmainConfig->Read(nvmainTechIni);
    info("NVMainControl: Reading NVMain config file: %s", nvmainTechIni.c_str());
	std::string mem_type = "NVMain";
	if( nvmainConfig->KeyExists("CMemType"))
		mem_type = nvmainConfig->GetString("CMemType");
	nvmainPtr = NVM::NVMainFactory::CreateNewNVMain(mem_type);
    nvmainStatsPtr = new NVM::Stats();
    nvmainSimInterface = new NVM::NullInterface();
    nvmainEventQueue = new NVM::EventQueue();
    nvmainGlobalEventQueue = new NVM::GlobalEventQueue();
    nvmainTagGenerator = new NVM::TagGenerator(1000);

    nvmainConfig->SetSimInterface(nvmainSimInterface);

    SetEventQueue(nvmainEventQueue);
    SetStats(nvmainStatsPtr);
    SetTagGenerator(nvmainTagGenerator);
    nvmainGlobalEventQueue->SetFrequency(nvmainConfig->GetEnergy("CPUFreq") * 1000000.0);
    SetGlobalEventQueue(nvmainGlobalEventQueue);

    /*  Add any specified hooks */
    std::vector<std::string>& hookList = nvmainConfig->GetHooks();
	previous_caching = 0;
	bool migrator_setted = false;
    for(size_t i = 0; i < hookList.size(); i++) {

        NVMObject *hook = NVM::HookFactory::CreateHook(hookList[i]);
        if( hook != NULL ) {
			AddHook(hook);
            hook->SetParent( this );
			std::cout<<"this:"<<this<<std::endl;
			std::cout<<"nvmainPtr:"<<nvmainPtr<<std::endl;
            hook->Init( nvmainConfig );
        } else {
            warn("Could not create a hook");
        }
		if( mem_type == "RBLANVMain" &&
			!migrator_setted && 
			hookList[i].find("Migrator")!=std::string::npos)
		{
			nvmainPtr->SetMigrator(hook);
			migrator_setted = true;
			//add migrator to nvmain
		}
	}
    //Setup child and parent modules
    AddChild(nvmainPtr);
    nvmainPtr->SetParent(this);
    nvmainGlobalEventQueue->AddSystem(nvmainPtr, nvmainConfig);
    nvmainPtr->SetConfig(nvmainConfig);
	if( mem_type == "FineNVMain"  )
	{
		mm = dynamic_cast<NVM::FineNVMain*>(nvmainPtr);
		//DRAM buffer fetcher related
		if( (mm->reserved_channels) > 0 )
		{
			fetcher = NVM::FetcherFactory::CreateFetcher(fetcher_name);
			debug_printf("set fetcher parent");
			fetcher->SetParent( nvmainPtr );
			nvmainPtr->AddChild(fetcher);
			fetcher->Init( nvmainConfig);
			mm->SetBlockFetcher(fetcher);
			//basic information about dram buffer and main memory
			zinfo->buffer_size = nvmainPtr->GetBufferSize();
			unsigned mem_width = nvmainPtr->GetMemoryWidth(); 
			zinfo->high_addr = (Address)1<<mem_width;
			//get delta time information for dynamically threshold adjustment
			mm->GetDeltaCycles( delta_hit_t,
								delta_clean_miss_t , delta_dirty_miss_t);
			debug_printf("nvmain_buffer size is : %llx",zinfo->buffer_size);
			debug_printf("base addr of nvmain dram buffer: %llx",zinfo->high_addr);
			debug_printf("width of main memory: %d",nvmainPtr->GetMemoryWidth());
		}
	}
	else
	{
		fetcher=NULL;
		zinfo->buffer_size = 0;
		zinfo->high_addr = 0;
		delta_hit_t = delta_clean_miss_t = delta_dirty_miss_t = 0;
	}
	/***-----get memory size------***/
	zinfo->memory_size = nvmainPtr->GetMemorySize();
    curCycle = 0;
    updateCycle = 0;
	nvmain_access_count = 0;
	nvmain_read_access_count = 0;
	nvmain_write_access_count = 0;
	prefetch_time = 0;
	last_memory_access = 0;
	last_memory_access_cycle=0;
    double cpuFreq = static_cast<double>(nvmainConfig->GetEnergy("CPUFreq"));
    double busFreq = static_cast<double>(nvmainConfig->GetEnergy("CLK"));
    eventDriven = static_cast<bool>(nvmainConfig->GetBool("EventDriven"));
    info("NVMain: with %f cpuFreq, %f busFreq", cpuFreq, busFreq);
    minLatency = _minLatency;
    domain = _domain;

    // No longer necessary, now we do not tick every cycle, we use SchedEvent

    name = _name;
    // Data
    if( nvmainConfig->KeyExists( "IgnoreData" ) && nvmainConfig->GetString( "IgnoreData" ) == "true" ) {
        ignoreData = true;
    } else {
        ignoreData = false;
    }

    // NVMain stats output file
    std::string path = zinfo->outputDir;
    path += "/";
    nvmainStatsFile = gm_strdup((path + name.c_str() + "-" + outputFile).c_str());
    std::ofstream out(nvmainStatsFile, std::ios_base::out);
    out << "# nvmain stats for " << name << std::endl;
    out << "===" << std::endl;

    // Wave phase handling
    nextSchedRequest = NULL;
    nextSchedEvent = NULL;
    eventFreelist = NULL;
	e = 2.718;
	T = 2000;
	N = 999;
	srand((unsigned)time(NULL));
	lastCycle = 0;
	previous_action = InitZero;
	previous_benefit = 0;

	if( zinfo->proc_fairness == false)
	{
		period_touch_vec.resize(1);
		period_nvm_touch.resize(1);
		period_access_vec.resize(1,0);
		period_nvm_access.resize(1,0);
		last_period_hotness.resize(1,0.0);
		last_action.resize(1,-1);
	}
	else
	{
		period_touch_vec.resize(zinfo->numProcs);
		period_nvm_touch.resize(zinfo->numProcs);
		period_access_vec.resize(zinfo->numProcs,0);	
		period_nvm_access.resize(zinfo->numProcs,0);
		last_period_hotness.resize(zinfo->numProcs,0.0);
		last_action.resize(zinfo->numProcs,-1);
	}
	for( unsigned i=0; i< period_touch_vec.size(); i++ )
	{
		g_map<Address, Address> tmp;
		g_map<Address, Address> tmp2;
		period_touch_vec[i] = tmp;
		period_nvm_touch[i] = tmp2;
	}
	fdrc.open("dram.log");
	fnvm.open("nvm.log");
	futex_init(&access_lock);
}
Exemplo n.º 2
0
bool CommonMigrator::TryMigration( NVMainRequest *request, bool atomic )
{
	begin_cycle_ = GetEventQueue()->GetCurrentCycle();

    bool rv = true;
	//translate this object to NVMain type
	 if( NVMTypeMatches(NVMain) )
     {
        /* Ensure the Migrator translator is used. */
		//parent module is who issue migration??
        Migrator *migratorTranslator = dynamic_cast<Migrator *>(parent->GetTrampoline( )->GetDecoder( ));
        assert( migratorTranslator != NULL );

        /* Migrations in progress must be served from the buffers during migration. */
        if( GetCurrentHookType( ) == NVMHOOK_PREISSUE && migratorTranslator->IsBuffered( request->address ) )
        {
            /* Short circuit this request so it is not queued. */
            rv = false;

            /* Complete the request, adding some buffer read latency. */
            GetEventQueue( )->InsertEvent( EventResponse, parent->GetTrampoline( ), request,
                              GetEventQueue()->GetCurrentCycle()+bufferReadLatency );

            bufferedReads++;

            return rv;
        }

        /* Don't inject results before the original is issued to prevent deadlock */
        if( GetCurrentHookType( ) != NVMHOOK_POSTISSUE )
        {
            return rv;
        }

        /* See if any migration is possible (i.e., no migration is in progress) */
        bool migrationPossible = false;

        if( !migratorTranslator->Migrating( ) 
            && !migratorTranslator->IsMigrated( request->address ) 
            && request->address.GetChannel( ) != promotionChannel )
        {
                migrationPossible = true;
        }
        if( migrationPossible )
        {
            assert( !demoBuffered && !promoBuffered );
            /* 
             *  Note: once IssueCommand is called, this hook may receive
             *  a different parent, but fail the NVMTypeMatch check. As a
             *  result we need to save a pointer to the NVMain class we
             *  are issuing requests to.
             */
            NVMObject *savedParent = parent->GetTrampoline( );

            /* Discard the unused column address. */
            uint64_t row, bank, rank, channel, subarray;
            request->address.GetTranslatedAddress( &row, NULL, &bank, &rank, &channel, &subarray );
            uint64_t promoteeAddress = migratorTranslator->ReverseTranslate( row, 0, bank, rank, channel, subarray ); 

            promotee.SetPhysicalAddress( promoteeAddress );
            promotee.SetTranslatedAddress( row, 0, bank, rank, channel, subarray );

            /* Pick a victim to replace. */
            ChooseVictim( migratorTranslator, promotee, demotee );
            assert( migratorTranslator->IsMigrated( demotee ) == false );
            assert( migratorTranslator->IsMigrated( promotee ) == false );

             if( atomic )
             {
                    migratorTranslator->StartMigration( request->address, demotee );
                    migratorTranslator->SetMigrationState( promotee, MIGRATION_DONE );
                    migratorTranslator->SetMigrationState( demotee, MIGRATION_DONE );
             }
                /* Lastly, make sure we can queue the migration requests. */
             else if( CheckIssuable( promotee, READ ) &&
                         CheckIssuable( demotee, READ ) )
             {
                    migratorTranslator->StartMigration( request->address, demotee );

                    promoRequest = new NVMainRequest( ); 
                    demoRequest = new NVMainRequest( );
					
                    promoRequest->address = promotee;
                    promoRequest->type = READ;
                    promoRequest->tag = MIG_READ_TAG;
                    promoRequest->burstCount = numCols;

                    demoRequest->address = demotee;
                    demoRequest->type = READ;
                    demoRequest->tag = MIG_READ_TAG;
                    demoRequest->burstCount = numCols;
                    
					promoRequest->owner = savedParent;
                    demoRequest->owner = savedParent;
                    savedParent->IssueCommand( promoRequest );
                    savedParent->IssueCommand( demoRequest );
             }
             else
            {
                queueWaits++;
            }
        }
	 }

    return rv;
}
Exemplo n.º 3
0
bool CommonMigrator::RequestComplete( NVMainRequest *request )
{
    if( NVMTypeMatches(NVMain) && GetCurrentHookType( ) == NVMHOOK_PREISSUE )
    {
        /* Ensure the Migrator translator is used. */
        Migrator *migratorTranslator = dynamic_cast<Migrator *>(parent->GetTrampoline( )->GetDecoder( ));
        assert( migratorTranslator != NULL );
        if( request->owner == parent->GetTrampoline( ) && request->tag == MIG_READ_TAG )
        {
            /* A migration read completed, update state. */
            migratorTranslator->SetMigrationState( request->address, MIGRATION_BUFFERED ); 

            /* If both requests are buffered, we can attempt to write. */
            bool bufferComplete = false;

            if( (request == promoRequest 
                 && migratorTranslator->IsBuffered( demotee ))
                || (request == demoRequest
                 && migratorTranslator->IsBuffered( promotee )) )
            {
                bufferComplete = true;
            }
            /* Make a new request to issue for write. Parent will delete current pointer. */
            if( request == promoRequest )
            {
                promoRequest = new NVMainRequest( );
                *promoRequest = *request;
            }
            else if( request == demoRequest )
            {
                demoRequest = new NVMainRequest( );
                *demoRequest = *request;
            }
            else
            {
                assert( false );
            }

            /* Swap the address and set type to write. */
            if( bufferComplete )
            {
                /* 
                 *  Note: once IssueCommand is called, this hook may receive
                 *  a different parent, but fail the NVMTypeMatch check. As a
                 *  result we need to save a pointer to the NVMain class we
                 *  are issuing requests to.
                 */
                NVMObject *savedParent = parent->GetTrampoline( );

                NVMAddress tempAddress = promoRequest->address;
                promoRequest->address = demoRequest->address;
                demoRequest->address = tempAddress;

                demoRequest->type = WRITE;
                promoRequest->type = WRITE;

                demoRequest->tag = MIG_WRITE_TAG;
                promoRequest->tag = MIG_WRITE_TAG;

                /* Try to issue these now, otherwise we can try later. */
                bool demoIssued, promoIssued;

                demoIssued = savedParent->GetChild( demoRequest )->IssueCommand( demoRequest );
                promoIssued = savedParent->GetChild( promoRequest )->IssueCommand( promoRequest );

                if( demoIssued )
                {
                    migratorTranslator->SetMigrationState( demoRequest->address, MIGRATION_WRITING );
                }
                if( promoIssued )
                {
                    migratorTranslator->SetMigrationState( promoRequest->address, MIGRATION_WRITING );
                }
                promoBuffered = !promoIssued;
                demoBuffered = !demoIssued;
            }
        }
        /* A write completed. */
        else if( request->owner == parent->GetTrampoline( ) && request->tag == MIG_WRITE_TAG )
        {
            // Note: request should be deleted by parent
            migratorTranslator->SetMigrationState( request->address, MIGRATION_DONE );
            migrationCount++;
			migration_cycles_ += GetEventQueue()->GetCurrentCycle() - begin_cycle_;
        }

        /* Some other request completed, see if we can ninja issue some migration writes that did not queue. */
        else if( promoBuffered || demoBuffered )
        {
            bool demoIssued, promoIssued;

            if( promoBuffered )
            {
                promoIssued = parent->GetTrampoline( )->GetChild( promoRequest )->IssueCommand( promoRequest );
                promoBuffered = !promoIssued;
            }

            if( demoBuffered )
            {
                demoIssued = parent->GetTrampoline( )->GetChild( demoRequest )->IssueCommand( demoRequest );
                demoBuffered = !demoIssued;
            }
        }
    }
    return true;
}
Exemplo n.º 4
0
bool MultiQueueMigrator::TryMigration( NVMainRequest *request, bool atomic )
{
//	std::cout<<"\nMultiQueueMigrator::TryMigration ---- addr: "<<std::hex<<request->address.GetPhysicalAddress()<<"\n"<<std::endl;
    bool rv = true;
    if( NVMTypeMatches(NVMain) )
    {
		//std::cout<<"migration:"<<std::endl;
        /* Ensure the Migrator translator is used. */
       MQMigrator *migratorTranslator = dynamic_cast<MQMigrator *>(parent->GetTrampoline( )->GetDecoder( ));
        assert( migratorTranslator != NULL );

        /* Migrations in progress must be served from the buffers during migration. */
        if( GetCurrentHookType( ) == NVMHOOK_PREISSUE && migratorTranslator->IsBuffered( request->address ) )
        {
            /* Short circuit this request so it is not queued. */
            rv = false;

            /* Complete the request, adding some buffer read latency. */
            GetEventQueue( )->InsertEvent( EventResponse, parent->GetTrampoline( ), request,
                              GetEventQueue()->GetCurrentCycle()+bufferReadLatency );

            bufferedReads++;

            return rv;
        }

        /* Don't inject results before the original is issued to prevent deadlock */
        if( GetCurrentHookType( ) != NVMHOOK_POSTISSUE )
        {
            return rv;
        }
		
		currentTime++; 
		
		if( !request->address.IsTranslated( ) )
		{
			uint64_t row, col, bank, rank, channel, subarray;
		     migratorTranslator->Translate(request, &row, &col,
					 &bank,&rank, &channel, &subarray);
			 request->address.SetTranslatedAddress( row, col, bank, rank, channel, subarray);
		}
		//***********************traces start
		uint64_t pageNo = migratorTranslator->GetAddressKey(request->address);
 		uint64_t channelNo = request->address.GetChannel();
		//std::cout<<"request:"<<std::hex<<request->address.GetPhysicalAddress()<<" channel:"<<request->address.GetChannel()<<std::endl;
		/*
		if (GetEventQueue()->GetCurrentCycle()%trace_interval==0 )
		{
			for( uint64_t i=0 ; i<channel_num ; i++)
			{
				file<<migratorTranslator->migrate_access_times[i]<<"   ";
				origin_file<< migratorTranslator->access_times[i]<<"   ";
			}
			file<<std::endl;
			origin_file<<std::endl;
		}*/
		//***********************traces end
	
		//this request is issued to access dram memory
		if( channelNo == promotionChannel && !IsInList(DRAMPageList, pageNo) )
		{
			DRAMPageList.push_back(pageNo);
		}       
		//get ranking queue num for the request
		int location = LocateQueue(pageNo);
	
		if( location == -1 )
		{
			PageType page = { pageNo, 1, currentTime + LIFE_TIME, channelNo };
			//insert the request to queue[0] (LRU)
 			JoinQueue(page);	
		}	
		else
		{
			AccessPage(location, pageNo);	
		}	

		Display();

        /* See if any migration is possible (i.e., no migration is in progress) */
        bool migrationPossible = false;

        if( !migratorTranslator->Migrating( ) 
            && !migratorTranslator->IsMigrated( request->address )
			&& channelNo != promotionChannel )
        {
                migrationPossible = true;
        }
		else if(migratorTranslator->Migrating( ))
		{	
			//std::cout<<"\nPossible?  ------ No ------ 1\n"<<std::endl;
		}
		else if(migratorTranslator->IsMigrated( request->address ))
		{	
			//std::cout<<"\nPossible?  ------ No ------ 2\n"<<std::endl;
		}
		else if(channelNo == promotionChannel)
		{	
			//std::cout<<"\nPossible?  ------ No ------ 3\n"<<std::endl;
		}

		//std::cout<<"migration possible:"<<migrationPossible<<std::endl;
        if( migrationPossible )
        {
			//std::cout<<"\n Possible?   ----    Yes!\n"<<std::endl;
            assert( !demoBuffered && !promoBuffered );
			//std::cout<<"location is:"<<location<<std::endl;
            if( location == THRESHOLD_QUEUE && !migratorTranslator->IsMigrated( request->address ))
            {
				//std::cout<<"\n Migrate?   ----    Yes!\n"<<std::endl;
                /* 
                 *  Note: once IssueCommand is called, this hook may receive
                 *  a different parent, but fail the NVMTypeMatch check. As a
                 *  result we need to save a pointer to the NVMain class we
                 *  are issuing requests to.
                 */
                NVMObject *savedParent = parent->GetTrampoline( );
                //NVMObject *savedParent = main_mem;

                /* Discard the unused column address. */
                uint64_t row, bank, rank, channel, subarray;
                request->address.GetTranslatedAddress( &row, NULL, &bank, &rank, &channel, &subarray );
                uint64_t promoteeAddress = migratorTranslator->ReverseTranslate( row, 0, bank, rank, channel, subarray ); 

                promotee.SetPhysicalAddress( promoteeAddress );
                promotee.SetTranslatedAddress( row, 0, bank, rank, channel, subarray );

                /* Pick a victim to replace. */
                ChooseVictim( migratorTranslator, promotee, demotee );

                assert( migratorTranslator->IsMigrated( demotee ) == false );
                assert( migratorTranslator->IsMigrated( promotee ) == false );

                if( atomic )
                {
                    migratorTranslator->StartMigration( request->address, demotee );
                    migratorTranslator->SetMigrationState( promotee, MQ_MIGRATION_DONE );
                    migratorTranslator->SetMigrationState( demotee, MQ_MIGRATION_DONE );
                }
                /* Lastly, make sure we can queue the migration requests. */
                else if( CheckIssuable( promotee, READ ) &&
                         CheckIssuable( demotee, READ ) )
                {
                    migratorTranslator->StartMigration( request->address, demotee );

                    promoRequest = new NVMainRequest( ); 
                    demoRequest = new NVMainRequest( );

                    promoRequest->address = promotee;
                    promoRequest->type = READ;
                    promoRequest->tag = MIG_READ_TAG;
                    promoRequest->burstCount = numCols;

                    demoRequest->address = demotee;
                    demoRequest->type = READ;
                    demoRequest->tag = MIG_READ_TAG;
                    demoRequest->burstCount = numCols;

                    promoRequest->owner = savedParent;
                    demoRequest->owner = savedParent;
                    savedParent->IssueCommand( promoRequest );
                    savedParent->IssueCommand( demoRequest );
                }
                else
                {
                    queueWaits++;
                }
            }
        }

		CheckQueue();
    }

    return rv;
}
Exemplo n.º 5
0
bool MultiQueueMigrator::RequestComplete( NVMainRequest *request )
{
//	std::cout<<"\nMultiQueueMigrator   -----  RequestComplete: "<<std::hex
  //                     <<request->address.GetPhysicalAddress()<<"  FFFFFFFF\n"<<std::endl;
    if( NVMTypeMatches(NVMain) && GetCurrentHookType( ) == NVMHOOK_PREISSUE )
    {
	//	std::cout<<"\nRequestComplete: If?  ---  Yes! FFFFFFFF \n "<<std::endl;
        /* Ensure the Migrator translator is used. */
        MQMigrator *migratorTranslator = dynamic_cast<MQMigrator *>(parent->GetTrampoline( )->GetDecoder( ));
        assert( migratorTranslator != NULL );

        if( request->owner == parent->GetTrampoline( ) && request->tag == MIG_READ_TAG )
        {
            /* A migration read completed, update state. */
			//std::cout<<"set migration state to MQ_MIGRATION_BUFFERED"<<std::endl;
            migratorTranslator->SetMigrationState( request->address, MQ_MIGRATION_BUFFERED ); 

            /* If both requests are buffered, we can attempt to write. */
            bool bufferComplete = false;

            if( (request == promoRequest 
                 && migratorTranslator->IsBuffered( demotee ))
                || (request == demoRequest
                 && migratorTranslator->IsBuffered( promotee )) )
            {
                bufferComplete = true;
            }

            /* Make a new request to issue for write. Parent will delete current pointer. */
            if( request == promoRequest )
            {
                promoRequest = new NVMainRequest( );
                *promoRequest = *request;
            }
            else if( request == demoRequest )
            {
                demoRequest = new NVMainRequest( );
                *demoRequest = *request;
            }
            else
            {
                assert( false );
            }

            /* Swap the address and set type to write. */
            if( bufferComplete )
            {
                /* 
                 *  Note: once IssueCommand is called, this hook may receive
                 *  a different parent, but fail the NVMTypeMatch check. As a
                 *  result we need to save a pointer to the NVMain class we
                 *  are issuing requests to.
                 */
			//	std::cout<<"\nBoth_Buffer_Complete == true. FFFFFFFF\n"<<std::endl;
                NVMObject *savedParent = parent->GetTrampoline( );

                NVMAddress tempAddress = promoRequest->address;
                promoRequest->address = demoRequest->address;
                demoRequest->address = tempAddress;

                demoRequest->type = WRITE;
                promoRequest->type = WRITE;

                demoRequest->tag = MIG_WRITE_TAG;
                promoRequest->tag = MIG_WRITE_TAG;

                /* Try to issue these now, otherwise we can try later. */
                bool demoIssued, promoIssued;

                demoIssued = savedParent->GetChild( demoRequest )->IssueCommand( demoRequest );
                promoIssued = savedParent->GetChild( promoRequest )->IssueCommand( promoRequest );

                if( demoIssued )
                {
					//std::cout<<"set migration state to MQ_MIGRATION_WRITING"<<std::endl;
                    migratorTranslator->SetMigrationState( demoRequest->address, MQ_MIGRATION_WRITING );
                }
                if( promoIssued )
                {
				//	std::cout<<"\npromo_Mig_Write Issued: "<<std::hex
                //                   <<promoRequest->address.GetPhysicalAddress()<<"\n"<<std::endl;
					//std::cout<<"set migration state to MQ_MIGRATION_WRITING"<<std::endl;
                    migratorTranslator->SetMigrationState( promoRequest->address, MQ_MIGRATION_WRITING );
                }

                promoBuffered = !promoIssued;
                demoBuffered = !demoIssued;
            }
        }
        /* A write completed. */
        else if( request->owner == parent->GetTrampoline( ) && request->tag == MIG_WRITE_TAG )
        {
            // Note: request should be deleted by parent
			//std::cout<<"set migration state to MQ_MIGRATION_DONE"<<std::endl;
            migratorTranslator->SetMigrationState( request->address, MQ_MIGRATION_DONE );

            if( request == promoRequest )
            {
			//	std::cout<<"\n######  promo_Mig_Done. FFFFFFFF\n"<<std::endl;
            }
            else if( request == demoRequest )
            {
			//	std::cout<<"\n######  demo_Mig_Done. FFFFFFFF\n"<<std::endl;
            }
            migrationCount++;
            
			if( (request == promoRequest 
                 && migratorTranslator->IsMigrated( demotee ))
                || (request == demoRequest
                 && migratorTranslator->IsMigrated( promotee )) )
            {
               // std::cout<<"\nBoth migrations are done.\n"<<std::endl;
				
            }
        }
        /* Some other request completed, see if we can ninja issue some migration writes that did not queue. */
        else if( promoBuffered || demoBuffered )
        {
            bool demoIssued, promoIssued;

            if( promoBuffered )
            {
                promoIssued = parent->GetTrampoline( )->GetChild( promoRequest )->IssueCommand( promoRequest );
                promoBuffered = !promoIssued;
            }

            if( demoBuffered )
            {
                demoIssued = parent->GetTrampoline( )->GetChild( demoRequest )->IssueCommand( demoRequest );
                demoBuffered = !demoIssued;
            }
        }
    }

    return true;
}
int TraceMain::RunTrace( int argc, char *argv[] )
{
    Stats *stats = new Stats( );
    Config *config = new Config( );
    GenericTraceReader *trace = NULL;
    TraceLine *tl = new TraceLine( );
    SimInterface *simInterface = new NullInterface( );
    NVMain *nvmain = new NVMain( );
    EventQueue *mainEventQueue = new EventQueue( );
    GlobalEventQueue *globalEventQueue = new GlobalEventQueue( );
    TagGenerator *tagGenerator = new TagGenerator( 1000 );
    bool IgnoreData = false;
    bool EventDriven = false;

    uint64_t simulateCycles;
    uint64_t currentCycle;
    
    if( argc < 4 )
    {
        std::cout << "Usage: nvmain CONFIG_FILE TRACE_FILE CYCLES [PARAM=value ...]" 
            << std::endl;
        return 1;
    }

    /* Print out the command line that was provided. */
    std::cout << "NVMain command line is:" << std::endl;
    for( int curArg = 0; curArg < argc; ++curArg )
    {
        std::cout << argv[curArg] << " ";
    }
    std::cout << std::endl << std::endl;

    config->Read( argv[1] );
    config->SetSimInterface( simInterface );
    SetEventQueue( mainEventQueue );
    SetGlobalEventQueue( globalEventQueue );
    SetStats( stats );
    SetTagGenerator( tagGenerator );
    std::ofstream statStream;

    /* Allow for overriding config parameter values for trace simulations from command line. */
    if( argc > 4 )
    {
        for( int curArg = 4; curArg < argc; ++curArg )
        {
            std::string clParam, clValue, clPair;
            
            clPair = argv[curArg];
            clParam = clPair.substr( 0, clPair.find_first_of("="));
            clValue = clPair.substr( clPair.find_first_of("=") + 1, std::string::npos );

            std::cout << "Overriding " << clParam << " with '" << clValue << "'" << std::endl;

            config->SetValue( clParam, clValue );
        }
    }

    if( config->KeyExists( "StatsFile" ) )
    {
        statStream.open( config->GetString( "StatsFile" ).c_str(), 
                         std::ofstream::out | std::ofstream::app );
    }

    if( config->KeyExists( "IgnoreData" ) && config->GetString( "IgnoreData" ) == "true" )
    {
        IgnoreData = true;
    }

    config->GetBool( "EventDriven", EventDriven );

    /*  Add any specified hooks */
    std::vector<std::string>& hookList = config->GetHooks( );

    for( size_t i = 0; i < hookList.size( ); i++ )
    {
        std::cout << "Creating hook " << hookList[i] << std::endl;

        NVMObject *hook = HookFactory::CreateHook( hookList[i] );
        
        if( hook != NULL )
        {
            AddHook( hook );
            hook->SetParent( this );
            hook->Init( config );
        }
        else
        {
            std::cout << "Warning: Could not create a hook named `" 
                << hookList[i] << "'." << std::endl;
        }
    }

    AddChild( nvmain );
    nvmain->SetParent( this );

    globalEventQueue->SetFrequency( config->GetEnergy( "CPUFreq" ) * 1000000.0 );
    globalEventQueue->AddSystem( nvmain, config );

    simInterface->SetConfig( config, true );
    nvmain->SetConfig( config, "defaultMemory", true );

    std::cout << "traceMain (" << (void*)(this) << ")" << std::endl;
    nvmain->PrintHierarchy( );

    if( config->KeyExists( "TraceReader" ) )
        trace = TraceReaderFactory::CreateNewTraceReader( 
                config->GetString( "TraceReader" ) );
    else
        trace = TraceReaderFactory::CreateNewTraceReader( "NVMainTrace" );

    trace->SetTraceFile( argv[2] );

    if( argc == 3 )
        simulateCycles = 0;
    else
        simulateCycles = atoi( argv[3] );

    std::cout << "*** Simulating " << simulateCycles << " input cycles. (";

    /*
     *  The trace cycle is assumed to be the rate that the CPU/LLC is issuing. 
     *  Scale the simulation cycles to be the number of *memory cycles* to run.
     */
    simulateCycles = (uint64_t)ceil( ((double)(config->GetValue( "CPUFreq" )) 
                    / (double)(config->GetValue( "CLK" ))) * simulateCycles ); 

    std::cout << simulateCycles << " memory cycles) ***" << std::endl;

    currentCycle = 0;
    while( currentCycle <= simulateCycles || simulateCycles == 0 )
    {
        if( !trace->GetNextAccess( tl ) )
        {
            /* Force all modules to drain requests. */
            bool draining = Drain( );

            std::cout << "Could not read next line from trace file!" 
                << std::endl;

            /* Wait for requests to drain. */
            while( outstandingRequests > 0 )
            {
                if( EventDriven )
                    globalEventQueue->Cycle( 1 );
                else 
                    GetChild( )->Cycle( 1 );
              
                currentCycle++;

                /* Retry drain each cycle if it failed. */
                if( !draining )
                    draining = Drain( );
            }

            break;
        }

        NVMainRequest *request = new NVMainRequest( );
        
        request->address = tl->GetAddress( );
        request->type = tl->GetOperation( );
        request->bulkCmd = CMD_NOP;
        request->threadId = tl->GetThreadId( );
        if( !IgnoreData ) request->data = tl->GetData( );
        if( !IgnoreData ) request->oldData = tl->GetOldData( );
        request->status = MEM_REQUEST_INCOMPLETE;
        request->owner = (NVMObject *)this;
        
        /* 
         * If you want to ignore the cycles used in the trace file, just set
         * the cycle to 0. 
         */
        if( config->KeyExists( "IgnoreTraceCycle" ) 
                && config->GetString( "IgnoreTraceCycle" ) == "true" )
            tl->SetLine( tl->GetAddress( ), tl->GetOperation( ), 0, 
                         tl->GetData( ), tl->GetOldData( ), tl->GetThreadId( ) );

        if( request->type != READ && request->type != WRITE )
            std::cout << "traceMain: Unknown Operation: " << request->type 
                << std::endl;

        /* 
         * If the next operation occurs after the requested number of cycles,
         * we can quit. 
         */
        if( tl->GetCycle( ) > simulateCycles && simulateCycles != 0 )
        {
            if( EventDriven )
            {
                globalEventQueue->Cycle( simulateCycles - currentCycle );
                currentCycle += simulateCycles - currentCycle;

                break;
            }

            /* Just ride it out 'til the end. */
            while( currentCycle < simulateCycles )
            {
                GetChild( )->Cycle( 1 );
              
                currentCycle++;
            }

            break;
        }
        else
        {
            /* 
             *  If the command is in the past, it can be issued. This would 
             *  occur since the trace was probably generated with an inaccurate 
             *  memory *  simulator, so the cycles may not match up. Otherwise, 
             *  we need to wait.
             */
            if( tl->GetCycle( ) > currentCycle )
            {
                if( EventDriven )
                {
                    globalEventQueue->Cycle( tl->GetCycle() - currentCycle );
                    currentCycle = globalEventQueue->GetCurrentCycle( );
                }
                else
                {
                    /* Wait until currentCycle is the trace operation's cycle. */
                    while( currentCycle < tl->GetCycle( ) )
                    {
                        if( currentCycle >= simulateCycles && simulateCycles != 0 )
                            break;

                        GetChild( )->Cycle( 1 );

                        currentCycle++;
                    }
                }

                if( currentCycle >= simulateCycles && simulateCycles != 0 )
                    break;
            }

            /* 
             *  Wait for the memory controller to accept the next command.. 
             *  the trace reader is "stalling" until then.
             */
            while( !GetChild( )->IsIssuable( request ) )
            {
                if( currentCycle >= simulateCycles && simulateCycles != 0 )
                    break;

                if( EventDriven )
                {
                    globalEventQueue->Cycle( 1 );
                    currentCycle = globalEventQueue->GetCurrentCycle( );
                }
                else 
                {
                    GetChild( )->Cycle( 1 );
                    currentCycle++;
                }
            }

            outstandingRequests++;
            GetChild( )->IssueCommand( request );

            if( currentCycle >= simulateCycles && simulateCycles != 0 )
                break;
        }
    }       

    GetChild( )->CalculateStats( );
    std::ostream& refStream = (statStream.is_open()) ? statStream : std::cout;
    stats->PrintAll( refStream );

    std::cout << "Exiting at cycle " << currentCycle << " because simCycles " 
        << simulateCycles << " reached." << std::endl; 
    if( outstandingRequests > 0 )
        std::cout << "Note: " << outstandingRequests << " requests still in-flight."
                  << std::endl;

    delete config;
    delete stats;

    return 0;
}