Added state saving and loading to nltool.

First step towards regression and unit tests. (nw)
This commit is contained in:
couriersud 2017-02-15 01:01:04 +01:00
parent 74e690d654
commit cc39da9c83
4 changed files with 184 additions and 27 deletions

View File

@ -31,7 +31,8 @@ namespace plib {
}
option::option(options &parent, pstring ashort, pstring along, pstring help, bool has_argument)
: option_base(parent, help), m_short(ashort), m_long(along), m_has_argument(has_argument)
: option_base(parent, help), m_short(ashort), m_long(along),
m_has_argument(has_argument), m_specified(false)
{
}
@ -149,13 +150,13 @@ namespace plib {
{
if (has_equal_arg)
{
if (opt->parse(opt_arg) != 0)
if (opt->do_parse(opt_arg) != 0)
return i;
}
else
{
i++; // FIXME: are there more arguments?
if (opt->parse(pstring(argv[i], pstring::UTF8)) != 0)
if (opt->do_parse(pstring(argv[i], pstring::UTF8)) != 0)
return i - 1;
}
}
@ -163,7 +164,7 @@ namespace plib {
{
if (has_equal_arg)
return i;
opt->parse("");
opt->do_parse("");
}
i++;
}

View File

@ -65,15 +65,25 @@ public:
/* no_argument options will be called with "" argument */
virtual int parse(const pstring &argument) = 0;
pstring short_opt() { return m_short; }
pstring long_opt() { return m_long; }
bool has_argument() { return m_has_argument ; }
bool was_specified() { return m_specified; }
int do_parse(const pstring &argument)
{
m_specified = true;
return parse(argument);
}
protected:
virtual int parse(const pstring &argument) = 0;
private:
pstring m_short;
pstring m_long;
bool m_has_argument;
bool m_specified;
};
class option_str : public option
@ -83,9 +93,11 @@ public:
: option(parent, ashort, along, help, true), m_val(defval)
{}
pstring operator ()() { return m_val; }
protected:
virtual int parse(const pstring &argument) override;
pstring operator ()() { return m_val; }
private:
pstring m_val;
};
@ -99,11 +111,12 @@ public:
m_limit = plib::psplit(limit, ":");
}
virtual int parse(const pstring &argument) override;
pstring operator ()() { return m_val; }
const std::vector<pstring> &limit() { return m_limit; }
protected:
virtual int parse(const pstring &argument) override;
private:
pstring m_val;
std::vector<pstring> m_limit;
@ -116,9 +129,11 @@ public:
: option(parent, ashort, along, help, false), m_val(false)
{}
bool operator ()() { return m_val; }
protected:
virtual int parse(const pstring &argument) override;
bool operator ()() { return m_val; }
private:
bool m_val;
};
@ -130,9 +145,11 @@ public:
: option(parent, ashort, along, help, true), m_val(defval)
{}
double operator ()() { return m_val; }
protected:
virtual int parse(const pstring &argument) override;
double operator ()() { return m_val; }
private:
double m_val;
};
@ -144,9 +161,11 @@ public:
: option(parent, ashort, along, help, true), m_val(defval)
{}
long operator ()() { return m_val; }
protected:
virtual int parse(const pstring &argument) override;
long operator ()() { return m_val; }
private:
long m_val;
};
@ -158,9 +177,11 @@ public:
: option(parent, ashort, along, help, true)
{}
std::vector<pstring> operator ()() { return m_val; }
protected:
virtual int parse(const pstring &argument) override;
std::vector<pstring> operator ()() { return m_val; }
private:
std::vector<pstring> m_val;
};

View File

@ -12,6 +12,8 @@
#include "pfmtlog.h"
#include "pexception.h"
#include <vector>
namespace plib {
// -----------------------------------------------------------------------------
// pstream: things common to all streams
@ -371,6 +373,76 @@ protected:
private:
};
// -----------------------------------------------------------------------------
// pbinary_writer_t: writer on top of ostream
// -----------------------------------------------------------------------------
class pbinary_writer : plib::nocopyassignmove
{
public:
explicit pbinary_writer(postream &strm) : m_strm(strm) {}
virtual ~pbinary_writer() {}
template <typename T>
void write(const T val)
{
m_strm.write(&val, sizeof(T));
}
void write(const pstring s)
{
write(s.blen());
m_strm.write(s.c_str(), s.blen());
}
template <typename T>
void write(const std::vector<T> val)
{
std::size_t sz = val.size();
write(sz);
m_strm.write(val.data(), sizeof(T) * sz);
}
private:
postream &m_strm;
};
class pbinary_reader : plib::nocopyassignmove
{
public:
explicit pbinary_reader(pistream &strm) : m_strm(strm) {}
virtual ~pbinary_reader() {}
template <typename T>
void read(T &val)
{
m_strm.read(&val, sizeof(T));
}
void read( pstring &s)
{
std::size_t sz = 0;
read(sz);
pstring::mem_t *buf = new pstring::mem_t[sz+1];
m_strm.read(buf, sz);
buf[sz] = 0;
s = pstring(buf, pstring::UTF8);
delete [] buf;
}
template <typename T>
void read(std::vector<T> &val)
{
std::size_t sz = 0;
read(sz);
val.resize(sz);
m_strm.read(val.data(), sizeof(T) * sz);
}
private:
pistream &m_strm;
};
}
#endif /* PSTREAM_H_ */

View File

