Factor telemetry to separate class
MODIFY
main.cpp
main.cpp
using namespace std;
-void initParser(QCommandLineParser &parser) {
+void initParser(QCommandLineParser &parser, Ripes::CmdModeOptions &options) {
QString helpText =
"The command line interface allows for assembling/compiling/executing a "
"\n"
@@ -24,7 +24,7 @@ void initParser(QCommandLineParser &parser) {
parser.setApplicationDescription(helpText);
QCommandLineOption modeOption("mode", "Ripes mode [gui, sh]", "mode", "gui");
parser.addOption(modeOption);
- Ripes::addCmdOptions(parser);
+ Ripes::addCmdOptions(parser, options);
}
enum CommandLineParseResult {
@@ -69,9 +69,8 @@ int guiMode(QApplication &app) {
return app.exec();
}
-int cmdMode(QCommandLineParser &parser, QApplication &) {
+int cmdMode(QCommandLineParser &parser, Ripes::CmdModeOptions &options) {
QString err;
- Ripes::CmdModeOptions options;
if (!Ripes::parseCmdOptions(parser, err, options)) {
std::cerr << "ERROR: " << err.toStdString() << std::endl;
parser.showHelp();
@@ -90,7 +89,8 @@ int main(int argc, char **argv) {
QCoreApplication::setApplicationName("Ripes");
QCommandLineParser parser;
- initParser(parser);
+ Ripes::CmdModeOptions options;
+ initParser(parser, options);
QString err;
switch (parseCommandLine(parser, err)) {
case CommandLineError:
@@ -103,6 +103,6 @@ int main(int argc, char **argv) {
case CommandLineGUI:
return guiMode(app);
case CommandLineCMD:
- return cmdMode(parser, app);
+ return cmdMode(parser, options);
}
}

MODIFY
src/cmd/cmdoptions.cpp
src/cmd/cmdoptions.cpp
#include "cmdoptions.h"
#include "processorregistry.h"
+#include "telemetry.h"
+#include <QFile>
#include <QMetaEnum>
namespace Ripes {
@@ -10,7 +12,7 @@ QString enumToString(T value) {
return QMetaEnum::fromType<T>().valueToKey(castValue);
}
-void addCmdOptions(QCommandLineParser &parser) {
+void addCmdOptions(QCommandLineParser &parser, Ripes::CmdModeOptions &options) {
QCommandLineOption srcOption("src", "Source file", "src");
parser.addOption(srcOption);
@@ -40,13 +42,23 @@ void addCmdOptions(QCommandLineParser &parser) {
QCommandLineOption verboseOption("v", "Verbose output");
parser.addOption(verboseOption);
+ // Output to file
+ QCommandLineOption outputOption(
+ "output",
+ "Telemetry output file. If not set, telemtry is printed to stdout.",
+ "output", "");
+ parser.addOption(outputOption);
+
// Telemtry reporting
- QCommandLineOption cycles("cycles", "Print # of cycles executed");
- parser.addOption(cycles);
- QCommandLineOption cpi("cpi", "Print CPI");
- parser.addOption(cpi);
- QCommandLineOption ipc("ipc", "Print IPC");
- parser.addOption(ipc);
+ options.telemetry.push_back(std::make_shared<CyclesTelemetry>());
+ options.telemetry.push_back(std::make_shared<CPITelemetry>());
+ options.telemetry.push_back(std::make_shared<IPCTelemetry>());
+
+ for (auto &telemetry : options.telemetry) {
+ QCommandLineOption telemetryOption(telemetry->key(),
+ telemetry->description());
+ parser.addOption(telemetryOption);
+ }
}
bool parseCmdOptions(QCommandLineParser &parser, QString &errorMessage,
@@ -111,10 +123,12 @@ bool parseCmdOptions(QCommandLineParser &parser, QString &errorMessage,
}
}
- // Telemtry reporting
- options.cycles = parser.isSet("cycles");
- options.cpi = parser.isSet("cpi");
- options.ipc = parser.isSet("ipc");
+ options.outputFile = parser.value("output");
+
+ // Enable selected telemetry options.
+ for (auto &telemetry : options.telemetry)
+ if (parser.isSet(telemetry->key()))
+ telemetry->enable();
return true;
}

MODIFY
src/cmd/cmdoptions.h
src/cmd/cmdoptions.h
#include "assembler/program.h"
#include "processorregistry.h"
+#include "telemetry.h"
#include <QCommandLineParser>
+#include <set>
namespace Ripes {
@@ -12,15 +14,14 @@ struct CmdModeOptions {
ProcessorID proc;
QStringList isaExtensions;
bool verbose;
+ QString outputFile;
- // telemetry
- bool cycles = false;
- bool cpi = false;
- bool ipc = false;
+ // A list of enabled telemetry options.
+ std::vector<std::shared_ptr<Telemetry>> telemetry;
};
/// Adds Ripes command-line mode options to a parser.
-void addCmdOptions(QCommandLineParser &parser);
+void addCmdOptions(QCommandLineParser &parser, Ripes::CmdModeOptions &options);
/// Parses Ripes command-line mode options to a CmdModeOptions struct. Returns
/// true if options were parsed successfully.
bool parseCmdOptions(QCommandLineParser &parser, QString &errorMessage,

MODIFY
src/cmd/cmdrunner.cpp
src/cmd/cmdrunner.cpp
@@ -91,26 +91,34 @@ int CmdRunner::runModel() {
int CmdRunner::postRun() {
info("Post-run", false, true);
- const auto cycleCount = ProcessorHandler::getProcessor()->getCycleCount();
- const auto instrsRetired =
- ProcessorHandler::getProcessor()->getInstructionsRetired();
- const double cpi =
- static_cast<double>(cycleCount) / static_cast<double>(instrsRetired);
- const double ipc = 1 / cpi;
-
- if (m_options.cycles)
- info("Cycles: " + QString::number(cycleCount), true);
+ // Open telemetry stream
+ std::unique_ptr<QTextStream> stream;
+ std::unique_ptr<QFile> outputFile;
+ if (m_options.outputFile.isEmpty()) {
+ stream = std::make_unique<QTextStream>(stdout, QIODevice::WriteOnly);
+ } else {
+ outputFile = std::make_unique<QFile>(m_options.outputFile);
+ if (!outputFile->open(QIODevice::Truncate | QIODevice::Text |
+ QIODevice::WriteOnly)) {
+ error("Failed to open output file");
+ return 1;
+ }
+ stream = std::make_unique<QTextStream>(outputFile.get());
+ }
- if (m_options.cpi)
- info("CPI: " + QString::number(cpi), true);
+ for (auto &telemetry : m_options.telemetry)
+ if (telemetry->isEnabled())
+ telemetry->report(*stream);
- if (m_options.ipc)
- info("IPC: " + QString::number(ipc), true);
+ // Close output file if necessary
+ if (!m_options.outputFile.isEmpty())
+ outputFile->close();
return 0;
}
void CmdRunner::info(QString msg, bool alwaysPrint, bool header) {
+
if (m_options.verbose || alwaysPrint) {
if (header) {
int headerWidth = 80;

ADD
src/cmd/telemetry.h
+#pragma once
+
+#include <QTextStream>
+
+#include "processorhandler.h"
+
+namespace Ripes {
+
+/// A class for
+class Telemetry {
+public:
+ Telemetry() {}
+ virtual ~Telemetry(){};
+
+ // Report this telemetry to the provided output stream.
+ virtual void report(QTextStream &out) = 0;
+
+ // Returns the name of this telemetry.
+ virtual QString key() const = 0;
+
+ // Returns the description of this telemetry.
+ virtual QString description() const = 0;
+
+ void enable() { m_enabled = true; }
+ void disable() { m_enabled = false; }
+ bool isEnabled() const { return m_enabled; }
+
+private:
+ bool m_enabled = false;
+};
+
+class CPITelemetry : public Telemetry {
+ QString key() const override { return "cpi"; }
+ QString description() const override {
+ return "Report cycles per instruction";
+ }
+ void report(QTextStream &out) override {
+ const auto cycleCount = ProcessorHandler::getProcessor()->getCycleCount();
+ const auto instrsRetired =
+ ProcessorHandler::getProcessor()->getInstructionsRetired();
+ const double cpi =
+ static_cast<double>(cycleCount) / static_cast<double>(instrsRetired);
+ out << "CPI: " << QString::number(cpi) << "\n";
+ }
+};
+
+class IPCTelemetry : public Telemetry {
+ QString key() const override { return "ipc"; }
+ QString description() const override {
+ return "Report instructions per cycle";
+ }
+ void report(QTextStream &out) override {
+ const auto cycleCount = ProcessorHandler::getProcessor()->getCycleCount();
+ const auto instrsRetired =
+ ProcessorHandler::getProcessor()->getInstructionsRetired();
+ const double cpi =
+ static_cast<double>(cycleCount) / static_cast<double>(instrsRetired);
+ const double ipc = 1 / cpi;
+ out << "IPC: " << QString::number(ipc) << "\n";
+ }
+};
+
+class CyclesTelemetry : public Telemetry {
+ QString key() const override { return "cycles"; }
+ QString description() const override {
+ return "Report total number of cycles";
+ }
+ void report(QTextStream &out) override {
+ const auto cycleCount = ProcessorHandler::getProcessor()->getCycleCount();
+ out << "Cycles: " << QString::number(cycleCount) << "\n";
+ }
+};
+
+} // namespace Ripes

Factor telemetry to separate class