serialize.cc revision 4762
12SN/A/*
21762SN/A * Copyright (c) 2002-2005 The Regents of The University of Michigan
32SN/A * All rights reserved.
42SN/A *
52SN/A * Redistribution and use in source and binary forms, with or without
62SN/A * modification, are permitted provided that the following conditions are
72SN/A * met: redistributions of source code must retain the above copyright
82SN/A * notice, this list of conditions and the following disclaimer;
92SN/A * redistributions in binary form must reproduce the above copyright
102SN/A * notice, this list of conditions and the following disclaimer in the
112SN/A * documentation and/or other materials provided with the distribution;
122SN/A * neither the name of the copyright holders nor the names of its
132SN/A * contributors may be used to endorse or promote products derived from
142SN/A * this software without specific prior written permission.
152SN/A *
162SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
172SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
182SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
192SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
202SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
212SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
222SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
232SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
242SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
252SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
262SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
272665Ssaidi@eecs.umich.edu *
282760Sbinkertn@umich.edu * Authors: Nathan Binkert
292760Sbinkertn@umich.edu *          Erik Hallnor
302665Ssaidi@eecs.umich.edu *          Steve Reinhardt
312SN/A */
322SN/A
332SN/A#include <sys/time.h>
34363SN/A#include <sys/types.h>
35363SN/A#include <sys/stat.h>
361354SN/A#include <errno.h>
372SN/A
382SN/A#include <fstream>
392SN/A#include <list>
402SN/A#include <string>
412SN/A#include <vector>
422SN/A
43363SN/A#include "base/inifile.hh"
4456SN/A#include "base/misc.hh"
451388SN/A#include "base/output.hh"
46217SN/A#include "base/str.hh"
47363SN/A#include "base/trace.hh"
4856SN/A#include "sim/eventq.hh"
4956SN/A#include "sim/serialize.hh"
5056SN/A#include "sim/sim_events.hh"
511638SN/A#include "sim/sim_exit.hh"
5256SN/A#include "sim/sim_object.hh"
532SN/A
542356SN/A// For stat reset hack
552356SN/A#include "sim/stat_control.hh"
562356SN/A
572SN/Ausing namespace std;
582SN/A
594000Ssaidi@eecs.umich.eduextern SimObject *resolveSimObject(const string &);
604000Ssaidi@eecs.umich.edu
614762Snate@binkert.org//
624762Snate@binkert.org// The base implementations use to_number for parsing and '<<' for
634762Snate@binkert.org// displaying, suitable for integer types.
644762Snate@binkert.org//
654762Snate@binkert.orgtemplate <class T>
664762Snate@binkert.orgbool
674762Snate@binkert.orgparseParam(const string &s, T &value)
684762Snate@binkert.org{
694762Snate@binkert.org    return to_number(s, value);
704762Snate@binkert.org}
714762Snate@binkert.org
724762Snate@binkert.orgtemplate <class T>
734762Snate@binkert.orgvoid
744762Snate@binkert.orgshowParam(ostream &os, const T &value)
754762Snate@binkert.org{
764762Snate@binkert.org    os << value;
774762Snate@binkert.org}
784762Snate@binkert.org
794762Snate@binkert.org//
804762Snate@binkert.org// Template specializations:
814762Snate@binkert.org// - char (8-bit integer)
824762Snate@binkert.org// - floating-point types
834762Snate@binkert.org// - bool
844762Snate@binkert.org// - string
854762Snate@binkert.org//
864762Snate@binkert.org
874762Snate@binkert.org// Treat 8-bit ints (chars) as ints on output, not as chars
884762Snate@binkert.orgtemplate <>
894762Snate@binkert.orgvoid
904762Snate@binkert.orgshowParam(ostream &os, const char &value)
914762Snate@binkert.org{
924762Snate@binkert.org    os << (int)value;
934762Snate@binkert.org}
944762Snate@binkert.org
954762Snate@binkert.org
964762Snate@binkert.orgtemplate <>
974762Snate@binkert.orgvoid
984762Snate@binkert.orgshowParam(ostream &os, const unsigned char &value)
994762Snate@binkert.org{
1004762Snate@binkert.org    os << (unsigned int)value;
1014762Snate@binkert.org}
1024762Snate@binkert.org
1034762Snate@binkert.org
1044762Snate@binkert.org// Use sscanf() for FP types as to_number() only handles integers
1054762Snate@binkert.orgtemplate <>
1064762Snate@binkert.orgbool
1074762Snate@binkert.orgparseParam(const string &s, float &value)
1084762Snate@binkert.org{
1094762Snate@binkert.org    return (sscanf(s.c_str(), "%f", &value) == 1);
1104762Snate@binkert.org}
1114762Snate@binkert.org
1124762Snate@binkert.orgtemplate <>
1134762Snate@binkert.orgbool
1144762Snate@binkert.orgparseParam(const string &s, double &value)
1154762Snate@binkert.org{
1164762Snate@binkert.org    return (sscanf(s.c_str(), "%lf", &value) == 1);
1174762Snate@binkert.org}
1184762Snate@binkert.org
1194762Snate@binkert.orgtemplate <>
1204762Snate@binkert.orgbool
1214762Snate@binkert.orgparseParam(const string &s, bool &value)
1224762Snate@binkert.org{
1234762Snate@binkert.org    const string &ls = to_lower(s);
1244762Snate@binkert.org
1254762Snate@binkert.org    if (ls == "true") {
1264762Snate@binkert.org        value = true;
1274762Snate@binkert.org        return true;
1284762Snate@binkert.org    }
1294762Snate@binkert.org
1304762Snate@binkert.org    if (ls == "false") {
1314762Snate@binkert.org        value = false;
1324762Snate@binkert.org        return true;
1334762Snate@binkert.org    }
1344762Snate@binkert.org
1354762Snate@binkert.org    return false;
1364762Snate@binkert.org}
1374762Snate@binkert.org
1384762Snate@binkert.org// Display bools as strings
1394762Snate@binkert.orgtemplate <>
1404762Snate@binkert.orgvoid
1414762Snate@binkert.orgshowParam(ostream &os, const bool &value)
1424762Snate@binkert.org{
1434762Snate@binkert.org    os << (value ? "true" : "false");
1444762Snate@binkert.org}
1454762Snate@binkert.org
1464762Snate@binkert.org
1474762Snate@binkert.org// String requires no processing to speak of
1484762Snate@binkert.orgtemplate <>
1494762Snate@binkert.orgbool
1504762Snate@binkert.orgparseParam(const string &s, string &value)
1514762Snate@binkert.org{
1524762Snate@binkert.org    value = s;
1534762Snate@binkert.org    return true;
1544762Snate@binkert.org}
1554762Snate@binkert.org
1562287SN/Aint Serializable::ckptMaxCount = 0;
1572287SN/Aint Serializable::ckptCount = 0;
1582287SN/Aint Serializable::ckptPrevCount = -1;
1591637SN/A
1602SN/Avoid
161395SN/ASerializable::nameOut(ostream &os)
1622SN/A{
163217SN/A    os << "\n[" << name() << "]\n";
1642SN/A}
1652SN/A
1662SN/Avoid
167395SN/ASerializable::nameOut(ostream &os, const string &_name)
1682SN/A{
169217SN/A    os << "\n[" << _name << "]\n";
1702SN/A}
1712SN/A
172217SN/Atemplate <class T>
1732SN/Avoid
174502SN/AparamOut(ostream &os, const std::string &name, const T &param)
1752SN/A{
176217SN/A    os << name << "=";
177217SN/A    showParam(os, param);
178217SN/A    os << "\n";
1792SN/A}
1802SN/A
181217SN/A
182217SN/Atemplate <class T>
183217SN/Avoid
184237SN/AparamIn(Checkpoint *cp, const std::string &section,
185502SN/A        const std::string &name, T &param)
1862SN/A{
187217SN/A    std::string str;
188237SN/A    if (!cp->find(section, name, str) || !parseParam(str, param)) {
189217SN/A        fatal("Can't unserialize '%s:%s'\n", section, name);
190217SN/A    }
1912SN/A}
1922SN/A
193217SN/A
194217SN/Atemplate <class T>
195217SN/Avoid
196217SN/AarrayParamOut(ostream &os, const std::string &name,
197217SN/A              const T *param, int size)
198217SN/A{
199217SN/A    os << name << "=";
200217SN/A    if (size > 0)
201217SN/A        showParam(os, param[0]);
202217SN/A    for (int i = 1; i < size; ++i) {
203217SN/A        os << " ";
204217SN/A        showParam(os, param[i]);
205217SN/A    }
206217SN/A    os << "\n";
207217SN/A}
208217SN/A
209217SN/A
210217SN/Atemplate <class T>
211217SN/Avoid
212237SN/AarrayParamIn(Checkpoint *cp, const std::string &section,
213217SN/A             const std::string &name, T *param, int size)
214217SN/A{
215217SN/A    std::string str;
216237SN/A    if (!cp->find(section, name, str)) {
217217SN/A        fatal("Can't unserialize '%s:%s'\n", section, name);
218217SN/A    }
219217SN/A
220217SN/A    // code below stolen from VectorParam<T>::parse().
221217SN/A    // it would be nice to unify these somehow...
222217SN/A
223217SN/A    vector<string> tokens;
224217SN/A
225217SN/A    tokenize(tokens, str, ' ');
226217SN/A
227217SN/A    // Need this if we were doing a vector
228217SN/A    // value.resize(tokens.size());
229217SN/A
230217SN/A    if (tokens.size() != size) {
231217SN/A        fatal("Array size mismatch on %s:%s'\n", section, name);
232217SN/A    }
233217SN/A
234217SN/A    for (int i = 0; i < tokens.size(); i++) {
235217SN/A        // need to parse into local variable to handle vector<bool>,
236217SN/A        // for which operator[] returns a special reference class
237217SN/A        // that's not the same as 'bool&', (since it's a packed
238217SN/A        // vector)
239217SN/A        T scalar_value;
240217SN/A        if (!parseParam(tokens[i], scalar_value)) {
241217SN/A            string err("could not parse \"");
242217SN/A
243217SN/A            err += str;
244217SN/A            err += "\"";
245217SN/A
246217SN/A            fatal(err);
247217SN/A        }
248217SN/A
249217SN/A        // assign parsed value to vector
250217SN/A        param[i] = scalar_value;
251217SN/A    }
252217SN/A}
253217SN/A
254217SN/A
255237SN/Avoid
256237SN/AobjParamIn(Checkpoint *cp, const std::string &section,
2574000Ssaidi@eecs.umich.edu           const std::string &name, SimObject * &param)
258237SN/A{
259237SN/A    if (!cp->findObj(section, name, param)) {
260237SN/A        fatal("Can't unserialize '%s:%s'\n", section, name);
261237SN/A    }
262237SN/A}
263237SN/A
264237SN/A
265221SN/A#define INSTANTIATE_PARAM_TEMPLATES(type)				\
266221SN/Atemplate void								\
267237SN/AparamOut(ostream &os, const std::string &name, type const &param);	\
268221SN/Atemplate void								\
269237SN/AparamIn(Checkpoint *cp, const std::string &section,			\
270221SN/A        const std::string &name, type & param);				\
271221SN/Atemplate void								\
272221SN/AarrayParamOut(ostream &os, const std::string &name,			\
273237SN/A              type const *param, int size);				\
274221SN/Atemplate void								\
275237SN/AarrayParamIn(Checkpoint *cp, const std::string &section,		\
276217SN/A             const std::string &name, type *param, int size);
277217SN/A
2781642SN/AINSTANTIATE_PARAM_TEMPLATES(signed char)
2791642SN/AINSTANTIATE_PARAM_TEMPLATES(unsigned char)
2801642SN/AINSTANTIATE_PARAM_TEMPLATES(signed short)
2811642SN/AINSTANTIATE_PARAM_TEMPLATES(unsigned short)
2821642SN/AINSTANTIATE_PARAM_TEMPLATES(signed int)
2831642SN/AINSTANTIATE_PARAM_TEMPLATES(unsigned int)
2841642SN/AINSTANTIATE_PARAM_TEMPLATES(signed long)
2851642SN/AINSTANTIATE_PARAM_TEMPLATES(unsigned long)
2861642SN/AINSTANTIATE_PARAM_TEMPLATES(signed long long)
2871642SN/AINSTANTIATE_PARAM_TEMPLATES(unsigned long long)
288219SN/AINSTANTIATE_PARAM_TEMPLATES(bool)
289217SN/AINSTANTIATE_PARAM_TEMPLATES(string)
290217SN/A
291217SN/A
292395SN/A/////////////////////////////
293395SN/A
294395SN/A/// Container for serializing global variables (not associated with
295395SN/A/// any serialized object).
296395SN/Aclass Globals : public Serializable
2972SN/A{
298395SN/A  public:
299512SN/A    const string name() const;
300510SN/A    void serialize(ostream &os);
301395SN/A    void unserialize(Checkpoint *cp);
302395SN/A};
3032SN/A
304395SN/A/// The one and only instance of the Globals class.
305395SN/AGlobals globals;
3062SN/A
307512SN/Aconst string
308395SN/AGlobals::name() const
3092SN/A{
310395SN/A    return "Globals";
3112SN/A}
3122SN/A
3132SN/Avoid
314510SN/AGlobals::serialize(ostream &os)
3152SN/A{
316395SN/A    nameOut(os);
317395SN/A    SERIALIZE_SCALAR(curTick);
318395SN/A
319395SN/A    nameOut(os, "MainEventQueue");
320395SN/A    mainEventQueue.serialize(os);
3212SN/A}
3222SN/A
3232SN/Avoid
324395SN/AGlobals::unserialize(Checkpoint *cp)
3252SN/A{
326395SN/A    const string &section = name();
327395SN/A    UNSERIALIZE_SCALAR(curTick);
3282SN/A
329395SN/A    mainEventQueue.unserialize(cp, "MainEventQueue");
3302SN/A}
3312SN/A
3322SN/Avoid
3332868Sktlim@umich.eduSerializable::serializeAll(const std::string &cpt_dir)
3342SN/A{
3352868Sktlim@umich.edu    setCheckpointDir(cpt_dir);
336449SN/A    string dir = Checkpoint::dir();
337363SN/A    if (mkdir(dir.c_str(), 0775) == -1 && errno != EEXIST)
338449SN/A            fatal("couldn't mkdir %s\n", dir);
339363SN/A
340449SN/A    string cpt_file = dir + Checkpoint::baseFilename;
341395SN/A    ofstream outstream(cpt_file.c_str());
3422SN/A    time_t t = time(NULL);
343395SN/A    outstream << "// checkpoint generated: " << ctime(&t);
3442SN/A
345395SN/A    globals.serialize(outstream);
346395SN/A    SimObject::serializeAll(outstream);
347395SN/A}
3482SN/A
3492797Sktlim@umich.eduvoid
3502868Sktlim@umich.eduSerializable::unserializeAll(const std::string &cpt_dir)
3512797Sktlim@umich.edu{
3522868Sktlim@umich.edu    setCheckpointDir(cpt_dir);
3532797Sktlim@umich.edu    string dir = Checkpoint::dir();
3542797Sktlim@umich.edu    string cpt_file = dir + Checkpoint::baseFilename;
3552797Sktlim@umich.edu    string section = "";
3562797Sktlim@umich.edu
3572797Sktlim@umich.edu    DPRINTFR(Config, "Loading checkpoint dir '%s'\n",
3582797Sktlim@umich.edu             dir);
3592797Sktlim@umich.edu    Checkpoint *cp = new Checkpoint(dir, section);
3602797Sktlim@umich.edu    unserializeGlobals(cp);
3612797Sktlim@umich.edu
3622797Sktlim@umich.edu    SimObject::unserializeAll(cp);
3632797Sktlim@umich.edu}
3642SN/A
365395SN/Avoid
366395SN/ASerializable::unserializeGlobals(Checkpoint *cp)
367395SN/A{
368395SN/A    globals.unserialize(cp);
369395SN/A}
3702SN/A
371449SN/Aconst char *Checkpoint::baseFilename = "m5.cpt";
372449SN/A
373449SN/Astatic string checkpointDirBase;
374294SN/A
3752797Sktlim@umich.eduvoid
3762797Sktlim@umich.edusetCheckpointDir(const std::string &name)
3772797Sktlim@umich.edu{
3782797Sktlim@umich.edu    checkpointDirBase = name;
3792797Sktlim@umich.edu    if (checkpointDirBase[checkpointDirBase.size() - 1] != '/')
3802797Sktlim@umich.edu        checkpointDirBase += "/";
3812797Sktlim@umich.edu}
3822797Sktlim@umich.edu
383294SN/Astring
384449SN/ACheckpoint::dir()
385294SN/A{
386449SN/A    // use csprintf to insert curTick into directory name if it
387449SN/A    // appears to have a format placeholder in it.
388449SN/A    return (checkpointDirBase.find("%") != string::npos) ?
389449SN/A        csprintf(checkpointDirBase, curTick) : checkpointDirBase;
3902SN/A}
3912SN/A
3922SN/Avoid
3932868Sktlim@umich.edudebug_serialize(const std::string &cpt_dir)
3942SN/A{
3952868Sktlim@umich.edu    Serializable::serializeAll(cpt_dir);
3962SN/A}
3972SN/A
3982SN/A
3992SN/A////////////////////////////////////////////////////////////////////////
4002SN/A//
401395SN/A// SerializableClass member definitions
4022SN/A//
4032SN/A////////////////////////////////////////////////////////////////////////
4042SN/A
405395SN/A// Map of class names to SerializableBuilder creation functions.
4062SN/A// Need to make this a pointer so we can force initialization on the
407395SN/A// first reference; otherwise, some SerializableClass constructors
4082SN/A// may be invoked before the classMap constructor.
409395SN/Amap<string,SerializableClass::CreateFunc> *SerializableClass::classMap = 0;
4102SN/A
411395SN/A// SerializableClass constructor: add mapping to classMap
412395SN/ASerializableClass::SerializableClass(const string &className,
4132SN/A                                       CreateFunc createFunc)
4142SN/A{
4152SN/A    if (classMap == NULL)
416395SN/A        classMap = new map<string,SerializableClass::CreateFunc>();
4172SN/A
4182SN/A    if ((*classMap)[className])
4192SN/A    {
4202SN/A        cerr << "Error: simulation object class " << className << " redefined"
4212SN/A             << endl;
4222SN/A        fatal("");
4232SN/A    }
4242SN/A
4252SN/A    // add className --> createFunc to class map
4262SN/A    (*classMap)[className] = createFunc;
4272SN/A}
4282SN/A
4292SN/A
4302SN/A//
4312SN/A//
432395SN/ASerializable *
433395SN/ASerializableClass::createObject(Checkpoint *cp,
434237SN/A                                 const std::string &section)
4352SN/A{
436237SN/A    string className;
4372SN/A
438237SN/A    if (!cp->find(section, "type", className)) {
439395SN/A        fatal("Serializable::create: no 'type' entry in section '%s'.\n",
440237SN/A              section);
4412SN/A    }
4422SN/A
443237SN/A    CreateFunc createFunc = (*classMap)[className];
444237SN/A
445237SN/A    if (createFunc == NULL) {
446395SN/A        fatal("Serializable::create: no create function for class '%s'.\n",
447237SN/A              className);
4482SN/A    }
4492SN/A
450395SN/A    Serializable *object = createFunc(cp, section);
4512SN/A
4522SN/A    assert(object != NULL);
4532SN/A
4542SN/A    return object;
4552SN/A}
4562SN/A
457237SN/A
458395SN/ASerializable *
459395SN/ASerializable::create(Checkpoint *cp, const std::string &section)
460237SN/A{
461395SN/A    Serializable *object = SerializableClass::createObject(cp, section);
462237SN/A    object->unserialize(cp, section);
463237SN/A    return object;
464237SN/A}
465237SN/A
466237SN/A
4672738Sstever@eecs.umich.eduCheckpoint::Checkpoint(const std::string &cpt_dir, const std::string &path)
4682738Sstever@eecs.umich.edu    : db(new IniFile), basePath(path), cptDir(cpt_dir)
469237SN/A{
470449SN/A    string filename = cpt_dir + "/" + Checkpoint::baseFilename;
471237SN/A    if (!db->load(filename)) {
472237SN/A        fatal("Can't load checkpoint file '%s'\n", filename);
473237SN/A    }
474237SN/A}
475237SN/A
476237SN/A
477237SN/Abool
478237SN/ACheckpoint::find(const std::string &section, const std::string &entry,
479237SN/A                 std::string &value)
480237SN/A{
481237SN/A    return db->find(section, entry, value);
482237SN/A}
483237SN/A
484237SN/A
485237SN/Abool
486237SN/ACheckpoint::findObj(const std::string &section, const std::string &entry,
4874000Ssaidi@eecs.umich.edu                    SimObject *&value)
488237SN/A{
489237SN/A    string path;
490237SN/A
491237SN/A    if (!db->find(section, entry, path))
492237SN/A        return false;
493237SN/A
4944000Ssaidi@eecs.umich.edu    value = resolveSimObject(path);
4954000Ssaidi@eecs.umich.edu    return true;
496237SN/A}
497304SN/A
498304SN/A
499304SN/Abool
500304SN/ACheckpoint::sectionExists(const std::string &section)
501304SN/A{
502304SN/A    return db->sectionExists(section);
503304SN/A}
504