Commit 30f65e18 authored by phlo's avatar phlo

added memory map support to Simulator and Trace

uninitialized loads now return random values and are stored in a memory map
parent 10a02ba5
......@@ -201,7 +201,8 @@ int simulate (const char * name, const int argc, const char ** argv)
}
// run program with given seed
Trace::ptr trace = Simulator::simulate(programs, bound);
// TODO: MMap
Trace::ptr trace = Simulator::simulate(programs, {}, bound);
// print the result
std::cout << trace->print();
......
......@@ -112,6 +112,8 @@ struct Program : public std::vector<Instruction>
// equality
//
// TODO: really needed - rely on base class?
//
bool operator == (const Program &, const Program &);
bool operator != (const Program &, const Program &);
......
......@@ -27,9 +27,11 @@ inline void erase (C & container, T & val)
//------------------------------------------------------------------------------
Simulator::Simulator (const Program::List::ptr & p,
const std::shared_ptr<MMap> & mmap,
const size_t b) :
random(seed),
programs(p),
trace(std::make_unique<Trace>(p)),
trace(std::make_unique<Trace>(p, mmap)),
step(0),
bound(b ? b : static_cast<size_t>(-1)),
state(p->size(), State::running),
......@@ -132,22 +134,28 @@ void Simulator::sb_full (const bool value)
// Simulator::load -------------------------------------------------------------
word_t Simulator::load (word_t address, const bool indirect)
word_t Simulator::load (const word_t address)
{
word_t adr = trace->sb_adr(thread);
word_t val = trace->sb_val(thread);
bool full = trace->sb_full(thread);
if (sb_full() && sb_adr() == address)
return sb_val();
std::optional<word_t> value = trace->heap(address);
if (!value)
{
value = random();
trace->init_heap(address, *value);
}
return *value;
}
word_t Simulator::load (word_t address, const bool indirect)
{
if (indirect)
address =
full && adr == address
? val
: trace->heap(address);
address = load(address);
return
full && adr == address
? val
: trace->heap(address);
return load(address);
}
// Simulator::store ------------------------------------------------------------
......@@ -457,30 +465,28 @@ Trace::ptr Simulator::run (std::function<word_t()> scheduler)
// Simulator::simulate ---------------------------------------------------------
Trace::ptr Simulator::simulate (const Program::List::ptr & programs,
const std::shared_ptr<MMap> & mmap,
const size_t bound)
{
Simulator simulator {programs, bound};
// Mersenne Twister pseudo-random number generator
std::mt19937_64 random(seed);
Simulator sim {programs, mmap, bound};
// random scheduler
return simulator.run([&simulator, &random] {
simulator.thread = simulator.active[random() % simulator.active.size()];
return sim.run([&sim] {
sim.thread = sim.active[sim.random() % sim.active.size()];
assert(simulator.state[simulator.thread] == State::running);
assert(sim.state[sim.thread] == State::running);
// rule 2, 5, 7: store buffer may be flushed at any time or must be empty
if (simulator.sb_full())
if (sim.sb_full())
{
const Instruction & op =
(*simulator.programs)[simulator.thread][simulator.pc()];
(*sim.programs)[sim.thread][sim.pc()];
if (random() % 2 || op.requires_flush())
simulator.state[simulator.thread] = State::flushing;
if (sim.random() % 2 || op.requires_flush())
sim.state[sim.thread] = State::flushing;
}
return simulator.thread;
return sim.thread;
});
}
......@@ -488,19 +494,20 @@ Trace::ptr Simulator::simulate (const Program::List::ptr & programs,
Trace::ptr Simulator::replay (const Trace & trace, const size_t bound)
{
Simulator simulator {
Simulator sim {
trace.programs,
{},
bound && bound < trace.length ? bound : trace.length - 1
};
// replay scheduler
Trace::iterator iterator = trace.begin();
Trace::iterator it = trace.begin();
return simulator.run([&simulator, &iterator] {
if (iterator->flush)
simulator.state[iterator->thread] = State::flushing;
return sim.run([&sim, &it] {
if (it->flush)
sim.state[it->thread] = State::flushing;
return iterator++->thread;
return it++->thread;
});
}
......
......@@ -7,6 +7,7 @@
#include "instruction.hh"
// TODO: forward-declare
#include "mmap.hh"
#include "program.hh"
#include "trace.hh"
......@@ -42,6 +43,9 @@ struct Simulator
// members
//----------------------------------------------------------------------------
// Mersenne Twister pseudo-random number generator
std::mt19937_64 random;
// list of programs
//
Program::List::ptr programs;
......@@ -88,7 +92,9 @@ struct Simulator
// constructors
//----------------------------------------------------------------------------
Simulator (const Program::List::ptr & programs, size_t bound = 0);
Simulator (const Program::List::ptr & programs,
const std::shared_ptr<MMap> & mmap = {},
size_t bound = 0);
//----------------------------------------------------------------------------
// private functions
......@@ -127,7 +133,8 @@ struct Simulator
// load value from given address
//
word_t load (word_t address, bool indirect = false);
word_t load (word_t address);
word_t load (word_t address, bool indirect);
// store given value at address
//
......@@ -189,6 +196,7 @@ struct Simulator
// runs the simulator using a random trace
//
static Trace::ptr simulate (const Program::List::ptr & programs,
const std::shared_ptr<MMap> & mmap,
size_t bound = 0);
// replay the given trace (trace must match simulator configuration)
......
......@@ -45,18 +45,18 @@ TEST_RUN := run_all_tests
GTEST_FILTER = --gtest_filter=
# GTEST_FILTER += "*"
GTEST_FILTER += Encoder.*
GTEST_FILTER += smtlib.*
GTEST_FILTER += smtlib_Encoder.*
GTEST_FILTER += smtlib_Functional.*
GTEST_FILTER += smtlib_Relational.*
GTEST_FILTER += btor2.*
GTEST_FILTER += btor2_Encoder.*
# GTEST_FILTER += Encoder.*
# GTEST_FILTER += smtlib.*
# GTEST_FILTER += smtlib_Encoder.*
# GTEST_FILTER += smtlib_Functional.*
# GTEST_FILTER += smtlib_Relational.*
# GTEST_FILTER += btor2.*
# GTEST_FILTER += btor2_Encoder.*
GTEST_FILTER += Simulator.*
# GTEST_FILTER += Main.*
# GTEST_FILTER += Experimental.*
# GTEST_FILTER += Instruction.*
GTEST_FILTER += Program.*
# GTEST_FILTER += Program.*
GTEST_FILTER += Trace.*
GTEST_FILTER += MMap.*
# GTEST_FILTER += Shell.*
......
......@@ -31,7 +31,7 @@ struct Encoder: public ::testing::Test
Program create_program (const std::string code)
{
std::istringstream inbuf {code};
std::istringstream inbuf (code);
return Program(inbuf, "dummy.asm");
}
......
......@@ -18,11 +18,13 @@ struct Simulator : public ::testing::Test
Trace::ptr trace;
std::unique_ptr<ConcuBinE::Simulator> simulator;
void create_simulator(std::initializer_list<Program> programs)
void create_simulator(std::initializer_list<Program> && programs,
MMap && mmap = {})
{
simulator =
std::make_unique<ConcuBinE::Simulator>(
std::make_shared<Program::List>(programs));
std::make_shared<Program::List>(programs),
std::make_shared<MMap>(mmap));
}
};
......@@ -251,7 +253,7 @@ TEST_F(Simulator, run_race_condition)
checker.push_back(Instruction::create("EXIT", 1));
checker.push_back(Instruction::create("EXIT", 0));
create_simulator({checker, program, program});
create_simulator({checker, program, program}, {{1, 0}});
ASSERT_EQ(3, simulator->active.size());
ASSERT_EQ(3, simulator->programs->size());
......@@ -632,7 +634,7 @@ TEST_F(Simulator, simulate_increment_check)
programs->push_back(
create_from_file<Program>("data/increment.check.thread.n.asm"));
trace = ConcuBinE::Simulator::simulate(programs, 16);
trace = ConcuBinE::Simulator::simulate(programs, {}, 16);
ASSERT_EQ(
Trace::update_map<word_t>({{3,0}, {14, 0}}),
......@@ -655,7 +657,7 @@ TEST_F(Simulator, simulate_increment_cas)
programs->push_back(increment);
programs->push_back(increment);
trace = ConcuBinE::Simulator::simulate(programs, 16);
trace = ConcuBinE::Simulator::simulate(programs, {}, 16);
ASSERT_EQ(
Trace::update_map<word_t>({{3, 0}, {4, 0}, {12, 0}}),
......@@ -666,6 +668,62 @@ TEST_F(Simulator, simulate_increment_cas)
ASSERT_EQ(expected, trace->print());
}
TEST_F(Simulator, simulate_load_uninitialized)
{
Program::List::ptr programs = std::make_shared<Program::List>();
for (word_t i = 1; i <= 3; i++)
{
std::istringstream code ("LOAD " + std::to_string(i));
programs->push_back(Program(code, std::to_string(i) + ".asm"));
}
trace = ConcuBinE::Simulator::simulate(programs, {}, 0);
ASSERT_EQ(0, trace->exit);
ASSERT_EQ(6, trace->length);
ASSERT_EQ(
Trace::thread_map<word_t>({
{{0, 0}, {1, 63883}},
{{0, 0}, {2, 64750}},
{{0, 0}, {5, 18152}}
}),
trace->accu_updates);
ASSERT_EQ(
MMap({
{1, 63883},
{2, 64750},
{3, 18152},
}),
*trace->mmap);
}
TEST_F(Simulator, simulate_load_mmap)
{
Program::List::ptr programs = std::make_shared<Program::List>();
std::shared_ptr<MMap> mmap =
std::make_shared<MMap>(create_from_file<MMap>("data/init.mmap"));
for (word_t i = 1; i <= 3; i++)
{
std::istringstream code ("LOAD " + std::to_string(i));
programs->push_back(Program(code, std::to_string(i) + ".asm"));
}
trace = ConcuBinE::Simulator::simulate(programs, mmap, 0);
ASSERT_EQ(0, trace->exit);
ASSERT_EQ(6, trace->length);
ASSERT_EQ(
Trace::thread_map<word_t>({
{{0, 0}, {1, 1}},
{{0, 0}, {3, 2}},
{{0, 0}, {2, 3}}
}),
trace->accu_updates);
ASSERT_EQ(*mmap, *trace->mmap);
}
// Simulator::replay ===========================================================
TEST_F(Simulator, replay_increment_check)
......
This diff is collapsed.
......@@ -16,8 +16,10 @@ namespace ConcuBinE {
// constructors
//------------------------------------------------------------------------------
Trace::Trace (const Program::List::ptr & p) :
Trace::Trace (const Program::List::ptr & p,
const std::shared_ptr<MMap> & m) :
programs(p),
mmap(m),
length(0),
exit(0)
{
......@@ -46,9 +48,14 @@ Trace::Trace(std::istream & file, const std::string & path) :
if (line >> token && token.front() == '#')
continue;
// check if all programs have been parsed
// check for memory map (all programs have been parsed)
if (token == ".")
break;
{
if ((line >> token))
mmap = std::make_shared<MMap>(create_from_file<MMap>(token));
break;
}
try
{
......@@ -342,6 +349,16 @@ void Trace::init_register_states ()
sb_full_updates.resize(num_threads);
}
// Trace::init_heap ------------------------------------------------------------
void Trace::init_heap (const word_t address, const word_t value)
{
if (!mmap)
mmap = std::make_shared<MMap>();
(*mmap)[address] = value;
}
// Trace::push_back ------------------------------------------------------------
template <typename T>
......@@ -547,12 +564,15 @@ bool Trace::sb_full (const word_t thread) const
// Trace::heap -----------------------------------------------------------------
word_t Trace::heap (const word_t address) const
std::optional<word_t> Trace::heap (const word_t address) const
{
return
heap_val_updates.empty()
? 0 // TODO: add randomness!
: heap_val_updates.at(address).crbegin()->second;
if (heap_val_updates.find(address) != heap_val_updates.end())
return heap_val_updates.at(address).crbegin()->second;
if (mmap && mmap->find(address) != mmap->end())
return (*mmap)[address];
return {};
}
// Trace::size -----------------------------------------------------------------
......@@ -585,8 +605,13 @@ std::string Trace::print () const
for (const Program & program : *programs)
ss << program.path << eol;
// separator
ss << '.' << eol;
// separator + mmap
ss << '.';
if (mmap)
ss << ' ' << mmap->path;
ss << eol;
// column headers
ss << "# tid\tpc\tcmd\targ\taccu\tmem\tadr\tval\tfull\theap" << eol;
......@@ -734,8 +759,11 @@ void Trace::iterator::init_iterators (thread_state_iterators<T> & iterators,
// Trace::iterator::next_state -------------------------------------------------
template <typename T>
const T & Trace::iterator::next_state (update_map_iterator<T> & state)
T Trace::iterator::next_state (update_map_iterator<T> & state)
{
if (state.cur == state.end)
return 0;
auto next = std::next(state.cur);
while (next != state.end && next->first <= step)
......@@ -748,10 +776,13 @@ const T & Trace::iterator::next_state (update_map_iterator<T> & state)
const std::optional<Trace::cell_t> Trace::iterator::next_heap_state ()
{
const word_t adr = next_state(heap_adr);
if (heap_adr.cur != heap_adr.end)
{
const word_t adr = next_state(heap_adr);
if (heap_adr.cur->first == step.step)
return {{adr, next_state(heap_val[adr])}};
if (heap_adr.cur->first == step.step)
return {{adr, next_state(heap_val[adr])}};
}
return {};
}
......
......@@ -5,6 +5,7 @@
#include <unordered_map>
#include <vector>
#include "mmap.hh"
#include "program.hh"
namespace ConcuBinE {
......@@ -134,7 +135,7 @@ struct Trace
// return current thread state and advance
//
template <typename T>
const T & next_state (update_map_iterator<T> & updates);
T next_state (update_map_iterator<T> & updates);
// return current heap state update and advance
//
......@@ -180,12 +181,18 @@ struct Trace
// members
//----------------------------------------------------------------------------
// programs used to generate the trace
// programs used to produce the trace
//
// might be copied to another Trace during replay
// NOTE: copied during replay
//
Program::List::ptr programs;
// memory map used to produce the trace
//
// NOTE: copied during replay
//
std::shared_ptr<MMap> mmap;
// trace length
//
size_t length;
......@@ -237,7 +244,8 @@ struct Trace
// construct from simulator/solver
//
Trace (const Program::List::ptr & programs);
Trace (const Program::List::ptr & programs,
const std::shared_ptr<MMap> & mmap = {});
// construct from file
//
......@@ -253,6 +261,10 @@ struct Trace
void init_register_states (thread_map<T> & updates);
void init_register_states ();
// initialize heap state (and add to memory map)
//
void init_heap (word_t address, word_t value);
// append state update helper
//
template <typename T>
......@@ -297,7 +309,7 @@ struct Trace
// return most recent heap state
//
word_t heap (word_t address) const;
std::optional<word_t> heap (word_t address) const;
// return trace size (length)
//
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment