Skip to content

Commit

Permalink
[emulator] migrate glog to spdlog
Browse files Browse the repository at this point in the history
* add builder pattern log constructor
* replace all glog use into spdlog
* clang-format

Signed-off-by: Avimitin <[email protected]>
  • Loading branch information
Avimitin committed Sep 25, 2023
1 parent 6f81c0d commit 907cd3b
Show file tree
Hide file tree
Showing 12 changed files with 573 additions and 314 deletions.
20 changes: 15 additions & 5 deletions emulator/src/dpi.cc
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

#include <csignal>

#include <glog/logging.h>
#include <spdlog/spdlog.h>
#include <fmt/core.h>

#include "encoding.h"
Expand Down Expand Up @@ -32,12 +32,16 @@ void print_perf_summary();
if (!terminated) {action} \
} catch (ReturnException &e) { \
terminated = true; \
LOG(INFO) << fmt::format("detect returning instruction, gracefully quit simulation"); \
Log("SimulationExit") \
.info("detect returning instruction, gracefully quit simulation"); \
print_perf_summary(); \
dpi_finish(); \
} catch (std::runtime_error &e) { \
terminated = true; \
LOG(ERROR) << fmt::format("detect exception ({}), gracefully abort simulation", e.what()); \
std::cerr << e.what() << std::endl; \
Log("RuntimeException") \
.with("error", e.what()) \
.warn("detect exception, gracefully abort simulation"); \
dpi_error(e.what()); \
}

Expand All @@ -52,7 +56,7 @@ void VBridgeImpl::dpiDumpWave() {
[[maybe_unused]] void dpi_init_cosim() {
std::signal(SIGINT, sigint_handler);
auto scope = svGetScopeFromName("TOP.TestBench.verificationModule.dpiFinish");
CHECK_S(scope);
CHECK(scope, "Got empty scope");
svSetScope(scope);
TRY({
vbridge_impl_instance.dpiInitCosim();
Expand Down Expand Up @@ -204,6 +208,10 @@ void VBridgeImpl::dpiDumpWave() {
chaining_perf.step(*lane_idx, slot_occupied);
})

[[maybe_unused]] void load_unit_monitor(const svBit load_unit_status_idle, const svBit writeReadyForLSU) TRY({

})

void print_perf_summary() {
auto output_file_path = get_env_arg_default("PERF_output_file", nullptr);
if (output_file_path != nullptr) {
Expand All @@ -219,6 +227,8 @@ void print_perf_summary() {
}
chaining_perf.print_summary(os);

LOG(INFO) << fmt::format("perf result saved in '{}'", output_file_path);
Log("PrintPerfSummary")
.with("path", output_file_path)
.info("Perf result saved");
}
}
14 changes: 9 additions & 5 deletions emulator/src/elf.cc
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#include "simple_sim.h"

#include <fmt/core.h>
#include <linux/elf.h>

simple_sim::load_elf_result_t simple_sim::load_elf(const std::string &fname) {
Expand All @@ -9,18 +10,21 @@ simple_sim::load_elf_result_t simple_sim::load_elf(const std::string &fname) {

Elf32_Ehdr ehdr;
fs.read(reinterpret_cast<char *>(&ehdr), sizeof(ehdr));
CHECK_S(ehdr.e_machine == EM_RISCV && ehdr.e_type == ET_EXEC && ehdr.e_ident[EI_CLASS] == ELFCLASS32);
CHECK_S(ehdr.e_phentsize == sizeof(elf32_phdr));
CHECK(ehdr.e_machine == EM_RISCV && ehdr.e_type == ET_EXEC && ehdr.e_ident[EI_CLASS] == ELFCLASS32, "ehdr check failed when loading elf");
CHECK_EQ(ehdr.e_phentsize, sizeof(elf32_phdr), "ehdr.e_phentsize does not equal to elf32_phdr");

for (size_t i = 0; i < ehdr.e_phnum; i++) {
auto phdr_offset = ehdr.e_phoff + i * ehdr.e_phentsize;
Elf32_Phdr phdr;
fs.seekg((long) phdr_offset).read(reinterpret_cast<char *>(&phdr), sizeof(phdr));
if (phdr.p_type == PT_LOAD) {
CHECK_S(phdr.p_paddr + phdr.p_filesz < mem_size);
CHECK(phdr.p_paddr + phdr.p_filesz < mem_size, "phdr p_paddr + p_filesz check failed");
fs.seekg((long) phdr.p_offset).read(reinterpret_cast<char *>(&mem[phdr.p_paddr]), phdr.p_filesz);
VLOG(1) << fmt::format("load elf segment {} at file phdr_offset {:08X} to paddr {:08X}-{:08X}",
i, phdr.p_offset, phdr.p_paddr, phdr.p_paddr + phdr.p_memsz);
Log("LoadElfResult")
.with("segment", i)
.with("phdr_offset", fmt::format("{:08X}", phdr.p_offset))
.with("paddr_range", fmt::format("{:08X}-{:08X}", phdr.p_paddr, phdr.p_paddr + phdr.p_memsz))
.trace();
}
}
return { .entry_addr = ehdr.e_entry };
Expand Down
49 changes: 0 additions & 49 deletions emulator/src/glog_exception_safe.h

This file was deleted.

1 change: 0 additions & 1 deletion emulator/src/perf.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
#pragma once

#include <glog/logging.h>
#include <fmt/core.h>

#include "encoding.h"
Expand Down
1 change: 1 addition & 0 deletions emulator/src/rtl_config.cc
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
using json = nlohmann::json;

#include "rtl_config.h"
#include "spdlog-ext.h"

RTLConfig::RTLConfig(const char *json_file_name) {
std::ifstream json_file(json_file_name);
Expand Down
14 changes: 7 additions & 7 deletions emulator/src/simple_sim.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

#include <fmt/core.h>

#include "glog_exception_safe.h"
#include "spdlog-ext.h"
#include "simif.h"

class simple_sim : public simif_t {
Expand All @@ -28,24 +28,24 @@ class simple_sim : public simif_t {

// should return NULL for MMIO addresses
char *addr_to_mem(reg_t addr) override {
CHECK_S(addr < mem_size) << fmt::format("memory out of bound ({:016X} >= {:016X})", addr, mem_size);
CHECK_LE(addr, mem_size, fmt::format("memory out of bound ({:016X} >= {:016X})", addr, mem_size));
return &mem[addr];
}

bool mmio_load(reg_t addr, size_t len, uint8_t *bytes) override {
LOG(FATAL_S) << "not implemented";
FATAL("Unimplemented");
}

bool mmio_store(reg_t addr, size_t len, const uint8_t *bytes) override {
LOG(FATAL_S) << "not implemented";
FATAL("Unimplemented");
}

[[nodiscard]] const cfg_t &get_cfg() const override {
LOG(FATAL_S) << "not implemented";
FATAL("Unimplemented");
}

[[nodiscard]] const std::map<size_t, processor_t*>& get_harts() const override {
LOG(FATAL_S) << "not implemented";
FATAL("Unimplemented");
}

// Callback for processors to let the simulation know they were reset.
Expand All @@ -54,6 +54,6 @@ class simple_sim : public simif_t {
}

const char *get_symbol(uint64_t addr) override {
LOG(FATAL_S) << "not implemented";
FATAL("Unimplemented");
}
};
27 changes: 17 additions & 10 deletions emulator/src/spdlog-ext.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#include <fmt/core.h>
#include <fstream>
#include <iostream>
#include <memory>
#include <mutex>
#include <set>
#include <sstream>
Expand All @@ -13,9 +14,6 @@
#include <spdlog/sinks/stdout_sinks.h>
#include <spdlog/spdlog.h>

#include <nlohmann/json.hpp>
using json = nlohmann::json;

#include "spdlog-ext.h"

/**
Expand Down Expand Up @@ -71,15 +69,19 @@ class ConsoleSink : public spdlog::sinks::base_sink<std::mutex> {

protected:
void sink_it_(const spdlog::details::log_msg &msg) override {
auto data = std::string(msg.payload.data(), msg.payload.size());
// Don't touch error message
if (msg.level == spdlog::level::info) {
json payload = json::parse(msg.payload.data());
std::string module_name;
try {
payload["module"].get_to(module_name);
json payload = json::parse(data);
payload["name"].get_to(module_name);
} catch (const json::parse_error &ex) {
throw std::runtime_error(
fmt::format("Fail to convert msg {} to json: {}", data, ex.what()));
} catch (const json::type_error &ex) {
fmt::println("Fail to get field `module` from: {}", msg.payload.data());
throw ex;
throw std::runtime_error(
fmt::format("Fail to get field name from: {}", msg.payload.data()));
}

// If module name was found in blacklist
Expand All @@ -94,10 +96,11 @@ class ConsoleSink : public spdlog::sinks::base_sink<std::mutex> {

spdlog::memory_buf_t formatted;
spdlog::sinks::base_sink<std::mutex>::formatter_->format(msg, formatted);
std::cout << fmt::to_string(formatted);
// stdout will be captured by mill, so we need to print them into stderr
std::cerr << fmt::to_string(formatted);
}

void flush_() override { std::cout << std::flush; }
void flush_() override { std::cerr << std::flush; }
};

/**
Expand Down Expand Up @@ -139,18 +142,22 @@ void setup_logger() {
// %T: "23:55:59" (We don't need other information.)
console_sink->set_pattern("%T %v");

// Combine the console sink and file sink into one logger.
// One thread with 8192 queue size
spdlog::init_thread_pool(8192, 1);
std::vector<spdlog::sink_ptr> sinks;
sinks.push_back(file_sink);
sinks.push_back(console_sink);

// Combine the console sink and file sink into one logger.
auto logger = std::make_shared<spdlog::async_logger>(
"Emulator", std::begin(sinks), std::end(sinks), spdlog::thread_pool(),
spdlog::async_overflow_policy::block);
logger->set_error_handler([&](const std::string &msg) {
throw std::runtime_error(fmt::format("Emulator internal error: {}", msg));
});
logger->flush_on(spdlog::level::info);
logger->flush_on(spdlog::level::err);
logger->flush_on(spdlog::level::critical);

spdlog::set_default_logger(logger);

Expand Down
89 changes: 85 additions & 4 deletions emulator/src/spdlog-ext.h
Original file line number Diff line number Diff line change
@@ -1,7 +1,17 @@
#pragma once

#include <iostream>
#include <nlohmann/json.hpp>
#include <optional>
#include <spdlog/spdlog.h>
using json = nlohmann::json;

// Exported symbols
void setup_logger();
#define FATAL(context) \
auto _fatal_fmt_msg = fmt::format("{}", context); \
spdlog::critical("{}", context); \
spdlog::shutdown(); \
throw std::runtime_error(_fatal_fmt_msg);

#define CHECK(cond, context) \
if (!(cond)) { \
Expand All @@ -10,13 +20,84 @@ void setup_logger();
context, #cond, __FILE__, __LINE__); \
json _j; \
_j["message"] = _f_msg; \
spdlog::error(_j.dump()); \
spdlog::shutdown(); \
throw std::runtime_error(_f_msg); \
FATAL(_j.dump()); \
}

#define CHECK_EQ(val1, val2, context) CHECK(val1 == val2, context)
#define CHECK_NE(val1, val2, context) CHECK(val1 != val2, context)
#define CHECK_LE(val1, val2, context) CHECK(val1 <= val2, context)
#define CHECK_LT(val1, val2, context) CHECK(val1 < val2, context)
#define CHECK_GE(val1, val2, context) CHECK(val1 >= val2, context)
#define CHECK_GT(val1, val2, context) CHECK(val1 > val2, context)

void setup_logger();

class Log {
private:
json internal;

inline std::string dump() {
std::string ret;
try {
ret = internal.dump(/*indent=*/2);
} catch (json::type_error &ex) {
throw std::runtime_error(fmt::format("JSON error for log '{}': {}",
internal["name"], ex.what()));
}
return ret;
}

public:
Log(const char *n) { internal["name"] = n; }
~Log() = default;

template <typename T> Log &with(const char *key, T value) {
internal["info"][key] = value;
return *this;
}

// Overload the index operator
json &operator[](const char *key) { return internal["info"][key]; };

inline void info() { spdlog::info("{}", this->dump()); }
inline void trace() { spdlog::trace("{}", this->dump()); }

template <typename... Arg>
inline void info(fmt::format_string<Arg...> fmt, Arg &&...args) {
auto msg = fmt::format(fmt, args...);
internal["message"] = msg;
spdlog::info("{}", this->dump());
}

template <typename... Arg>
inline void warn(fmt::format_string<Arg...> fmt, Arg &&...args) {
auto msg = fmt::format(fmt, args...);
internal["message"] = msg;
spdlog::warn("{}", this->dump());
}

template <typename... Arg>
inline void critical(fmt::format_string<Arg...> fmt, Arg &&...args) {
auto msg = fmt::format(fmt, args...);
internal["message"] = msg;
spdlog::critical("{}", this->dump());
}

template <typename... Arg>
inline void trace(fmt::format_string<Arg...> fmt, Arg &&...args) {
auto msg = fmt::format(fmt, args...);
internal["message"] = msg;
spdlog::trace("{}", this->dump());
};

template <typename... Arg>
inline void fatal(fmt::format_string<Arg...> fmt, Arg &&...args) {
auto msg = fmt::format(fmt, args...);
internal["message"] = msg;

spdlog::critical("{}", this->dump());
spdlog::shutdown();

throw std::runtime_error(msg);
};
};
Loading

0 comments on commit 907cd3b

Please sign in to comment.