Alot of changes to push towards ISA independence. Highlights are renaming of the...
[gem5.git] / sim / serialize.cc
index f838acc8d9c5a5487896a9604cedcbbe7984c9c3..ec72414985c9f1c65a75bbf0a2c68df732fe1089 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003 The Regents of The University of Michigan
+ * 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
  */
 
 #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 "base/inifile.hh"
 #include "sim/sim_events.hh"
+#include "sim/sim_exit.hh"
 #include "sim/sim_object.hh"
-#include "base/trace.hh"
 
 using namespace std;
 
-Serializer *Serializeable::serializer = NULL;
-
-Serializeable::Serializeable(const string &n)
-    : objName(n), serialized(false)
-{ }
-
-Serializeable::~Serializeable()
-{ }
+int Serializable::maxCount = 0;
+int Serializable::count = 0;
 
 void
-Serializeable::mark()
-{
-    if (!serialized)
-        serializer->add_object(this);
-
-    serialized = true;
-}
-
-void
-Serializeable::nameOut(ostream &os)
+Serializable::nameOut(ostream &os)
 {
     os << "\n[" << name() << "]\n";
 }
 
 void
-Serializeable::nameOut(ostream &os, const string &_name)
+Serializable::nameOut(ostream &os, const string &_name)
 {
     os << "\n[" << _name << "]\n";
 }
 
 template <class T>
 void
