serialize.cc revision 237
1/*
2 * Copyright (c) 2003 The Regents of The University of Michigan
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met: redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer;
9 * redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution;
12 * neither the name of the copyright holders nor the names of its
13 * contributors may be used to endorse or promote products derived from
14 * this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29#include <sys/time.h>
30
31#include <fstream>
32#include <list>
33#include <string>
34#include <vector>
35
36#include "base/misc.hh"
37#include "base/str.hh"
38
39#include "sim/eventq.hh"
40#include "sim/param.hh"
41#include "sim/serialize.hh"
42#include "base/inifile.hh"
43#include "sim/sim_events.hh"
44#include "sim/sim_object.hh"
45#include "base/trace.hh"
46#include "sim/config_node.hh"
47
48using namespace std;
49
50Serializer *Serializeable::serializer = NULL;
51
52Serializeable::Serializeable(const string &n)
53    : objName(n), serialized(false)
54{ }
55
56Serializeable::~Serializeable()
57{ }
58
59void
60Serializeable::mark()
61{
62    if (!serialized)
63        serializer->add_object(this);
64
65    serialized = true;
66}
67
68void
69Serializeable::nameOut(ostream &os)
70{
71    os << "\n[" << name() << "]\n";
72}
73
74void
75Serializeable::nameOut(ostream &os, const string &_name)
76{
77    os << "\n[" << _name << "]\n";
78}
79
80template <class T>
81void
82paramOut(ostream &os, const std::string &name, const T& param)
83{
84    os << name << "=";
85    showParam(os, param);
86    os << "\n";
87}
88
89
90template <class T>
91void
92paramIn(Checkpoint *cp, const std::string &section,
93        const std::string &name, T& param)
94{
95    std::string str;
96    if (!cp->find(section, name, str) || !parseParam(str, param)) {
97        fatal("Can't unserialize '%s:%s'\n", section, name);
98    }
99}
100
101
102template <class T>
103void
104arrayParamOut(ostream &os, const std::string &name,
105              const T *param, int size)
106{
107    os << name << "=";
108    if (size > 0)
109        showParam(os, param[0]);
110    for (int i = 1; i < size; ++i) {
111        os << " ";
112        showParam(os, param[i]);
113    }
114    os << "\n";
115}
116
117
118template <class T>
119void
120arrayParamIn(Checkpoint *cp, const std::string &section,
121             const std::string &name, T *param, int size)
122{
123    std::string str;
124    if (!cp->find(section, name, str)) {
125        fatal("Can't unserialize '%s:%s'\n", section, name);
126    }
127
128    // code below stolen from VectorParam<T>::parse().
129    // it would be nice to unify these somehow...
130
131    vector<string> tokens;
132
133    tokenize(tokens, str, ' ');
134
135    // Need this if we were doing a vector
136    // value.resize(tokens.size());
137
138    if (tokens.size() != size) {
139        fatal("Array size mismatch on %s:%s'\n", section, name);
140    }
141
142    for (int i = 0; i < tokens.size(); i++) {
143        // need to parse into local variable to handle vector<bool>,
144        // for which operator[] returns a special reference class
145        // that's not the same as 'bool&', (since it's a packed
146        // vector)
147        T scalar_value;
148        if (!parseParam(tokens[i], scalar_value)) {
149            string err("could not parse \"");
150
151            err += str;
152            err += "\"";
153
154            fatal(err);
155        }
156
157        // assign parsed value to vector
158        param[i] = scalar_value;
159    }
160}
161
162
163void
164objParamIn(Checkpoint *cp, const std::string &section,
165           const std::string &name, Serializeable * &param)
166{
167    if (!cp->findObj(section, name, param)) {
168        fatal("Can't unserialize '%s:%s'\n", section, name);
169    }
170}
171
172
173#define INSTANTIATE_PARAM_TEMPLATES(type)				\
174template void								\
175paramOut(ostream &os, const std::string &name, type const &param);	\
176template void								\
177paramIn(Checkpoint *cp, const std::string &section,			\
178        const std::string &name, type & param);				\
179template void								\
180arrayParamOut(ostream &os, const std::string &name,			\
181              type const *param, int size);				\
182template void								\
183arrayParamIn(Checkpoint *cp, const std::string &section,		\
184             const std::string &name, type *param, int size);
185
186
187INSTANTIATE_PARAM_TEMPLATES(int8_t)
188INSTANTIATE_PARAM_TEMPLATES(uint8_t)
189INSTANTIATE_PARAM_TEMPLATES(int16_t)
190INSTANTIATE_PARAM_TEMPLATES(uint16_t)
191INSTANTIATE_PARAM_TEMPLATES(int32_t)
192INSTANTIATE_PARAM_TEMPLATES(uint32_t)
193INSTANTIATE_PARAM_TEMPLATES(int64_t)
194INSTANTIATE_PARAM_TEMPLATES(uint64_t)
195INSTANTIATE_PARAM_TEMPLATES(bool)
196INSTANTIATE_PARAM_TEMPLATES(string)
197
198
199#if 0
200// unneeded?
201void
202Serializeable::childOut(const string &name, Serializeable *child)
203{
204    child->mark();
205    if (child->name() == "")
206        panic("child is unnamed");
207
208    out() << name << "=" << child->name() << "\n";
209}
210#endif
211
212void
213Serializeable::setName(const string &name)
214{
215    if (objName != "") {
216        cprintf("Renaming object '%s' to '%s'.\n", objName, name);
217    }
218
219    objName = name;
220}
221
222Serializer::Serializer()
223{ }
224
225Serializer::~Serializer()
226{ }
227
228ostream &
229Serializer::out() const
230{
231    if (!output)
232        panic("must set output before serializing");
233
234    return *output;
235}
236
237void
238Serializer::add_object(Serializeable *obj)
239{
240    objects.push_back(obj);
241}
242
243void
244Serializer::add_objects()
245{
246    mainEventQueue.mark();
247
248    SimObject::SimObjectList::iterator i = SimObject::simObjectList.begin();
249    SimObject::SimObjectList::iterator end = SimObject::simObjectList.end();
250
251    while (i != end) {
252        (*i)->mark();
253        ++i;
254    }
255}
256
257void
258Serializer::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