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); }
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; }
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; }
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; }
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; }