-paramOut(ostream &os, const std::string &name, const Tparam)
+paramOut(ostream &os, const std::string &name, const T &param)
 {
     os << name << "=";
     showParam(os, param);
@@ -88,11 +78,11 @@ paramOut(ostream &os, const std::string &name, const T& param)
 
 template <class T>
 void
-paramIn(const IniFile *db, const std::string &section,
-        const std::string &name, Tparam)
+paramIn(Checkpoint *cp, const std::string &section,
+        const std::string &name, T &param)
 {
     std::string str;
-    if (!db->find(section, name, str) || !parseParam(str, param)) {
+    if (!cp->find(section, name, str) || !parseParam(str, param)) {
         fatal("Can't unserialize '%s:%s'\n", section, name);
     }
 }
@@ -116,11 +106,11 @@ arrayParamOut(ostream &os, const std::string &name,
 
 template <class T>
 void
-arrayParamIn(const IniFile *db, const std::string &section,
+arrayParamIn(Checkpoint *cp, const std::string &section,
              const std::string &name, T *param, int size)
 {
     std::string str;
-    if (!db->find(section, name, str)) {
+    if (!cp->find(section, name, str)) {
         fatal("Can't unserialize '%s:%s'\n", section, name);
     }
 
@@ -159,178 +149,157 @@ arrayParamIn(const IniFile *db, const std::string &section,
 }
 
 
+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, const type &param);     \
+paramOut(ostream &os, const std::string &name, type const &param);     \
 template void                                                          \
-paramIn(const IniFile *db, const std::string &section,                 \
+paramIn(Checkpoint *cp, const std::string &section,                    \
         const std::string &name, type & param);                                \
 template void                                                          \
 arrayParamOut(ostream &os, const std::string &name,                    \
-              const type *param, int size);                            \
+              type const *param, int size);                            \
 template void                                                          \
-arrayParamIn(const IniFile *db, const std::string &section,            \
+arrayParamIn(Checkpoint *cp, const std::string &section,               \
              const std::string &name, type *param, int size);
 
-
-INSTANTIATE_PARAM_TEMPLATES(int8_t)
-INSTANTIATE_PARAM_TEMPLATES(uint8_t)
-INSTANTIATE_PARAM_TEMPLATES(int16_t)
-INSTANTIATE_PARAM_TEMPLATES(uint16_t)
-INSTANTIATE_PARAM_TEMPLATES(int32_t)
-INSTANTIATE_PARAM_TEMPLATES(uint32_t)
-INSTANTIATE_PARAM_TEMPLATES(int64_t)
-INSTANTIATE_PARAM_TEMPLATES(uint64_t)
+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)
 
 
-#if 0
-// unneeded?
-void
-Serializeable::childOut(const string &name, Serializeable *child)
-{
-    child->mark();
-    if (child->name() == "")
-        panic("child is unnamed");
-
-    out() << name << "=" << child->name() << "\n";
-}
-#endif
+/////////////////////////////
 
-void
-Serializeable::setName(const string &name)
+/// Container for serializing global variables (not associated with
+/// any serialized object).
+class Globals : public Serializable
 {
-    if (objName != "") {
-        cprintf("Renaming object '%s' to '%s'.\n", objName, name);
-    }
-
-    objName = name;
-}
-
-Serializer::Serializer()
-{ }
+  public:
+    const string name() const;
+    void serialize(ostream &os);
+    void unserialize(Checkpoint *cp);
+};
 
-Serializer::~Serializer()
-{ }
+/// The one and only instance of the Globals class.
+Globals globals;
 
-ostream &
-Serializer::out() const
+const string
+Globals::name() const
 {
-    if (!output)
-        panic("must set output before serializing");
-
-    return *output;
+    return "Globals";
 }
 
 void
-Serializer::add_object(Serializeable *obj)
+Globals::serialize(ostream &os)
 {
-    objects.push_back(obj);
+    nameOut(os);
+    SERIALIZE_SCALAR(curTick);
+
+    nameOut(os, "MainEventQueue");
+    mainEventQueue.serialize(os);
 }
 
 void
-Serializer::add_objects()
+Globals::unserialize(Checkpoint *cp)
 {
-    mainEventQueue.mark();
-
-    SimObject::SimObjectList::iterator i = SimObject::simObjectList.begin();
-    SimObject::SimObjectList::iterator end = SimObject::simObjectList.end();
+    const string &section = name();
+    UNSERIALIZE_SCALAR(curTick);
 
-    while (i != end) {
-        (*i)->mark();
-        ++i;
-    }
+    mainEventQueue.unserialize(cp, "MainEventQueue");
 }
 
 void
-Serializer::serialize(const string &f)
+Serializable::serializeAll()
 {
-    if (Serializeable::serializer != NULL)
-        panic("in process of serializing!");
-
-    Serializeable::serializer = this;
+    string dir = Checkpoint::dir();
+    if (mkdir(dir.c_str(), 0775) == -1 && errno != EEXIST)
+            fatal("couldn't mkdir %s\n", dir);
 
-    file = f;
-    string cpt_file = file + ".cpt";
-    output = new ofstream(cpt_file.c_str());
+    string cpt_file = dir + Checkpoint::baseFilename;
+    ofstream outstream(cpt_file.c_str());
     time_t t = time(NULL);
-    *output << "// checkpoint generated: " << ctime(&t);
-
-    serlist_t list;
-
-    add_objects();
-    while (!objects.empty()) {
-        Serializeable *serial = objects.front();
-        DPRINTF(Serialize, "Naming children of %s\n", serial->name());
-        serial->nameChildren();
-        objects.pop_front();
-        list.push_back(serial);
-    }
-
-    while (!list.empty()) {
-        list.front()->serialized = false;
-        list.pop_front();
-    }
+    outstream << "// checkpoint generated: " << ctime(&t);
 
-    add_objects();
-    while (!objects.empty()) {
-        Serializeable *obj = objects.front();
-        DPRINTF(Serialize, "Serializing %s\n", obj->name());
-        obj->nameOut(out());
-        obj->serialize(out());
-        objects.pop_front();
-        list.push_back(obj);
-    }
+    globals.serialize(outstream);
+    SimObject::serializeAll(outstream);
 
-    while (!list.empty()) {
-        list.front()->serialized = false;
-        list.pop_front();
-    }
+    if (maxCount && ++count >= maxCount)
+        SimExit(curTick + 1, "Maximum number of checkpoints dropped");
+}
 
-    Serializeable::serializer = NULL;
 
-    delete output;
-    output = NULL;
-    file = "";
+void
+Serializable::unserializeGlobals(Checkpoint *cp)
+{
+    globals.unserialize(cp);
 }
 
+
 class SerializeEvent : public Event
 {
   protected:
-    string file;
+    Tick repeat;
 
   public:
-    SerializeEvent(EventQueue *q, Tick when, const string &file);
-    ~SerializeEvent();
-
+    SerializeEvent(Tick _when, Tick _repeat);
     virtual void process();
-    virtual void serialize(std::ostream &os);
+    virtual void serialize(std::ostream &os)
+    {
+        panic("Cannot serialize the SerializeEvent");
+    }
+
 };
 
-SerializeEvent::SerializeEvent(EventQueue *q, Tick when, const string &f)
-    : Event(q), file(f)
+SerializeEvent::SerializeEvent(Tick _when, Tick _repeat)
+    : Event(&mainEventQueue, Serialize_Pri), repeat(_repeat)
 {
     setFlags(AutoDelete);
-    schedule(when);
+    schedule(_when);
 }
 
-SerializeEvent::~SerializeEvent()
+void
+SerializeEvent::process()
 {
+    Serializable::serializeAll();
+    if (repeat)
+        schedule(curTick + repeat);
 }
 
-void
-SerializeEvent::process()
+const char *Checkpoint::baseFilename = "m5.cpt";
+
+static string checkpointDirBase;
+
+string
+Checkpoint::dir()
 {
-    Serializer serial;
-    serial.serialize(file);
-    new SimExitEvent("Serialization caused exit");
+    // 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
-SerializeEvent::serialize(ostream &os)
+Checkpoint::setup(Tick when, Tick period)
 {
-    panic("Cannot serialize the SerializeEvent");
+    new SerializeEvent(when, period);
 }
 
 class SerializeParamContext : public ParamContext
@@ -346,18 +315,22 @@ class SerializeParamContext : public ParamContext
 
 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<string> serialize_file(&serialParams,
-                             "file",
-                             "file to write to", "");
+Param<Counter> serialize_period(&serialParams,
+                                "period",
+                                "period to repeat serializations",
+                                0);
 
-// Copy filename into regular string so we can export it without
-// having to include param.hh all over the place.
-string serializeFilename;
+Param<int> serialize_count(&serialParams, "count",
+                           "maximum number of checkpoints to drop");
 
 SerializeParamContext::SerializeParamContext(const string &section)
     : ParamContext(section), event(NULL)
@@ -370,41 +343,48 @@ SerializeParamContext::~SerializeParamContext()
 void
 SerializeParamContext::checkParams()
 {
-    serializeFilename = serialize_file;
-    if (!serializeFilename.empty() && serialize_cycle > 0)
-        event = new SerializeEvent(&mainEventQueue, serialize_cycle,
-                                   serializeFilename);
+    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::maxCount = serialize_count;
 }
 
 void
-debug_serialize(const char *file)
+debug_serialize()
 {
-    Serializer serial;
-    serial.serialize(file);
-    new SimExitEvent("Serialization caused exit");
+    Serializable::serializeAll();
 }
 
-
-
+void
+debug_serialize(Tick when)
+{
+    new SerializeEvent(when, 0);
+}
 
 ////////////////////////////////////////////////////////////////////////
 //
-// SerializeableClass member definitions
+// SerializableClass member definitions
 //
 ////////////////////////////////////////////////////////////////////////
 
-// Map of class names to SerializeableBuilder creation functions.
+// 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 SerializeableClass constructors
+// first reference; otherwise, some SerializableClass constructors
 // may be invoked before the classMap constructor.
-map<string,SerializeableClass::CreateFunc> *SerializeableClass::classMap = 0;
+map<string,SerializableClass::CreateFunc> *SerializableClass::classMap = 0;
 
-// SerializeableClass constructor: add mapping to classMap
-SerializeableClass::SerializeableClass(const string &className,
+// SerializableClass constructor: add mapping to classMap
+SerializableClass::SerializableClass(const string &className,
                                        CreateFunc createFunc)
 {
     if (classMap == NULL)
-        classMap = new map<string,SerializeableClass::CreateFunc>();
+        classMap = new map<string,SerializableClass::CreateFunc>();
 
     if ((*classMap)[className])
     {
@@ -420,42 +400,81 @@ SerializeableClass::SerializeableClass(const string &className,
 
 //
 //
-Serializeable *
-SerializeableClass::createObject(IniFile &configDB,
-                                 const string &configClassName)
+Serializable *
+SerializableClass::createObject(Checkpoint *cp,
+                                 const std::string &section)
 {
-    // find simulation object class name from configuration class
-    // (specified by 'type=' parameter)
-    string simObjClassName;
+    string className;
 
-    if (!configDB.findDefault(configClassName, "type", simObjClassName)) {
-        cerr << "Configuration class '" << configClassName << "' not found."
-             << endl;
-        abort();
+    if (!cp->find(section, "type", className)) {
+        fatal("Serializable::create: no 'type' entry in section '%s'.\n",
+              section);
     }
 
-    // look up className to get appropriate createFunc
-    if (classMap->find(simObjClassName) == classMap->end()) {
-        cerr << "Simulator object class '" << simObjClassName << "' not found."
-             << endl;
-        abort();
+    CreateFunc createFunc = (*classMap)[className];
+
+    if (createFunc == NULL) {
+        fatal("Serializable::create: no create function for class '%s'.\n",
+              className);
     }
 
-    CreateFunc createFunc = (*classMap)[simObjClassName];
+    Serializable *object = createFunc(cp, section);
 
-    // builder instance
-    SerializeableBuilder *objectBuilder = (*createFunc)();
+    assert(object != NULL);
 
-    assert(objectBuilder != NULL);
+    return object;
+}
 
-    // now create the actual simulation object
-    Serializeable *object = objectBuilder->create();
 
-    assert(object != NULL);
+Serializable *
+Serializable::create(Checkpoint *cp, const std::string &section)
+{
+    Serializable *object = SerializableClass::createObject(cp, section);
+    object->unserialize(cp, section);
+    return object;
+}
 
-    // done with the SerializeableBuilder now
-    delete objectBuilder;
 
-    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);
+}