The configuration library has been refactored to make use of nlohmann macros to reduce boilerplate code. The nlohmann parser callback is used to decide whether to include configuration json objects directly, or if they need to be loaded from a sperate file.
393 lines
12 KiB
C++
393 lines
12 KiB
C++
/*
|
|
* Copyright (c) 2021, Technische Universität 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:
|
|
* 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;
|
|
TraceSetup 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<TraceSetup>(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());
|
|
}
|