Files
DRAMSys/extensions/apps/traceAnalyzer/simulationdialog.cpp
2023-08-29 09:26:25 +02:00

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