summaryrefslogtreecommitdiff
path: root/src/sim/serialize.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/sim/serialize.cc')
-rw-r--r--src/sim/serialize.cc484
1 files changed, 484 insertions, 0 deletions
diff --git a/src/sim/serialize.cc b/src/sim/serialize.cc
new file mode 100644
index 000000000..c4ef124bb
--- /dev/null
+++ b/src/sim/serialize.cc
@@ -0,0 +1,484 @@
+/*
+ * Copyright (c) 2002-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <errno.h>
+
+#include <fstream>
+#include <list>
+#include <string>
+#include <vector>
+
+#include "base/inifile.hh"
+#include "base/misc.hh"
+#include "base/output.hh"
+#include "base/str.hh"
+#include "base/trace.hh"
+#include "sim/config_node.hh"
+#include "sim/eventq.hh"
+#include "sim/param.hh"
+#include "sim/serialize.hh"
+#include "sim/sim_events.hh"
+#include "sim/sim_exit.hh"
+#include "sim/sim_object.hh"
+
+using namespace std;
+
+int Serializable::ckptMaxCount = 0;
+int Serializable::ckptCount = 0;
+int Serializable::ckptPrevCount = -1;
+
+void
+Serializable::nameOut(ostream &os)
+{
+ os << "\n[" << name() << "]\n";
+}
+
+void
+Serializable::nameOut(ostream &os, const string &_name)
+{
+ os << "\n[" << _name << "]\n";
+}
+
+template <class T>
+void
+paramOut(ostream &os, const std::string &name, const T &param)
+{
+ os << name << "=";
+ showParam(os, param);
+ os << "\n";
+}
+
+
+template <class T>
+void
+paramIn(Checkpoint *cp, const std::string &section,
+ const std::string &name, T &param)
+{
+ std::string str;
+ if (!cp->find(section, name, str) || !parseParam(str, param)) {
+ fatal("Can't unserialize '%s:%s'\n", section, name);
+ }
+}
+
+
+template <class T>
+void
+arrayParamOut(ostream &os, const std::string &name,
+ const T *param, int size)
+{
+ os << name << "=";
+ if (size > 0)
+ showParam(os, param[0]);
+ for (int i = 1; i < size; ++i) {
+ os << " ";
+ showParam(os, param[i]);
+ }
+ os << "\n";
+}
+
+
+template <class T>
+void
+arrayParamIn(Checkpoint *cp, const std::string &section,
+ const std::string &name, T *param, int size)
+{
+ std::string str;
+ if (!cp->find(section, name, str)) {
+ fatal("Can't unserialize '%s:%s'\n", section, name);
+ }
+
+ // code below stolen from VectorParam<T>::parse().
+ // it would be nice to unify these somehow...
+
+ vector<string> tokens;
+
+ tokenize(tokens, str, ' ');
+
+ // Need this if we were doing a vector
+ // value.resize(tokens.size());
+
+ if (tokens.size() != size) {
+ fatal("Array size mismatch on %s:%s'\n", section, name);
+ }
+
+ for (int i = 0; i < tokens.size(); i++) {
+ // need to parse into local variable to handle vector<bool>,
+ // for which operator[] returns a special reference class
+ // that's not the same as 'bool&', (since it's a packed
+ // vector)
+ T scalar_value;
+ if (!parseParam(tokens[i], scalar_value)) {
+ string err("could not parse \"");
+
+ err += str;
+ err += "\"";
+
+ fatal(err);
+ }
+
+ // assign parsed value to vector
+ param[i] = scalar_value;
+ }
+}
+
+
+void
+objParamIn(Checkpoint *cp, const std::string &section,
+ const std::string &name, Serializable * &param)
+{
+ if (!cp->findObj(section, name, param)) {
+ fatal("Can't unserialize '%s:%s'\n", section, name);
+ }
+}
+
+
+#define INSTANTIATE_PARAM_TEMPLATES(type) \
+template void \
+paramOut(ostream &os, const std::string &name, type const &param); \
+template void \
+paramIn(Checkpoint *cp, const std::string &section, \
+ const std::string &name, type & param); \
+template void \
+arrayParamOut(ostream &os, const std::string &name, \
+ type const *param, int size); \
+template void \
+arrayParamIn(Checkpoint *cp, const std::string &section, \
+ const std::string &name, type *param, int size);
+
+INSTANTIATE_PARAM_TEMPLATES(signed char)
+INSTANTIATE_PARAM_TEMPLATES(unsigned char)
+INSTANTIATE_PARAM_TEMPLATES(signed short)
+INSTANTIATE_PARAM_TEMPLATES(unsigned short)
+INSTANTIATE_PARAM_TEMPLATES(signed int)
+INSTANTIATE_PARAM_TEMPLATES(unsigned int)
+INSTANTIATE_PARAM_TEMPLATES(signed long)
+INSTANTIATE_PARAM_TEMPLATES(unsigned long)
+INSTANTIATE_PARAM_TEMPLATES(signed long long)
+INSTANTIATE_PARAM_TEMPLATES(unsigned long long)
+INSTANTIATE_PARAM_TEMPLATES(bool)
+INSTANTIATE_PARAM_TEMPLATES(string)
+
+
+/////////////////////////////
+
+/// Container for serializing global variables (not associated with
+/// any serialized object).
+class Globals : public Serializable
+{
+ public:
+ const string name() const;
+ void serialize(ostream &os);
+ void unserialize(Checkpoint *cp);
+};
+
+/// The one and only instance of the Globals class.
+Globals globals;
+
+const string
+Globals::name() const
+{
+ return "Globals";
+}
+
+void
+Globals::serialize(ostream &os)
+{
+ nameOut(os);
+ SERIALIZE_SCALAR(curTick);
+
+ nameOut(os, "MainEventQueue");
+ mainEventQueue.serialize(os);
+}
+
+void
+Globals::unserialize(Checkpoint *cp)
+{
+ const string &section = name();
+ UNSERIALIZE_SCALAR(curTick);
+
+ mainEventQueue.unserialize(cp, "MainEventQueue");
+}
+
+void
+Serializable::serializeAll()
+{
+ string dir = Checkpoint::dir();
+ if (mkdir(dir.c_str(), 0775) == -1 && errno != EEXIST)
+ fatal("couldn't mkdir %s\n", dir);
+
+ string cpt_file = dir + Checkpoint::baseFilename;
+ ofstream outstream(cpt_file.c_str());
+ time_t t = time(NULL);
+ outstream << "// checkpoint generated: " << ctime(&t);
+
+ globals.serialize(outstream);
+ SimObject::serializeAll(outstream);
+
+ assert(Serializable::ckptPrevCount + 1 == Serializable::ckptCount);
+ Serializable::ckptPrevCount++;
+ if (ckptMaxCount && ++ckptCount >= ckptMaxCount)
+ SimExit(curTick + 1, "Maximum number of checkpoints dropped");
+
+}
+
+
+void
+Serializable::unserializeGlobals(Checkpoint *cp)
+{
+ globals.unserialize(cp);
+}
+
+
+class SerializeEvent : public Event
+{
+ protected:
+ Tick repeat;
+
+ public:
+ SerializeEvent(Tick _when, Tick _repeat);
+ virtual void process();
+ virtual void serialize(std::ostream &os)
+ {
+ panic("Cannot serialize the SerializeEvent");
+ }
+
+};
+
+SerializeEvent::SerializeEvent(Tick _when, Tick _repeat)
+ : Event(&mainEventQueue, Serialize_Pri), repeat(_repeat)
+{
+ setFlags(AutoDelete);
+ schedule(_when);
+}
+
+void
+SerializeEvent::process()
+{
+ Serializable::serializeAll();
+ if (repeat)
+ schedule(curTick + repeat);
+}
+
+const char *Checkpoint::baseFilename = "m5.cpt";
+
+static string checkpointDirBase;
+
+string
+Checkpoint::dir()
+{
+ // use csprintf to insert curTick into directory name if it
+ // appears to have a format placeholder in it.
+ return (checkpointDirBase.find("%") != string::npos) ?
+ csprintf(checkpointDirBase, curTick) : checkpointDirBase;
+}
+
+void
+Checkpoint::setup(Tick when, Tick period)
+{
+ new SerializeEvent(when, period);
+}
+
+class SerializeParamContext : public ParamContext
+{
+ private:
+ SerializeEvent *event;
+
+ public:
+ SerializeParamContext(const string &section);
+ ~SerializeParamContext();
+ void checkParams();
+};
+
+SerializeParamContext serialParams("serialize");
+
+Param<string> serialize_dir(&serialParams, "dir",
+ "dir to stick checkpoint in "
+ "(sprintf format with cycle #)");
+
+Param<Counter> serialize_cycle(&serialParams,
+ "cycle",
+ "cycle to serialize",
+ 0);
+
+Param<Counter> serialize_period(&serialParams,
+ "period",
+ "period to repeat serializations",
+ 0);
+
+Param<int> serialize_count(&serialParams, "count",
+ "maximum number of checkpoints to drop");
+
+SerializeParamContext::SerializeParamContext(const string &section)
+ : ParamContext(section), event(NULL)
+{ }
+
+SerializeParamContext::~SerializeParamContext()
+{
+}
+
+void
+SerializeParamContext::checkParams()
+{
+ checkpointDirBase = simout.resolve(serialize_dir);
+
+ // guarantee that directory ends with a '/'
+ if (checkpointDirBase[checkpointDirBase.size() - 1] != '/')
+ checkpointDirBase += "/";
+
+ if (serialize_cycle > 0)
+ Checkpoint::setup(serialize_cycle, serialize_period);
+
+ Serializable::ckptMaxCount = serialize_count;
+}
+
+void
+debug_serialize()
+{
+ Serializable::serializeAll();
+}
+
+void
+debug_serialize(Tick when)
+{
+ new SerializeEvent(when, 0);
+}
+
+////////////////////////////////////////////////////////////////////////
+//
+// SerializableClass member definitions
+//
+////////////////////////////////////////////////////////////////////////
+
+// Map of class names to SerializableBuilder creation functions.
+// Need to make this a pointer so we can force initialization on the
+// first reference; otherwise, some SerializableClass constructors
+// may be invoked before the classMap constructor.
+map<string,SerializableClass::CreateFunc> *SerializableClass::classMap = 0;
+
+// SerializableClass constructor: add mapping to classMap
+SerializableClass::SerializableClass(const string &className,
+ CreateFunc createFunc)
+{
+ if (classMap == NULL)
+ classMap = new map<string,SerializableClass::CreateFunc>();
+
+ if ((*classMap)[className])
+ {
+ cerr << "Error: simulation object class " << className << " redefined"
+ << endl;
+ fatal("");
+ }
+
+ // add className --> createFunc to class map
+ (*classMap)[className] = createFunc;
+}
+
+
+//
+//
+Serializable *
+SerializableClass::createObject(Checkpoint *cp,
+ const std::string &section)
+{
+ string className;
+
+ if (!cp->find(section, "type", className)) {
+ fatal("Serializable::create: no 'type' entry in section '%s'.\n",
+ section);
+ }
+
+ CreateFunc createFunc = (*classMap)[className];
+
+ if (createFunc == NULL) {
+ fatal("Serializable::create: no create function for class '%s'.\n",
+ className);
+ }
+
+ Serializable *object = createFunc(cp, section);
+
+ assert(object != NULL);
+
+ return object;
+}
+
+
+Serializable *
+Serializable::create(Checkpoint *cp, const std::string &section)
+{
+ Serializable *object = SerializableClass::createObject(cp, section);
+ object->unserialize(cp, section);
+ return object;
+}
+
+
+Checkpoint::Checkpoint(const std::string &cpt_dir, const std::string &path,
+ const ConfigNode *_configNode)
+ : db(new IniFile), basePath(path), configNode(_configNode), cptDir(cpt_dir)
+{
+ string filename = cpt_dir + "/" + Checkpoint::baseFilename;
+ if (!db->load(filename)) {
+ fatal("Can't load checkpoint file '%s'\n", filename);
+ }
+}
+
+
+bool
+Checkpoint::find(const std::string &section, const std::string &entry,
+ std::string &value)
+{
+ return db->find(section, entry, value);
+}
+
+
+bool
+Checkpoint::findObj(const std::string &section, const std::string &entry,
+ Serializable *&value)
+{
+ string path;
+
+ if (!db->find(section, entry, path))
+ return false;
+
+ if ((value = configNode->resolveSimObject(path)) != NULL)
+ return true;
+
+ if ((value = objMap[path]) != NULL)
+ return true;
+
+ return false;
+}
+
+
+bool
+Checkpoint::sectionExists(const std::string &section)
+{
+ return db->sectionExists(section);
+}