@ -26,7 +26,7 @@ public:
opt_cmd (*this, "c", "cmd", "run", "run:convert:listdevices:static:header:docheader", "run|convert|listdevices|static|header"),
opt_file(*this, "f", "file", "-", "file to process (default is stdin)"),
opt_defines(*this, "D", "define", "predefine value as macro, e.g. -Dname=value. If '=value' is omitted predefine it as 1. This option may be specified repeatedly."),
opt_rfolders(*this, "r", "rom", "where to look for files"),
opt_rfolders(*this, "r", "rom", "where to look for data files"),
opt_verb(*this, "v", "verbose", "be verbose - this produces lots of output"),
opt_quiet(*this, "q", "quiet", "be quiet - no warnings"),
opt_version(*this, "", "version", "display version and exit"),
@ -37,6 +37,8 @@ public:
opt_ttr (*this, "t", "time_to_run", 1.0, "time to run the emulation (seconds)"),
opt_logs(*this, "l", "log" , "define terminal to log. This option may be specified repeatedly."),
opt_inp(*this, "i", "input", "", "input file to process (default is none)"),
opt_loadstate(*this,"", "loadstate", "", "load state from file and continue from there"),
opt_savestate(*this,"", "savestate", "", "save state to file at end of run"),
opt_grp4(*this, "Options for convert command", "These options are only used by the convert command."),
opt_type(*this, "y", "type", "spice", "spice:eagle:rinf", "type of file to be converted: spice,eagle,rinf"),
@ -61,6 +63,8 @@ public:
plib::option_double opt_ttr;
plib::option_vec opt_logs;
plib::option_str opt_inp;
plib::option_str opt_loadstate;
plib::option_str opt_savestate;
plib::option_group opt_grp4;
plib::option_str_limit opt_type;
plib::option_example opt_ex1;
@ -179,15 +183,16 @@ public:
}
}
void save_state()
template<typename T>
std::vector<T> save_state()
{
state().pre_save();
std::size_t size = 0;
for (auto const & s : state().save_list())
size += ((s->m_dt.size * s->m_count + sizeof(unsigned) - 1) / sizeof(unsigned));
size += ((s->m_dt.size * s->m_count + sizeof(T) - 1) / sizeof(T));
auto buf = plib::palloc_array<unsigned>(size);
auto p = buf;
auto buf = std::vector<T>(size);
auto p = buf.data();
for (auto const & s : state().save_list())
{
@ -196,8 +201,34 @@ public:
std::memcpy(p, s->m_ptr, sz );
else
log().fatal("found unsupported save element {1}\n", s->m_name);
p += ((sz + sizeof(unsigned) - 1) / sizeof(unsigned));
p += ((sz + sizeof(T) - 1) / sizeof(T));
}
return buf;
}
template<typename T>
void load_state(std::vector<T> &buf)
{
std::size_t size = 0;
for (auto const & s : state().save_list())
size += ((s->m_dt.size * s->m_count + sizeof(T) - 1) / sizeof(T));
if (buf.size() != size)
throw netlist::nl_exception("Size different during load state.");
auto p = buf.data();
for (auto const & s : state().save_list())
{
std::size_t sz = s->m_dt.size * s->m_count;
if (s->m_dt.is_float || s->m_dt.is_integral)
std::memcpy(s->m_ptr, p, sz );
else
log().fatal("found unsupported save element {1}\n", s->m_name);
p += ((sz + sizeof(T) - 1) / sizeof(T));
}
state().post_load();
rebuild_lists();
}
protected:
@ -295,33 +326,65 @@ void tool_app_t::run()
std::vector<input_t> inps = read_input(nt.setup(), opt_inp());
double ttr = opt_ttr();
netlist::netlist_time ttr = netlist::netlist_time::from_double(opt_ttr());
t.stop();
pout("startup time ==> {1:5.3f}\n", t.as_seconds() );
pout("runnning ...\n");
t.reset();
t.start();
unsigned pos = 0;
netlist::netlist_time nlt = netlist::netlist_time::zero();
// FIXME: error handling
if (opt_loadstate.was_specified())
{
plib::pifilestream strm(opt_loadstate());
plib::pbinary_reader reader(strm);
std::vector<char> loadstate;
reader.read(loadstate);
nt.load_state(loadstate);
pout("Loaded state, run will continue at {1:.6f}\n", nt.time().as_double());
}
while (pos < inps.size() && inps[pos].m_time < netlist::netlist_time::from_double(ttr))
unsigned pos = 0;
netlist::netlist_time nlt = nt.time();
while (pos < inps.size()
&& inps[pos].m_time < ttr
&& inps[pos].m_time >= nlt)
{
nt.process_queue(inps[pos].m_time - nlt);
inps[pos].setparam();
nlt = inps[pos].m_time;
pos++;
}
nt.process_queue(netlist::netlist_time::from_double(ttr) - nlt);
nt.save_state();
pout("runnning ...\n");
if (ttr > nlt)
nt.process_queue(ttr - nlt);
else
{
pout("end time {1:.6f} less than saved time {2:.6f}\n",
ttr.as_double(), nlt.as_double());
ttr = nlt;
}
if (opt_savestate.was_specified())
{
auto savestate = nt.save_state<char>();
plib::pofilestream strm(opt_savestate());
plib::pbinary_writer writer(strm);
writer.write(savestate);
}
nt.stop();
t.stop();
double emutime = t.as_seconds();
pout("{1:f} seconds emulation took {2:f} real time ==> {3:5.2f}%\n", ttr, emutime, ttr/emutime*100.0);
pout("{1:f} seconds emulation took {2:f} real time ==> {3:5.2f}%\n",
(ttr - nlt).as_double(), emutime,
(ttr - nlt).as_double() / emutime * 100.0);
}
void tool_app_t::static_compile()