Skip to content

Commit

Permalink
Add support for footprint and in-memory inputs (#145)
Browse files Browse the repository at this point in the history
Since Verilator v4.218 by default uses c++14, the code is
compiled with warnings. However, with newer versions of
Verilator, they compile without warnings.
  • Loading branch information
poemonsense authored Sep 10, 2023
1 parent 911a1fc commit 5906a9e
Show file tree
Hide file tree
Showing 5 changed files with 246 additions and 1 deletion.
11 changes: 11 additions & 0 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -119,3 +119,14 @@ jobs:
make emu
./build/emu -e 0 -i ./ready-to-run/microbench.bin --diff ./ready-to-run/riscv64-nemu-interpreter-so --dump-difftrace microbench
./build/emu -e 0 -i ./ready-to-run/microbench.bin --diff ./ready-to-run/riscv64-nemu-interpreter-so --load-difftrace microbench
- name: Difftest with Footprints
run: |
cd $GITHUB_WORKSPACE/../xs-env
source ./env.sh
cd $GITHUB_WORKSPACE/../xs-env/NutShell
source ./env.sh
make clean
make emu
./build/emu -e 0 -i ./ready-to-run/microbench.bin --diff ./ready-to-run/riscv64-nemu-interpreter-so --dump-footprints microbench.bin
./build/emu -e 0 -i microbench.bin --diff ./ready-to-run/riscv64-nemu-interpreter-so --as-footprints
134 changes: 134 additions & 0 deletions src/test/csrc/common/ram.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,45 @@ uint64_t StdinReader::read_all(void *dest, uint64_t max_bytes) {
return n_read;
}

// wim@[base_addr],[wim_size]
uint64_t *SimMemory::is_wim(const char *image, uint64_t &wim_size) {
const char wim_prefix[] = "wim";
const char *wim_info = strchr(image, '@');
if (!wim_info || strncmp(wim_prefix, image, sizeof(wim_prefix) - 1)) {
return nullptr;
}
wim_info++;
uint64_t base_addr = strtoul(wim_info, (char **)&wim_info, 16);
if (base_addr % sizeof(uint64_t) || *wim_info != '+') {
return nullptr;
}
wim_info++;
wim_size = strtoul(wim_info, (char **)&wim_info, 16);
if (*wim_info) {
return nullptr;
}
return (uint64_t *)base_addr;
}

uint64_t WimReader::next() {
if (index + sizeof(uint64_t) > size) {
return 0;
}
uint64_t value = base_addr[index / sizeof(uint64_t)];
index += sizeof(uint64_t);
return value;
}

uint64_t WimReader::read_all(void *dest, uint64_t max_bytes) {
uint64_t n_read = size - index;
if (n_read >= max_bytes) {
n_read = max_bytes;
}
memcpy(dest, base_addr, n_read);
index += n_read;
return n_read;
}

FileReader::FileReader(const char *filename) : file(filename, std::ios::binary) {
if (!file.is_open()) {
std::cerr << "Cannot open '" << filename << "'\n";
Expand Down Expand Up @@ -179,6 +218,10 @@ InputReader *SimMemory::createInputReader(const char *image) {
if (is_stdin(image)) {
return new StdinReader();
}
uint64_t n_bytes;
if (uint64_t *ptr = is_wim(image, n_bytes)) {
return new WimReader(ptr, n_bytes);
}
return new FileReader(image);
}

Expand Down Expand Up @@ -277,6 +320,97 @@ void pmem_write(uint64_t waddr, uint64_t wdata) {
return ram_write_helper(waddr / sizeof(uint64_t), wdata, -1UL, 1);
}

MmapMemoryWithFootprints::MmapMemoryWithFootprints(const char *image, uint64_t n_bytes, const char *footprints_name)
: MmapMemory(image, n_bytes) {
uint64_t n_touched = memory_size / sizeof(uint64_t);
touched = (uint8_t *)mmap(NULL, n_touched, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0);
footprints_file.open(footprints_name, std::ios::binary);
if (!footprints_file.is_open()) {
printf("Cannot open %s as the footprints file\n", footprints_name);
assert(0);
}
}

MmapMemoryWithFootprints::~MmapMemoryWithFootprints() {
munmap(touched, memory_size / sizeof(uint64_t));
footprints_file.close();
}

uint64_t& MmapMemoryWithFootprints::at(uint64_t index) {
uint64_t &data = MmapMemory::at(index);
if (!touched[index]) {
footprints_file.write(reinterpret_cast<const char*>(&data), sizeof(data));
touched[index] = 1;
}
return data;
}

FootprintsMemory::FootprintsMemory(const char *footprints_name, uint64_t n_bytes)
: SimMemory(n_bytes), reader(createInputReader(footprints_name)), n_accessed(0) {
printf("The image is %s\n", footprints_name);
add_callback([this](uint64_t, uint64_t) { this->on_access(this->n_accessed / sizeof(uint64_t)); });
}

FootprintsMemory::~FootprintsMemory() {
delete reader;
}

uint64_t& FootprintsMemory::at(uint64_t index) {
if (ram.find(index) == ram.end()) {
uint64_t value = reader->next();
ram[index] = value;
for (auto& cb : callbacks) {
cb(index, value);
}
n_accessed += sizeof(uint64_t);
}
return ram[index];
}

LinearizedFootprintsMemory::LinearizedFootprintsMemory(
const char *footprints_name,
uint64_t n_bytes,
const char *linear_name)
: FootprintsMemory(footprints_name, n_bytes), linear_name(linear_name), n_touched(0) {
linear_memory = (uint64_t*)mmap(nullptr, n_bytes,
PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
if (linear_memory == MAP_FAILED) {
perror("mmap");
exit(EXIT_FAILURE);
}
add_callback([this](uint64_t index, uint64_t value) {
if (value) {
linear_memory[index] = value;
n_touched++;
}
});
}

LinearizedFootprintsMemory::~LinearizedFootprintsMemory() {
save_linear_memory(linear_name);
munmap(linear_memory, get_size());
}

void LinearizedFootprintsMemory::save_linear_memory(const char* filename) {
std::ofstream out_file(filename, std::ios::out | std::ios::binary);
if (!out_file) {
std::cerr << "Cannot open output file: " << filename << std::endl;
return;
}
// Find the position of the last non-zero element
uint64_t last_nonzero_index = 0, nonzero_count = 0;
for (uint64_t i = 0; i < get_size() / sizeof(uint64_t) && nonzero_count < n_touched; ++i) {
if (linear_memory[i] != 0) {
last_nonzero_index = i;
nonzero_count++;
}
}
// Even if all all zeros, we still write one uint64_t.
size_t n_bytes = (last_nonzero_index + 1) * sizeof(uint64_t);
out_file.write(reinterpret_cast<char*>(linear_memory), n_bytes);
out_file.close();
}

#ifdef WITH_DRAMSIM3
void dramsim3_init() {
#if !defined(DRAMSIM3_CONFIG) || !defined(DRAMSIM3_OUTDIR)
Expand Down
71 changes: 71 additions & 0 deletions src/test/csrc/common/ram.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,19 @@ class StdinReader : public InputReader {
uint64_t n_bytes;
};

class WimReader : public InputReader {
public:
WimReader(uint64_t *addr, uint64_t size) : base_addr(addr), size(size), index(0) {}
~WimReader() {}
uint64_t len() { return size; };
uint64_t next();
uint64_t read_all(void *dest, uint64_t max_bytes = -1ULL);

private:
uint64_t *base_addr;
uint64_t size, index;
};

class FileReader : public InputReader {
public:
FileReader(const char *filename);
Expand Down Expand Up @@ -126,6 +139,64 @@ class MmapMemory : public SimMemory {
uint64_t *as_ptr() { return ram; }
};

class MmapMemoryWithFootprints : public MmapMemory {
private:
uint8_t *touched;
std::ofstream footprints_file;

public:
MmapMemoryWithFootprints(const char *image, uint64_t n_bytes, const char *footprints_name);
~MmapMemoryWithFootprints();
uint64_t& at(uint64_t index);
};

class FootprintsMemory : public SimMemory {
private:
std::unordered_map<uint64_t, uint64_t> ram;
std::ifstream footprints_file;
std::vector<std::function<void(uint64_t, uint64_t)>> callbacks;
InputReader *reader;
uint64_t n_accessed;

protected:
virtual inline uint64_t get_img_size() {
return reader->len();
}
void add_callback(std::function<void(uint64_t, uint64_t)> func) {
callbacks.push_back(func);
}

public:
FootprintsMemory(const char *footprints_name, uint64_t n_bytes);
~FootprintsMemory();
uint64_t& at(uint64_t index);
void clone(std::function<void(void*, uint64_t)> func, bool skip_zero = false) {
printf("clone_instant not support by FootprintsMemory\n");
assert(0);
}
void clone_on_demand(std::function<void(uint64_t, void*, size_t)> func, bool skip_zero = false) {
auto cb = [func](uint64_t index, uint64_t value) {
func(index * sizeof(uint64_t), &value, sizeof(uint64_t));
};
for (const auto& [index, value] : ram) {
cb(index, value);
}
add_callback(cb);
}
};

class LinearizedFootprintsMemory : public FootprintsMemory {
private:
const char *linear_name;
uint64_t* linear_memory;
uint64_t n_touched; // for performance opt

public:
LinearizedFootprintsMemory(const char *footprints_name, uint64_t n_bytes, const char *linear_name);
~LinearizedFootprintsMemory();
void save_linear_memory(const char* filename);
};

extern SimMemory *simMemory;

#ifdef WITH_DRAMSIM3
Expand Down
28 changes: 27 additions & 1 deletion src/test/csrc/verilator/emu.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,9 @@ static inline void print_help(const char *file) {
#endif // VM_COVERAGE
printf(" --load-difftrace=NAME load from trace NAME\n");
printf(" --dump-difftrace=NAME dump to trace NAME\n");
printf(" --dump-footprints=NAME dump memory access footprints to NAME\n");
printf(" --as-footprints load the image as memory access footprints\n");
printf(" --dump-linearized=NAME dump the linearized footprints to NAME\n");
printf(" -h, --help print program help info\n");
printf("\n");
}
Expand Down Expand Up @@ -137,6 +140,9 @@ inline EmuArgs parse_args(int argc, const char *argv[]) {
{ "dump-commit-trace", 0, NULL, 0 },
{ "load-difftrace", 1, NULL, 0 },
{ "dump-difftrace", 1, NULL, 0 },
{ "dump-footprints", 1, NULL, 0 },
{ "as-footprints", 0, NULL, 0 },
{ "dump-linearized", 1, NULL, 0 },
{ "seed", 1, NULL, 's' },
{ "max-cycles", 1, NULL, 'C' },
{ "fork-interval", 1, NULL, 'X' },
Expand Down Expand Up @@ -204,6 +210,9 @@ inline EmuArgs parse_args(int argc, const char *argv[]) {
case 16: args.enable_commit_trace = true; continue;
case 17: args.trace_name = optarg; args.trace_is_read = true; continue;
case 18: args.trace_name = optarg; args.trace_is_read = false; continue;
case 19: args.footprints_name = optarg; continue;
case 20: args.image_as_footprints = true; continue;
case 21: args.linearized_name = optarg; continue;
}
// fall through
default:
Expand Down Expand Up @@ -316,7 +325,24 @@ Emulator::Emulator(int argc, const char *argv[]):
if (args.ram_size) {
ram_size = parse_and_update_ramsize(args.ram_size);
}
simMemory = new MmapMemory(args.image, ram_size);
// footprints
if (args.image_as_footprints) {
if (args.linearized_name) {
simMemory = new LinearizedFootprintsMemory(args.image, ram_size, args.linearized_name);
}
else {
simMemory = new FootprintsMemory(args.image, ram_size);
}
}
// normal linear memory
else {
if (args.footprints_name) {
simMemory = new MmapMemoryWithFootprints(args.image, ram_size, args.footprints_name);
}
else {
simMemory = new MmapMemory(args.image, ram_size);
}
}

#ifdef ENABLE_CHISEL_DB
init_db(args.dump_db, (args.select_db != NULL), args.select_db);
Expand Down
3 changes: 3 additions & 0 deletions src/test/csrc/verilator/emu.h
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,8 @@ struct EmuArgs {
const char *flash_bin = nullptr;
const char *select_db = nullptr;
const char *trace_name = nullptr;
const char *footprints_name = nullptr;
const char *linearized_name = nullptr;
bool enable_waveform = false;
bool enable_ref_trace = false;
bool enable_commit_trace = false;
Expand All @@ -73,6 +75,7 @@ struct EmuArgs {
bool dump_db = false;
bool trace_is_read = true;
bool dump_coverage = false;
bool image_as_footprints = false;
};

enum {
Expand Down

0 comments on commit 5906a9e

Please sign in to comment.