Skip to content

Commit

Permalink
add timer capabilities to cli, refactor args
Browse files Browse the repository at this point in the history
Co-authored-by: Maksim Shagov <43129418+MaksimShagov@users.noreply.github.com>
  • Loading branch information
vla5924 and MaksimShagov committed Apr 7, 2024
1 parent c140a1f commit 37ac49a
Show file tree
Hide file tree
Showing 4 changed files with 181 additions and 81 deletions.
14 changes: 9 additions & 5 deletions compiler/include/compiler/cli/logger.hpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#pragma once

#include <fstream>
#include <iostream>
#include <string>

class Logger {
Expand All @@ -14,11 +15,14 @@ class Logger {
void setStdoutEnabled(bool enabled);
void setOutputFile(const std::string &filename);

Logger &operator<<(const std::string &);
Logger &operator<<(const char *const);
Logger &operator<<(char);
Logger &operator<<(size_t);
Logger &operator<<(std::ostream &(*)(std::ostream &));
template <typename T>
Logger &operator<<(const T &out) {
if (stdoutEnabled)
std::cout << out;
if (fileOutput.is_open())
fileOutput << out;
return *this;
}

private:
void closeOutputFile();
Expand Down
33 changes: 33 additions & 0 deletions compiler/include/compiler/utils/timer.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
#pragma once

#include <chrono>

namespace utils {

struct Timer {
using TimePoint = std::chrono::time_point<std::chrono::steady_clock>;

Timer() = default;
Timer(const Timer &) = default;
Timer(Timer &&) = default;
~Timer() = default;

void start() {
startPoint = std::chrono::steady_clock::now();
}

void stop() {
stopPoint = std::chrono::steady_clock::now();
}

// Obtain elapsed time in milliseconds
auto elapsed() const {
return std::chrono::duration_cast<std::chrono::milliseconds>(stopPoint - startPoint).count();
}

private:
TimePoint startPoint;
TimePoint stopPoint;
};

} // namespace utils
188 changes: 139 additions & 49 deletions compiler/lib/cli/compiler.cpp
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
#include "compiler.hpp"

#include <exception>
#include <iostream>
#include <iterator>
#include <numeric>
#include <string>
#include <string_view>
#include <vector>

#ifdef ENABLE_CODEGEN
Expand All @@ -19,6 +23,7 @@
#include "compiler/frontend/parser/parser.hpp"
#include "compiler/frontend/preprocessor/preprocessor.hpp"
#include "compiler/utils/source_files.hpp"
#include "compiler/utils/timer.hpp"

#ifdef ENABLE_CODEGEN
#include "compiler/codegen/ir_generator.hpp"
Expand All @@ -33,26 +38,47 @@ using parser::Parser;
using preprocessor::Preprocessor;
using semantizer::Semantizer;
using utils::SourceFile;
using utils::Timer;

#ifdef ENABLE_CODEGEN
using ir_generator::IRGenerator;
#endif

namespace {
namespace arg {

const char *const ARG_HELP = "--help";
const char *const ARG_VERBOSE = "--verbose";
const char *const ARG_LOG = "--log";
const char *const ARG_OPTIMIZE = "--optimize";
const char *const ARG_FILES = "FILES";
constexpr std::string_view help = "--help";
constexpr std::string_view verbose = "--verbose";
constexpr std::string_view log = "--log";
constexpr std::string_view optimize = "--optimize";
constexpr std::string_view time = "--time";
constexpr std::string_view stopAfter = "--stop-after";
constexpr std::string_view files = "FILES";

#ifdef ENABLE_CODEGEN
const char *const ARG_COMPILE = "--compile";
const char *const ARG_CLANG = "--clang";
const char *const ARG_LLC = "--llc";
const char *const ARG_OUTPUT = "--output";
constexpr std::string_view compile = "--compile";
constexpr std::string_view clang = "--clang";
constexpr std::string_view llc = "--llc";
constexpr std::string_view output = "--output";
#endif

} // namespace arg

namespace stage {

constexpr std::string_view preprocessor = "preprocessor";
constexpr std::string_view lexer = "lexer";
constexpr std::string_view parser = "parser";
constexpr std::string_view semantizer = "semantizer";
constexpr std::string_view optimizer = "optimizer";

#ifdef ENABLE_CODEGEN
constexpr std::string_view codegen = "codegen";
#endif

} // namespace stage

namespace {

#ifdef ENABLE_CODEGEN
std::filesystem::path createTemporaryDirectory() {
auto tempDir = std::filesystem::temp_directory_path();
Expand Down Expand Up @@ -96,113 +122,173 @@ std::string generateClangCommand(const std::string &clangBin, const std::filesys

int Compiler::exec(int argc, char *argv[]) {
argparse::ArgumentParser program("compiler", "1.0", argparse::default_arguments::none);
program.add_argument("-h", ARG_HELP).help("show help message and exit").default_value(false).implicit_value(true);
program.add_argument("-v", ARG_VERBOSE).help("print info messages").default_value(false).implicit_value(true);
program.add_argument("-l", ARG_LOG).help("log file (stages output will be saved if provided)");
program.add_argument("-O", ARG_OPTIMIZE).help("run optimization pass").default_value(false).implicit_value(true);
program.add_argument("-h", arg::help).help("show help message and exit").default_value(false).implicit_value(true);
program.add_argument("-v", arg::verbose).help("print info messages").default_value(false).implicit_value(true);
program.add_argument("-l", arg::log).help("log file (stages output will be saved if provided)");
program.add_argument("-O", arg::optimize).help("run optimization pass").default_value(false).implicit_value(true);
#ifdef ENABLE_CODEGEN
program.add_argument("-c", ARG_COMPILE)
program.add_argument("-c", arg::compile)
.help("produce an executable instead of LLVM IR code")
.default_value(false)
.implicit_value(true);
program.add_argument(ARG_CLANG)
program.add_argument(arg::clang)
.help("path to clang executable (required if --compile argument is set)")
.default_value("clang");
program.add_argument(ARG_LLC)
program.add_argument(arg::llc)
.help("path to llc executable (required if --compile argument is set)")
.default_value("llc");
program.add_argument("-o", ARG_OUTPUT).help("output file");
program.add_argument("-o", arg::output).help("output file");
#endif
program.add_argument(ARG_FILES).help("source files (separated by spaces)").required().remaining();
program.add_argument(arg::time)
.help("print execution times of each stage")
.default_value(false)
.implicit_value(true);
program.add_argument(arg::stopAfter)
.help("stop processing after specific stage")
.choices(stage::preprocessor, stage::lexer, stage::parser, stage::semantizer, stage::optimizer);
program.add_argument(arg::files)
.help("source files (separated by spaces)")
.required()
.nargs(argparse::nargs_pattern::at_least_one);

try {
program.parse_args(argc, argv);
} catch (const std::runtime_error &err) {
std::cerr << err.what() << std::endl;
std::cerr << err.what() << "\n";
std::cerr << program;
return 1;
}

if (program.get<bool>(ARG_HELP)) {
if (program.get<bool>(arg::help)) {
std::cout << program;
return 0;
}

Logger logger;
bool verbose = program.get<bool>(ARG_VERBOSE);
bool verbose = program.get<bool>(arg::verbose);
if (verbose)
logger.setStdoutEnabled(true);
if (program.is_used(ARG_LOG))
logger.setOutputFile(program.get<std::string>(ARG_LOG));
if (program.is_used(arg::log))
logger.setOutputFile(program.get<std::string>(arg::log));

std::vector<std::string> files;
try {
files = program.get<std::vector<std::string>>(ARG_FILES);
logger << files.size() << " file(s) provided:" << std::endl;
files = program.get<std::vector<std::string>>(arg::files);
logger << files.size() << " file(s) provided:\n";
for (auto &file : files)
logger << " " << file << std::endl;
logger << " " << file << "\n";
} catch (std::logic_error &e) {
std::cerr << "No files provided" << std::endl;
std::cerr << "No files provided\n";
return 2;
}

SourceFile source;
for (const std::string &path : files) {
SourceFile other = utils::readFile(path);
source.insert(source.end(), std::make_move_iterator(other.begin()), std::make_move_iterator(other.end()));
logger << "Read file " << path << std::endl;
try {
for (const std::string &path : files) {
SourceFile other = utils::readFile(path);
source.insert(source.end(), std::make_move_iterator(other.begin()), std::make_move_iterator(other.end()));
logger << "Read file " << path << "\n";
}
} catch (std::exception &e) {
logger << e.what();
return 3;
}

std::string stopAfter;
if (program.is_used(arg::stopAfter))
stopAfter = program.get<std::string>(arg::stopAfter);
bool times = program.get<bool>(arg::time);
Timer timer;
std::vector<long long> measuredTimes;

ast::SyntaxTree tree;

try {
logger << std::endl << "PREPROCESSOR:" << std::endl;
logger << "\nPREPROCESSOR:\n";
timer.start();
source = Preprocessor::process(source);
logger << dumping::dump(source) << std::endl;

logger << "LEXER:" << std::endl;
timer.stop();
measuredTimes.push_back(timer.elapsed());
if (times)
logger << "PREPROCESSOR Elapsed time: " << measuredTimes.back() << "\n";
logger << dumping::dump(source) << "\n";
if (stopAfter == stage::preprocessor)
return 0;

logger << "\nLEXER:\n";
timer.start();
auto tokens = Lexer::process(source);
logger << dumping::dump(tokens) << std::endl;

logger << "PARSER:" << std::endl;
timer.stop();
measuredTimes.push_back(timer.elapsed());
if (times)
logger << "LEXER Elapsed time: " << measuredTimes.back() << "\n";
logger << dumping::dump(tokens) << "\n";
if (stopAfter == stage::lexer)
return 0;

logger << "PARSER:\n";
timer.start();
tree = Parser::process(tokens);
timer.stop();
measuredTimes.push_back(timer.elapsed());
if (times)
logger << "PARSER Elapsed time: " << measuredTimes.back() << "\n";
logger << tree.dump();
if (stopAfter == stage::parser)
return 0;

logger << "SEMANTIZER:" << std::endl;
logger << "SEMANTIZER:\n";
timer.start();
Semantizer::process(tree);
timer.stop();
measuredTimes.push_back(timer.elapsed());
if (times)
logger << "SEMANTIZER Elapsed time: " << measuredTimes.back() << "\n";
logger << tree.dump();
if (stopAfter == stage::semantizer)
return 0;

if (program.get<bool>(ARG_OPTIMIZE)) {
logger << "OPTIMIZER:" << std::endl;
if (program.get<bool>(arg::optimize)) {
logger << "OPTIMIZER:\n";
timer.start();
Optimizer::process(tree);
timer.stop();
measuredTimes.push_back(timer.elapsed());
if (times)
logger << "OPTIMIZER Elapsed time: " << measuredTimes.back() << "\n";
logger << tree.dump();
}

if (stopAfter == stage::optimizer)
return 0;
if (times)
logger << "Compile time: " << std::accumulate(measuredTimes.begin(), measuredTimes.end(), 0LL) << "\n";
} catch (ErrorBuffer &errors) {
std::cerr << errors.message();
return 3;
}

#ifdef ENABLE_CODEGEN
logger << std::endl << "IR GENERATOR:" << std::endl;
logger << "\nIR GENERATOR:\n";
IRGenerator generator("module");
generator.process(tree);
if (verbose) {
generator.dump();
}

if (!program.is_used(ARG_OUTPUT))
if (!program.is_used(arg::output))
return 0;

bool compile = program.get<bool>(ARG_COMPILE);
std::string output = program.get<std::string>(ARG_OUTPUT);
bool compile = program.get<bool>(arg::compile);
std::string output = program.get<std::string>(arg::output);

if (!compile) {
generator.writeToFile(output);
return 0;
}

std::string llcBin = program.is_used(ARG_LLC) ? program.get<std::string>(ARG_LLC) : "llc";
std::string clangBin = program.is_used(ARG_CLANG) ? program.get<std::string>(ARG_CLANG) : "clang";
std::string llcBin = program.is_used(arg::llc) ? program.get<std::string>(arg::llc) : "llc";
std::string clangBin = program.is_used(arg::clang) ? program.get<std::string>(arg::clang) : "clang";

try {
std::filesystem::path tempDir = createTemporaryDirectory();
Expand All @@ -212,7 +298,9 @@ int Compiler::exec(int argc, char *argv[]) {
const auto exeFile = tempDir / "out.exe";
std::string llcCmd = generateLlcCommand(llcBin, llFile, objFile);
std::string clangCmd = generateClangCommand(clangBin, objFile, exeFile);
logger << "Executing commands:" << std::endl << " " << llcCmd << std::endl << " " << clangCmd << std::endl;
logger << "Executing commands:\n"
<< " " << llcCmd << "\n"
<< " " << clangCmd << "\n";
bool cmdFailed = (std::system(llcCmd.c_str()) || std::system(clangCmd.c_str()));
if (!cmdFailed)
std::filesystem::copy_file(exeFile, output);
Expand All @@ -223,6 +311,8 @@ int Compiler::exec(int argc, char *argv[]) {
std::cerr << e.what();
return 3;
}
if (stopAfter == stage::codegen)
return 0;
#endif

return 0;
Expand Down
Loading

0 comments on commit 37ac49a

Please sign in to comment.