265 lines
9.5 KiB
C++
265 lines
9.5 KiB
C++
/*
|
|
* Copyright (c) 2015, University of Kaiserslautern
|
|
* All rights reserved.
|
|
*
|
|
* 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 copyright holder nor the names of its
|
|
* contributors may be used to endorse or promote products derived from
|
|
* this software without specific prior written permission.
|
|
*
|
|
* 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 HOLDER
|
|
* 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.
|
|
*
|
|
* Authors:
|
|
* Janik Schlemminger
|
|
* Matthias Jung
|
|
* Eder F. Zulian
|
|
*/
|
|
|
|
#include <stdlib.h>
|
|
#include <iostream>
|
|
#include <fstream>
|
|
#include <vector>
|
|
|
|
#include "Simulation.h"
|
|
#include "../common/TlmRecorder.h"
|
|
#include "../common/DebugManager.h"
|
|
#include "../common/xmlAddressdecoder.h"
|
|
#include "../controller/core/ControllerCore.h"
|
|
#include "../controller/core/configuration/ConfigurationLoader.h"
|
|
#include "../common/Utils.h"
|
|
#include "../simulation/StlDataPlayer.h"
|
|
#include "../simulation/TemperatureController.h"
|
|
#include "../controller/Controller.h"
|
|
|
|
using namespace std;
|
|
|
|
Simulation::Simulation(sc_module_name __attribute__((unused)) name, string pathToResources, string traceName, DramSetup setup,
|
|
std::vector<Device> devices) : traceName(traceName), dramSetup(setup)
|
|
{
|
|
SC_THREAD(stop);
|
|
|
|
// XXX: The xmlAddressDecoder MUST be initialized before calling the
|
|
// ConfigurationLoader because some information from the xmlAddressDecoder
|
|
// is needed to assure the coherence of the configuration.
|
|
xmlAddressDecoder::Initialize(setup.addressmapping);
|
|
xmlAddressDecoder::getInstance().print();
|
|
|
|
ConfigurationLoader::loadMemConfig(Configuration::getInstance(), setup.memconfig);
|
|
ConfigurationLoader::loadMemSpec(Configuration::getInstance(), setup.memspec);
|
|
ConfigurationLoader::loadSimConfig(Configuration::getInstance(), setup.simconfig);
|
|
ConfigurationLoader::loadTemperatureSimConfig(Configuration::getInstance(), setup.thermalsimconfig);
|
|
|
|
instantiateModules(traceName, pathToResources, devices);
|
|
bindSockets();
|
|
setupDebugManager(traceName);
|
|
}
|
|
|
|
void Simulation::setupDebugManager(const string& traceName)
|
|
{
|
|
auto& dbg = DebugManager::getInstance();
|
|
dbg.writeToConsole = true;
|
|
dbg.writeToFile = true;
|
|
if(dbg.writeToFile)
|
|
dbg.openDebugFile(traceName + ".txt");
|
|
}
|
|
|
|
void Simulation::setupTlmRecorders(const string &traceName, const string &pathToResources, const std::vector<Device> &devices)
|
|
{
|
|
// Create TLM Recorders, one per channel.
|
|
for (size_t i = 0; i < Configuration::getInstance().NumberOfMemChannels; i++) {
|
|
std::string sqlScriptURI = pathToResources + string("scripts/createTraceDB.sql");
|
|
std::string dbName = traceName + string("_channel") + std::to_string(i) + ".tdb";
|
|
std::string recorderName = "tlmRecorder" + std::to_string(i);
|
|
TlmRecorder *tlmRecorder = new TlmRecorder(recorderName.c_str(), sqlScriptURI.c_str(), dbName.c_str(), Configuration::getInstance().DatabaseRecording);
|
|
|
|
tlmRecorder->recordMemconfig(Configuration::getInstance().memconfigUri);
|
|
tlmRecorder->recordMemspec(Configuration::getInstance().memspecUri);
|
|
|
|
tlmRecorders.push_back(tlmRecorder);
|
|
|
|
std::string traceNames;
|
|
for (size_t i = 0; i < devices.size(); i++) {
|
|
traceNames.append(devices[i].trace);
|
|
if (i == devices.size() - 1)
|
|
continue;
|
|
traceNames.append(",");
|
|
}
|
|
tlmRecorder->recordTracenames(traceNames);
|
|
}
|
|
}
|
|
|
|
void Simulation::instantiateModules(const string &traceName, const string &pathToResources, const std::vector<Device> &devices)
|
|
{
|
|
// The first call to getInstance() creates the Temperature Controller.
|
|
// The same instance will be accessed by all other modules.
|
|
TemperatureController::getInstance();
|
|
|
|
for (size_t i = 0; i < Configuration::getInstance().NumberOfTracePlayers; i++) {
|
|
std::string playerStr = "tracePlayer" + std::to_string(i);
|
|
TracePlayer<> *player;
|
|
// When data should be stored during the simulation the StlDataPlayer is needed.
|
|
// Else: no data should be stored, for instance to get a faster simulation
|
|
// or if you simply dont care about the data the normal StlPlayer is used.
|
|
if(Configuration::getInstance().ErrorStoreMode == ErrorStorageMode::NoStorage)
|
|
{
|
|
StlPlayer<> *newPlayer = new StlPlayer<>(playerStr.c_str(), pathToResources + string("traces/") + devices[i].trace, devices[i].clkMhz, this);
|
|
player = newPlayer;
|
|
newPlayer->getTraceLength(pathToResources + string("traces/") + devices[i].trace);
|
|
totalTransactions += newPlayer->getNumberOfLines(pathToResources + string("traces/") + devices[i].trace);
|
|
}
|
|
else
|
|
{
|
|
StlDataPlayer<> *newPlayer = new StlDataPlayer<>(playerStr.c_str(), pathToResources + string("traces/") + devices[i].trace, devices[i].clkMhz, this);
|
|
player = newPlayer;
|
|
newPlayer->getTraceLength(pathToResources + string("traces/") + devices[i].trace);
|
|
totalTransactions += newPlayer->getNumberOfLines(pathToResources + string("traces/") + devices[i].trace);
|
|
}
|
|
players.push_back(player);
|
|
}
|
|
remainingTransactions = totalTransactions;
|
|
|
|
//player->remainingTransactions = player->totalTransactions;
|
|
|
|
// Create and properly initialize TLM recorders. They need to be ready before creating some modules.
|
|
setupTlmRecorders(traceName, pathToResources, devices);
|
|
|
|
arbiter = new Arbiter<128>("arbiter");
|
|
arbiter->setTlmRecorders(tlmRecorders);
|
|
|
|
for (size_t i = 0; i < Configuration::getInstance().NumberOfMemChannels; i++) {
|
|
std::string str = "controller" + std::to_string(i);
|
|
Controller<> *controller = new Controller<>(str.c_str(), tlmRecorders[i]);
|
|
controllers.push_back(controller);
|
|
|
|
str = "dram" + std::to_string(i);
|
|
Dram<> *dram = new Dram<>(str.c_str());
|
|
dram->setTlmRecorder(tlmRecorders[i]);
|
|
dram->setDramController(controllers[i]);
|
|
drams.push_back(dram);
|
|
}
|
|
}
|
|
|
|
void Simulation::bindSockets()
|
|
{
|
|
for (auto player : players) {
|
|
player->iSocket.bind(arbiter->tSocket);
|
|
}
|
|
|
|
for (size_t i = 0; i < Configuration::getInstance().NumberOfMemChannels; i++) {
|
|
arbiter->iSocket.bind(controllers[i]->tSocket);
|
|
controllers[i]->iSocket.bind(drams[i]->tSocket);
|
|
}
|
|
}
|
|
|
|
Simulation::~Simulation()
|
|
{
|
|
for (auto player : players) {
|
|
delete player;
|
|
}
|
|
|
|
delete arbiter;
|
|
|
|
for (auto controller : controllers) {
|
|
delete controller;
|
|
}
|
|
|
|
for (auto dram : drams) {
|
|
delete dram;
|
|
}
|
|
|
|
for (auto rec : tlmRecorders) {
|
|
delete rec;
|
|
}
|
|
}
|
|
|
|
void Simulation::start()
|
|
{
|
|
report("\n\nStarting simulation:");
|
|
report(headline);
|
|
report(" -> setup: \t\t" + getFileName(traceName));
|
|
report(" -> memspec: \t\t" + Configuration::getInstance().memSpec.MemoryId);
|
|
cout << endl;
|
|
simulationStartTime = clock();
|
|
|
|
for (auto player : players) {
|
|
player->nextPayload();
|
|
}
|
|
|
|
sc_set_stop_mode(SC_STOP_FINISH_DELTA);
|
|
sc_start();
|
|
}
|
|
|
|
void inline Simulation::tracePlayerTerminates()
|
|
{
|
|
static unsigned int finishedTracePlayers = 0;
|
|
finishedTracePlayers++;
|
|
|
|
if (finishedTracePlayers == Configuration::getInstance().NumberOfTracePlayers)
|
|
terminateSimulation.notify();
|
|
}
|
|
|
|
void Simulation::stop()
|
|
{
|
|
wait(terminateSimulation);
|
|
|
|
unsigned int pending_payloads = 0;
|
|
do {
|
|
pending_payloads = 0;
|
|
for (auto controller : controllers) {
|
|
pending_payloads += controller->getTotalNumberOfPayloadsInSystem();
|
|
}
|
|
wait(sc_time(200, SC_NS));
|
|
} while(pending_payloads != 0);
|
|
|
|
report("\nTerminating simulation");
|
|
for (auto controller : controllers) {
|
|
controller->terminateSimulation();
|
|
}
|
|
wait(sc_time(200, SC_NS));
|
|
for (auto rec : tlmRecorders) {
|
|
rec->closeConnection();
|
|
}
|
|
sc_stop();
|
|
|
|
double elapsed_secs = double(clock() - simulationStartTime) / CLOCKS_PER_SEC;
|
|
report("Simulation took " + to_string(elapsed_secs) + " seconds");
|
|
}
|
|
|
|
|
|
void inline Simulation::transactionFinished()
|
|
{
|
|
remainingTransactions--;
|
|
loadbar(totalTransactions - remainingTransactions, totalTransactions);
|
|
if (remainingTransactions == 0)
|
|
{
|
|
cout << endl;
|
|
}
|
|
}
|
|
|
|
void Simulation::report(string message)
|
|
{
|
|
DebugManager::getInstance().printDebugMessage(this->name(), message);
|
|
cout << message << endl;
|
|
}
|
|
|