401 lines
12 KiB
C++
401 lines
12 KiB
C++
/*
|
|
* Copyright (c) 2021, RPTU Kaiserslautern-Landau
|
|
* 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:
|
|
* Derek Christ
|
|
*/
|
|
|
|
#include "simulationdialog.h"
|
|
#include "DRAMSys/config/TraceSetup.h"
|
|
|
|
#include <QDateTime>
|
|
#include <QDebug>
|
|
#include <QFile>
|
|
#include <QFileDialog>
|
|
#include <QMessageBox>
|
|
#include <QRegularExpression>
|
|
#include <optional>
|
|
|
|
SimulationDialog::SimulationDialog(QWidget* parent) : QWidget(parent), ui(new Ui::SimulationDialog)
|
|
{
|
|
ui->setupUi(this);
|
|
|
|
showStopButton(false);
|
|
|
|
// Try to find path to DRAMSys
|
|
{
|
|
QFileInfo fileInfo;
|
|
|
|
fileInfo.setFile("../simulator/DRAMSys");
|
|
if (fileInfo.isFile())
|
|
ui->dramSysPath->setText(fileInfo.absoluteFilePath());
|
|
|
|
fileInfo.setFile("../simulator/DRAMSys.exe");
|
|
if (fileInfo.isFile())
|
|
ui->dramSysPath->setText(fileInfo.absoluteFilePath());
|
|
|
|
fileInfo.setFile("simulator/DRAMSys");
|
|
if (fileInfo.isFile())
|
|
ui->dramSysPath->setText(fileInfo.absoluteFilePath());
|
|
|
|
fileInfo.setFile("simulator/DRAMSys.exe");
|
|
if (fileInfo.isFile())
|
|
ui->dramSysPath->setText(fileInfo.absoluteFilePath());
|
|
}
|
|
|
|
ui->outputDirLineEdit->setText(QDir::currentPath());
|
|
}
|
|
|
|
void SimulationDialog::on_browseDramSysButton_clicked()
|
|
{
|
|
QString fileName = QFileDialog::getOpenFileName(
|
|
this, ui->browseDramSysButton->text(), {}, "DRAMSys executable (*)");
|
|
ui->dramSysPath->setText(fileName);
|
|
}
|
|
|
|
void SimulationDialog::on_browseConfigButton_clicked()
|
|
{
|
|
QString fileName = QFileDialog::getOpenFileName(
|
|
this, ui->browseConfigButton->text(), {}, "Configuration file (*.json)");
|
|
ui->jsonPath->setText(fileName);
|
|
|
|
loadConfigurationFromPath();
|
|
}
|
|
|
|
void SimulationDialog::on_browseOutputButton_clicked()
|
|
{
|
|
QString fileName = QFileDialog::getExistingDirectory(this, ui->browseOutputButton->text(), {});
|
|
ui->outputDirLineEdit->setText(fileName);
|
|
|
|
loadConfigurationFromPath();
|
|
}
|
|
|
|
void SimulationDialog::on_browseResourceDirButton_clicked()
|
|
{
|
|
QString fileName =
|
|
QFileDialog::getExistingDirectory(this, ui->browseResourceDirButton->text(), {});
|
|
ui->resourceDirLineEdit->setText(fileName);
|
|
|
|
loadConfigurationFromPath();
|
|
}
|
|
|
|
void SimulationDialog::on_simulateButton_clicked()
|
|
{
|
|
saveConfiguration(temporaryConfigurationFile);
|
|
|
|
ui->tabWidget->setCurrentWidget(ui->outputTab);
|
|
ui->progressBar->setEnabled(true);
|
|
ui->progressBar->setValue(0);
|
|
|
|
showStopButton(true);
|
|
|
|
// Spawn the DRAMSys process
|
|
simulatorProcess = new QProcess(this);
|
|
|
|
QObject::connect(simulatorProcess,
|
|
&QIODevice::readyRead,
|
|
this,
|
|
[=]
|
|
{
|
|
QByteArray msg = simulatorProcess->read(4096);
|
|
msg = msg.trimmed();
|
|
processMessage(msg.toStdString());
|
|
});
|
|
|
|
QObject::connect(simulatorProcess,
|
|
QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished),
|
|
this,
|
|
[=](int exitCode, QProcess::ExitStatus exitStatus)
|
|
{
|
|
Q_UNUSED(exitStatus)
|
|
|
|
showStopButton(false);
|
|
|
|
// Clear all the contents so that the user is not asked
|
|
// next time to overwrite the temp file.
|
|
temporaryConfigurationFile.resize(0);
|
|
|
|
if (exitCode == 0)
|
|
{
|
|
ui->progressBar->setValue(100);
|
|
|
|
QMessageBox msgBox;
|
|
msgBox.setText("Simulation done.");
|
|
msgBox.setInformativeText("Do you want to open the results?");
|
|
msgBox.setStandardButtons(QMessageBox::Open | QMessageBox::Cancel);
|
|
msgBox.setDefaultButton(QMessageBox::Open);
|
|
int ret = msgBox.exec();
|
|
|
|
if (ret == QMessageBox::Open)
|
|
{
|
|
auto results = getSimulationResults();
|
|
openSimulationResults(results);
|
|
}
|
|
}
|
|
});
|
|
|
|
QStringList argumentList;
|
|
argumentList << temporaryConfigurationFile.fileName();
|
|
|
|
if (!ui->resourceDirLineEdit->text().isEmpty())
|
|
argumentList << ui->resourceDirLineEdit->text();
|
|
|
|
simulatorProcess->setWorkingDirectory(ui->outputDirLineEdit->text());
|
|
simulatorProcess->start(ui->dramSysPath->text(), argumentList);
|
|
}
|
|
|
|
void SimulationDialog::on_reloadButton_clicked()
|
|
{
|
|
loadConfigurationFromPath();
|
|
|
|
ui->outputPlainTextEdit->clear();
|
|
}
|
|
|
|
void SimulationDialog::on_saveButton_clicked()
|
|
{
|
|
QFile file(ui->jsonPath->text());
|
|
saveConfiguration(file);
|
|
}
|
|
|
|
void SimulationDialog::on_stopButton_clicked()
|
|
{
|
|
if (simulatorProcess)
|
|
simulatorProcess->terminate();
|
|
}
|
|
|
|
void SimulationDialog::showStopButton(bool val)
|
|
{
|
|
ui->simulateButton->setVisible(!val);
|
|
ui->stopButton->setVisible(val);
|
|
}
|
|
|
|
void SimulationDialog::saveConfiguration(QFile& file)
|
|
{
|
|
if (!file.open(QIODevice::ReadWrite | QIODevice::Text))
|
|
return;
|
|
|
|
if (file.size() != 0)
|
|
{
|
|
QMessageBox msgBox;
|
|
msgBox.setText("The configuration file will be overwritten.");
|
|
msgBox.setInformativeText("Do you want to save your changes?");
|
|
msgBox.setStandardButtons(QMessageBox::Save | QMessageBox::Cancel);
|
|
msgBox.setDefaultButton(QMessageBox::Save);
|
|
int ret = msgBox.exec();
|
|
|
|
if (ret != QMessageBox::Save)
|
|
return;
|
|
}
|
|
|
|
// Clear the file
|
|
file.resize(0);
|
|
|
|
QTextStream out(&file);
|
|
|
|
loadConfigurationFromTextFields();
|
|
|
|
std::string dump = nlohmann::json(configuration).dump(4);
|
|
out << dump.c_str();
|
|
}
|
|
|
|
void SimulationDialog::processMessage(const std::string& msg)
|
|
{
|
|
// Get percentages
|
|
QRegularExpression re("(\\d+(\\.\\d+)?|\\.\\d+) ?%");
|
|
QRegularExpressionMatch match = re.match(msg.c_str());
|
|
|
|
if (match.hasMatch())
|
|
{
|
|
unsigned int percentage = match.captured(1).toUInt();
|
|
|
|
ui->progressBar->setValue(percentage);
|
|
}
|
|
|
|
ui->outputPlainTextEdit->appendPlainText(msg.c_str());
|
|
}
|
|
|
|
void SimulationDialog::loadConfigurationFromTextFields()
|
|
{
|
|
using namespace DRAMSys::Config;
|
|
|
|
AddressMapping addressMapping;
|
|
McConfig mcConfig;
|
|
MemSpec memSpec;
|
|
SimConfig simConfig;
|
|
std::string simulationId;
|
|
std::vector<Initiator> traceSetup;
|
|
|
|
simulationId = ui->simulationIdLineEdit->text().toStdString();
|
|
|
|
try
|
|
{
|
|
nlohmann::json::parse(ui->addressMappingTextEdit->toPlainText().toStdString())
|
|
.get_to(addressMapping);
|
|
nlohmann::json::parse(ui->mcConfigTextEdit->toPlainText().toStdString()).get_to(mcConfig);
|
|
nlohmann::json::parse(ui->memSpecTextEdit->toPlainText().toStdString()).get_to(memSpec);
|
|
nlohmann::json::parse(ui->simConfigTextEdit->toPlainText().toStdString()).get_to(simConfig);
|
|
|
|
if (!ui->traceSetupTextEdit->toPlainText().toStdString().empty())
|
|
nlohmann::json::parse(ui->traceSetupTextEdit->toPlainText().toStdString())
|
|
.get_to(traceSetup);
|
|
}
|
|
catch (const std::exception& e)
|
|
{
|
|
qWarning() << "Error while parsing json:" << e.what();
|
|
return;
|
|
}
|
|
|
|
configuration = DRAMSys::Config::Configuration{
|
|
addressMapping,
|
|
mcConfig,
|
|
memSpec,
|
|
simConfig,
|
|
simulationId,
|
|
std::make_optional<std::vector<Initiator>>(std::move(traceSetup))};
|
|
|
|
loadConfiguration();
|
|
}
|
|
|
|
void SimulationDialog::loadConfigurationFromPath()
|
|
{
|
|
QFileInfo fileInfo(ui->jsonPath->text());
|
|
|
|
if (!fileInfo.isFile())
|
|
return;
|
|
|
|
try
|
|
{
|
|
configuration = DRAMSys::Config::from_path(ui->jsonPath->text().toStdString());
|
|
}
|
|
catch (const std::exception& e)
|
|
{
|
|
qWarning() << "Error while parsing json:" << e.what();
|
|
return;
|
|
}
|
|
|
|
loadConfiguration();
|
|
}
|
|
|
|
void SimulationDialog::loadConfiguration()
|
|
{
|
|
ui->simulationIdLabel->setEnabled(true);
|
|
ui->simulationId->setEnabled(true);
|
|
ui->simulationId->setText(configuration.simulationid.c_str());
|
|
|
|
ui->simulationIdLineEdit->setText(configuration.simulationid.c_str());
|
|
|
|
loadSimConfig();
|
|
loadMcConfig();
|
|
loadMemSpec();
|
|
loadAddressMapping();
|
|
loadTraceSetup();
|
|
loadPreview();
|
|
}
|
|
|
|
void SimulationDialog::loadSimConfig()
|
|
{
|
|
ui->simConfigTextEdit->clear();
|
|
|
|
std::string dump = nlohmann::json(configuration.simconfig).dump(4);
|
|
ui->simConfigTextEdit->setText(dump.c_str());
|
|
}
|
|
|
|
void SimulationDialog::loadMcConfig()
|
|
{
|
|
ui->mcConfigTextEdit->clear();
|
|
|
|
std::string dump = nlohmann::json(configuration.mcconfig).dump(4);
|
|
ui->mcConfigTextEdit->setText(dump.c_str());
|
|
}
|
|
|
|
void SimulationDialog::loadMemSpec()
|
|
{
|
|
ui->memSpecTextEdit->clear();
|
|
|
|
std::string dump = nlohmann::json(configuration.memspec).dump(4);
|
|
ui->memSpecTextEdit->setText(dump.c_str());
|
|
}
|
|
|
|
void SimulationDialog::loadAddressMapping()
|
|
{
|
|
ui->addressMappingTextEdit->clear();
|
|
|
|
std::string dump = nlohmann::json(configuration.addressmapping).dump(4);
|
|
ui->addressMappingTextEdit->setText(dump.c_str());
|
|
}
|
|
|
|
void SimulationDialog::loadTraceSetup()
|
|
{
|
|
ui->traceSetupTextEdit->clear();
|
|
|
|
if (const auto& traceSetup = configuration.tracesetup)
|
|
{
|
|
std::string dump = nlohmann::json(*traceSetup).dump(4);
|
|
ui->traceSetupTextEdit->setText(dump.c_str());
|
|
}
|
|
}
|
|
|
|
void SimulationDialog::loadPreview()
|
|
{
|
|
ui->previewTextEdit->clear();
|
|
|
|
std::string dump = nlohmann::json(configuration).dump(4);
|
|
ui->previewTextEdit->setText(dump.c_str());
|
|
}
|
|
|
|
QFileInfoList SimulationDialog::getSimulationResults()
|
|
{
|
|
QFileInfoList list;
|
|
|
|
// Get the path where the tracefiles are located
|
|
QDir baseDir(ui->outputDirLineEdit->text());
|
|
|
|
for (const auto& fileInfo : baseDir.entryInfoList())
|
|
{
|
|
if (fileInfo.baseName().startsWith(configuration.simulationid.c_str()))
|
|
{
|
|
// Dont open tracefiles that are older than a few seconds
|
|
if (fileInfo.metadataChangeTime().secsTo(QDateTime::currentDateTime()) > 30)
|
|
continue;
|
|
|
|
list << fileInfo;
|
|
}
|
|
}
|
|
|
|
return list;
|
|
}
|
|
|
|
void SimulationDialog::openSimulationResults(const QFileInfoList& fileInfos)
|
|
{
|
|
for (const auto& fileInfo : fileInfos)
|
|
openFileRequested(fileInfo.absoluteFilePath());
|
|
}
|