serialize.cc revision 237
13560SN/A/*
23560SN/A * Copyright (c) 2003 The Regents of The University of Michigan
33560SN/A * All rights reserved.
43560SN/A *
53560SN/A * Redistribution and use in source and binary forms, with or without
63560SN/A * modification, are permitted provided that the following conditions are
73560SN/A * met: redistributions of source code must retain the above copyright
83560SN/A * notice, this list of conditions and the following disclaimer;
93560SN/A * redistributions in binary form must reproduce the above copyright
103560SN/A * notice, this list of conditions and the following disclaimer in the
113560SN/A * documentation and/or other materials provided with the distribution;
123560SN/A * neither the name of the copyright holders nor the names of its
133560SN/A * contributors may be used to endorse or promote products derived from
143560SN/A * this software without specific prior written permission.
153560SN/A *
163560SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
173560SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
183560SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
193560SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
203560SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
213560SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
223560SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
233560SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
243560SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
253560SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
263560SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
273560SN/A */
283560SN/A
293560SN/A#include <sys/time.h>
303560SN/A
313560SN/A#include <fstream>
3211793Sbrandon.potter@amd.com#include <list>
3311793Sbrandon.potter@amd.com#include <string>
343560SN/A#include <vector>
353560SN/A
363560SN/A#include "base/misc.hh"
373560SN/A#include "base/str.hh"
3811793Sbrandon.potter@amd.com
399329Sdam.sunwoo@arm.com#include "sim/eventq.hh"
403560SN/A#include "sim/param.hh"
413560SN/A#include "sim/serialize.hh"
428232Snate@binkert.org#include "base/inifile.hh"
433560SN/A#include "sim/sim_events.hh"
443560SN/A#include "sim/sim_object.hh"
453560SN/A#include "base/trace.hh"
463560SN/A#include "sim/config_node.hh"
473560SN/A
483560SN/Ausing namespace std;
493560SN/A
503560SN/ASerializer *Serializeable::serializer = NULL;
513560SN/A
523560SN/ASerializeable::Serializeable(const string &n)
5312181Sgabeblack@google.com    : objName(n), serialized(false)
5412181Sgabeblack@google.com{ }
5512182Sgabeblack@google.com
5612182Sgabeblack@google.comSerializeable::~Serializeable()
573560SN/A{ }
583560SN/A
593560SN/Avoid
603560SN/ASerializeable::mark()
613560SN/A{
623560SN/A    if (!serialized)
633560SN/A        serializer->add_object(this);
643560SN/A
653560SN/A    serialized = true;
663560SN/A}
673560SN/A
683560SN/Avoid
693560SN/ASerializeable::nameOut(ostream &os)
703560SN/A{
713560SN/A    os << "\n[" << name() << "]\n";
723560SN/A}
733560SN/A
743560SN/Avoid
753560SN/ASerializeable::nameOut(ostream &os, const string &_name)
763560SN/A{
773560SN/A    os << "\n[" << _name << "]\n";
783560SN/A}
793560SN/A
803560SN/Atemplate <class T>
813560SN/Avoid
823560SN/AparamOut(ostream &os, const std::string &name, const T& param)
833560SN/A{
843560SN/A    os << name << "=";
853560SN/A    showParam(os, param);
863560SN/A    os << "\n";
873560SN/A}
883560SN/A
893560SN/A
903560SN/Atemplate <class T>
913560SN/Avoid
923560SN/AparamIn(Checkpoint *cp, const std::string &section,
933560SN/A        const std::string &name, T& param)
943560SN/A{
953560SN/A    std::string str;
963560SN/A    if (!cp->find(section, name, str) || !parseParam(str, param)) {
973560SN/A        fatal("Can't unserialize '%s:%s'\n", section, name);
983560SN/A    }
993560SN/A}
1003560SN/A
1013560SN/A
1023560SN/Atemplate <class T>
1033560SN/Avoid
1043560SN/AarrayParamOut(ostream &os, const std::string &name,
1053560SN/A              const T *param, int size)
1063560SN/A{
1073560SN/A    os << name << "=";
1083560SN/A    if (size > 0)
1093560SN/A        showParam(os, param[0]);
1103560SN/A    for (int i = 1; i < size; ++i) {
1113560SN/A        os << " ";
1123560SN/A        showParam(os, param[i]);
1133560SN/A    }
1143560SN/A    os << "\n";
1153560SN/A}
1163560SN/A
1173560SN/A
1183560SN/Atemplate <class T>
1193560SN/Avoid
1203560SN/AarrayParamIn(Checkpoint *cp, const std::string &section,
1213560SN/A             const std::string &name, T *param, int size)
1223560SN/A{
1233560SN/A    std::string str;
12412182Sgabeblack@google.com    if (!cp->find(section, name, str)) {
12512182Sgabeblack@google.com        fatal("Can't unserialize '%s:%s'\n", section, name);
12612182Sgabeblack@google.com    }
12712182Sgabeblack@google.com
12812182Sgabeblack@google.com    // code below stolen from VectorParam<T>::parse().
12912182Sgabeblack@google.com    // it would be nice to unify these somehow...
13012182Sgabeblack@google.com
13112182Sgabeblack@google.com    vector<string> tokens;
13212182Sgabeblack@google.com
13312182Sgabeblack@google.com    tokenize(tokens, str, ' ');
13412182Sgabeblack@google.com
13512182Sgabeblack@google.com    // Need this if we were doing a vector
13612182Sgabeblack@google.com    // value.resize(tokens.size());
13712182Sgabeblack@google.com
13812182Sgabeblack@google.com    if (tokens.size() != size) {
13912182Sgabeblack@google.com        fatal("Array size mismatch on %s:%s'\n", section, name);
14012182Sgabeblack@google.com    }
14112182Sgabeblack@google.com
14212182Sgabeblack@google.com    for (int i = 0; i < tokens.size(); i++) {
14312182Sgabeblack@google.com        // need to parse into local variable to handle vector<bool>,
14412182Sgabeblack@google.com        // for which operator[] returns a special reference class
14512182Sgabeblack@google.com        // that's not the same as 'bool&', (since it's a packed
14612182Sgabeblack@google.com        // vector)
14712182Sgabeblack@google.com        T scalar_value;
14812182Sgabeblack@google.com        if (!parseParam(tokens[i], scalar_value)) {
14912182Sgabeblack@google.com            string err("could not parse \"");
15012182Sgabeblack@google.com
15112182Sgabeblack@google.com            err += str;
15212182Sgabeblack@google.com            err += "\"";
1533560SN/A
1543560SN/A            fatal(err);
1553560SN/A        }
1563560SN/A
1573560SN/A        // assign parsed value to vector
1583560SN/A        param[i] = scalar_value;
1593560SN/A    }
1603560SN/A}
1613560SN/A
1623560SN/A
1633560SN/Avoid
1643560SN/AobjParamIn(Checkpoint *cp, const std::string &section,
1653560SN/A           const std::string &name, Serializeable * &param)
1663560SN/A{
1673560SN/A    if (!cp->findObj(section, name, param)) {
1683560SN/A        fatal("Can't unserialize '%s:%s'\n", section, name);
1693560SN/A    }
1703560SN/A}
1713560SN/A
1725191Ssaidi@eecs.umich.edu
1735191Ssaidi@eecs.umich.edu#define INSTANTIATE_PARAM_TEMPLATES(type)				\
1745191Ssaidi@eecs.umich.edutemplate void								\
1753560SN/AparamOut(ostream &os, const std::string &name, type const &param);	\
1763560SN/Atemplate void								\
1777823Ssteve.reinhardt@amd.comparamIn(Checkpoint *cp, const std::string &section,			\
1783560SN/A        const std::string &name, type & param);				\
1797823Ssteve.reinhardt@amd.comtemplate void								\
1803560SN/AarrayParamOut(ostream &os, const std::string &name,			\
1813560SN/A              type const *param, int size);				\
1823560SN/Atemplate void								\
1833560SN/AarrayParamIn(Checkpoint *cp, const std::string &section,		\
1843560SN/A             const std::string &name, type *param, int size);
1853560SN/A
1865568Snate@binkert.org
1873560SN/AINSTANTIATE_PARAM_TEMPLATES(int8_t)
1883560SN/AINSTANTIATE_PARAM_TEMPLATES(uint8_t)
1893560SN/AINSTANTIATE_PARAM_TEMPLATES(int16_t)
1903560SN/AINSTANTIATE_PARAM_TEMPLATES(uint16_t)
1913560SN/AINSTANTIATE_PARAM_TEMPLATES(int32_t)
1923560SN/AINSTANTIATE_PARAM_TEMPLATES(uint32_t)
1933560SN/AINSTANTIATE_PARAM_TEMPLATES(int64_t)
1943560SN/AINSTANTIATE_PARAM_TEMPLATES(uint64_t)
1953560SN/AINSTANTIATE_PARAM_TEMPLATES(bool)
1963560SN/AINSTANTIATE_PARAM_TEMPLATES(string)
1973560SN/A
1983560SN/A
1993560SN/A#if 0
2003560SN/A// unneeded?
2015191Ssaidi@eecs.umich.eduvoid
2025191Ssaidi@eecs.umich.eduSerializeable::childOut(const string &name, Serializeable *child)
2035191Ssaidi@eecs.umich.edu{
2045191Ssaidi@eecs.umich.edu    child->mark();
2053560SN/A    if (child->name() == "")
2063560SN/A        panic("child is unnamed");
2073560SN/A
2083560SN/A    out() << name << "=" << child->name() << "\n";
2093560SN/A}
2103560SN/A#endif
2113560SN/A
2123560SN/Avoid
2133560SN/ASerializeable::setName(const string &name)
2143560SN/A{
2153560SN/A    if (objName != "") {
2163560SN/A        cprintf("Renaming object '%s' to '%s'.\n", objName, name);
21712182Sgabeblack@google.com    }
21812182Sgabeblack@google.com
21912182Sgabeblack@google.com    objName = name;
22012182Sgabeblack@google.com}
22112182Sgabeblack@google.com
22212182Sgabeblack@google.comSerializer::Serializer()
22312182Sgabeblack@google.com{ }
22412182Sgabeblack@google.com
22512182Sgabeblack@google.comSerializer::~Serializer()
22612182Sgabeblack@google.com{ }
22712182Sgabeblack@google.com
22812182Sgabeblack@google.comostream &
22912182Sgabeblack@google.comSerializer::out() const
23012182Sgabeblack@google.com{
23112182Sgabeblack@google.com    if (!output)
23212182Sgabeblack@google.com        panic("must set output before serializing");
23310905Sandreas.sandberg@arm.com
2343560SN/A    return *output;
23510905Sandreas.sandberg@arm.com}
2363560SN/A
2373560SN/Avoid
2383560SN/ASerializer::add_object(Serializeable *obj)
2393560SN/A{
24012182Sgabeblack@google.com    objects.push_back(obj);
24112182Sgabeblack@google.com}
2423560SN/A
2433560SN/Avoid
2443560SN/ASerializer::add_objects()
24510905Sandreas.sandberg@arm.com{
2463560SN/A    mainEventQueue.mark();
24710905Sandreas.sandberg@arm.com
2483560SN/A    SimObject::SimObjectList::iterator i = SimObject::simObjectList.begin();
2493560SN/A    SimObject::SimObjectList::iterator end = SimObject::simObjectList.end();
2503560SN/A
2513560SN/A    while (i != end) {
2523560SN/A        (*i)->mark();
25312182Sgabeblack@google.com        ++i;
25412182Sgabeblack@google.com    }
2553560SN/A}
2563560SN/A
2575568Snate@binkert.orgvoid
2585568Snate@binkert.orgSerializer::serialize(const string &f)
259{
260    if (Serializeable::serializer != NULL)
261        panic("in process of serializing!");
262
263    Serializeable::serializer = this;
264
265    file = f;
266    string cpt_file = file + ".cpt";
267    output = new ofstream(cpt_file.c_str());
268    time_t t = time(NULL);
269    *output << "// checkpoint generated: " << ctime(&t);
270
271    serlist_t list;
272
273    add_objects();
274    while (!objects.empty()) {
275        Serializeable *serial = objects.front();
276        DPRINTF(Serialize, "Naming children of %s\n", serial->name());
277        serial->nameChildren();
278        objects.pop_front();
279        list.push_back(serial);
280    }
281
282    while (!list.empty()) {
283        list.front()->serialized = false;
284        list.pop_front();
285    }
286
287    add_objects();
288    while (!objects.empty()) {
289        Serializeable *obj = objects.front();
290        DPRINTF(Serialize, "Serializing %s\n", obj->name());
291        obj->nameOut(out());
292        obj->serialize(out());
293        objects.pop_front();
294        list.push_back(obj);
295    }
296
297    while (!list.empty()) {
298        list.front()->serialized = false;
299        list.pop_front();
300    }
301
302    Serializeable::serializer = NULL;
303
304    delete output;
305    output = NULL;
306    file = "";
307}
308
309class SerializeEvent : public Event
310{
311  protected:
312    string file;
313
314  public:
315    SerializeEvent(EventQueue *q, Tick when, const string &file);
316    ~SerializeEvent();
317
318    virtual void process();
319    virtual void serialize(std::ostream &os);
320};
321
322SerializeEvent::SerializeEvent(EventQueue *q, Tick when, const string &f)
323    : Event(q), file(f)
324{
325    setFlags(AutoDelete);
326    schedule(when);
327}
328
329SerializeEvent::~SerializeEvent()
330{
331}
332
333void
334SerializeEvent::process()
335{
336    Serializer serial;
337    serial.serialize(file);
338    new SimExitEvent("Serialization caused exit");
339}
340
341void
342SerializeEvent::serialize(ostream &os)
343{
344    panic("Cannot serialize the SerializeEvent");
345}
346
347class SerializeParamContext : public ParamContext
348{
349  private:
350    SerializeEvent *event;
351
352  public:
353    SerializeParamContext(const string &section);
354    ~SerializeParamContext();
355    void checkParams();
356};
357
358SerializeParamContext serialParams("serialize");
359
360Param<Counter> serialize_cycle(&serialParams,
361                                "cycle",
362                                "cycle to serialize",
363                                0);
364
365Param<string> serialize_file(&serialParams,
366                             "file",
367                             "file to write to", "");
368
369// Copy filename into regular string so we can export it without
370// having to include param.hh all over the place.
371string serializeFilename;
372
373SerializeParamContext::SerializeParamContext(const string &section)
374    : ParamContext(section), event(NULL)
375{ }
376
377SerializeParamContext::~SerializeParamContext()
378{
379}
380
381void
382SerializeParamContext::checkParams()
383{
384    serializeFilename = serialize_file;
385    if (!serializeFilename.empty() && serialize_cycle > 0)
386        event = new SerializeEvent(&mainEventQueue, serialize_cycle,
387                                   serializeFilename);
388}
389
390void
391debug_serialize(const char *file)
392{
393    Serializer serial;
394    serial.serialize(file);
395    new SimExitEvent("Serialization caused exit");
396}
397
398
399
400
401////////////////////////////////////////////////////////////////////////
402//
403// SerializeableClass member definitions
404//
405////////////////////////////////////////////////////////////////////////
406
407// Map of class names to SerializeableBuilder creation functions.
408// Need to make this a pointer so we can force initialization on the
409// first reference; otherwise, some SerializeableClass constructors
410// may be invoked before the classMap constructor.
411map<string,SerializeableClass::CreateFunc> *SerializeableClass::classMap = 0;
412
413// SerializeableClass constructor: add mapping to classMap
414SerializeableClass::SerializeableClass(const string &className,
415                                       CreateFunc createFunc)
416{
417    if (classMap == NULL)
418        classMap = new map<string,SerializeableClass::CreateFunc>();
419
420    if ((*classMap)[className])
421    {
422        cerr << "Error: simulation object class " << className << " redefined"
423             << endl;
424        fatal("");
425    }
426
427    // add className --> createFunc to class map
428    (*classMap)[className] = createFunc;
429}
430
431
432//
433//
434Serializeable *
435SerializeableClass::createObject(Checkpoint *cp,
436                                 const std::string &section)
437{
438    string className;
439
440    if (!cp->find(section, "type", className)) {
441        fatal("Serializeable::create: no 'type' entry in section '%s'.\n",
442              section);
443    }
444
445    CreateFunc createFunc = (*classMap)[className];
446
447    if (createFunc == NULL) {
448        fatal("Serializeable::create: no create function for class '%s'.\n",
449              className);
450    }
451
452    Serializeable *object = createFunc(cp, section);
453
454    assert(object != NULL);
455
456    return object;
457}
458
459
460Serializeable *
461Serializeable::create(Checkpoint *cp, const std::string &section)
462{
463    Serializeable *object = SerializeableClass::createObject(cp, section);
464    object->unserialize(cp, section);
465    return object;
466}
467
468
469Checkpoint::Checkpoint(const std::string &filename, const std::string &path,
470                       const ConfigNode *_configNode)
471    : db(new IniFile), basePath(path), configNode(_configNode)
472{
473    if (!db->load(filename)) {
474        fatal("Can't load checkpoint file '%s'\n", filename);
475    }
476
477    mainEventQueue.unserialize(this, "MainEventQueue");
478}
479
480
481bool
482Checkpoint::find(const std::string &section, const std::string &entry,
483                 std::string &value)
484{
485    return db->find(section, entry, value);
486}
487
488
489bool
490Checkpoint::findObj(const std::string &section, const std::string &entry,
491                    Serializeable *&value)
492{
493    string path;
494
495    if (!db->find(section, entry, path))
496        return false;
497
498    if ((value = configNode->resolveSimObject(path)) != NULL)
499        return true;
500
501    if ((value = objMap[path]) != NULL)
502        return true;
503
504    return false;
505}
506