serialize.cc revision 304
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()
53    : 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
212Serializer::Serializer()
213{ }
214
215Serializer::~Serializer()
216{ }
217
218ostream &
219Serializer::out() const
220{
221    if (!output)
222        panic("must set output before serializing");
223
224    return *output;
225}
226
227void
228Serializer::add_object(Serializeable *obj)
229{
230    objects.push_back(obj);
231}
232
233void
234Serializer::add_objects()
235{
236    mainEventQueue.mark();
237
238    SimObject::SimObjectList::iterator i = SimObject::simObjectList.begin();
239    SimObject::SimObjectList::iterator end = SimObject::simObjectList.end();
240
241    while (i != end) {
242        (*i)->mark();
243        ++i;
244    }
245}
246
247void
248Serializer::serialize()
249{
250    if (Serializeable::serializer != NULL)
251        panic("in process of serializing!");
252
253    Serializeable::serializer = this;
254
255    file = CheckpointFile();
256    string cpt_file = file + ".cpt";
257    output = new ofstream(cpt_file.c_str());
258    time_t t = time(NULL);
259    *output << "// checkpoint generated: " << ctime(&t);
260
261    serlist_t list;
262
263    add_objects();
264    while (!objects.empty()) {
265        Serializeable *obj = objects.front();
266        DPRINTF(Serialize, "Serializing %s\n", obj->name());
267        obj->nameOut(out());
268        obj->serialize(out());
269        objects.pop_front();
270        list.push_back(obj);
271    }
272
273    while (!list.empty()) {
274        list.front()->serialized = false;
275        list.pop_front();
276    }
277
278    Serializeable::serializer = NULL;
279
280    delete output;
281    output = NULL;
282    file = "";
283}
284
285class SerializeEvent : public Event
286{
287  protected:
288    string file;
289    Tick repeat;
290
291  public:
292    SerializeEvent(Tick _when, Tick _repeat);
293    virtual void process();
294    virtual void serialize(std::ostream &os)
295    {
296        panic("Cannot serialize the SerializeEvent");
297    }
298
299};
300
301SerializeEvent::SerializeEvent(Tick _when, Tick _repeat)
302    : Event(&mainEventQueue, 990), repeat(_repeat)
303{
304    setFlags(AutoDelete);
305    schedule(_when);
306}
307
308void
309SerializeEvent::process()
310{
311    Serializer serial;
312    serial.serialize();
313    if (repeat)
314        schedule(curTick + repeat);
315}
316
317string __CheckpointFileBase;
318
319string
320CheckpointFile()
321{
322    if (__CheckpointFileBase.empty())
323        return __CheckpointFileBase;
324
325    return csprintf("%s.%d", __CheckpointFileBase, curTick);
326}
327
328void
329SetupCheckpoint(Tick when, Tick period)
330{
331    new SerializeEvent(when, period);
332}
333
334class SerializeParamContext : public ParamContext
335{
336  private:
337    SerializeEvent *event;
338
339  public:
340    SerializeParamContext(const string &section);
341    ~SerializeParamContext();
342    void checkParams();
343};
344
345SerializeParamContext serialParams("serialize");
346
347Param<string> serialize_file(&serialParams,
348                             "file",
349                             "file to write to", "m5");
350
351Param<Counter> serialize_cycle(&serialParams,
352                                "cycle",
353                                "cycle to serialize",
354                                0);
355
356Param<Counter> serialize_period(&serialParams,
357                                "period",
358                                "period to repeat serializations",
359                                0);
360
361
362
363SerializeParamContext::SerializeParamContext(const string &section)
364    : ParamContext(section), event(NULL)
365{ }
366
367SerializeParamContext::~SerializeParamContext()
368{
369}
370
371void
372SerializeParamContext::checkParams()
373{
374    __CheckpointFileBase = serialize_file;
375    if (serialize_cycle > 0)
376        SetupCheckpoint(serialize_cycle, serialize_period);
377}
378
379void
380debug_serialize()
381{
382    Serializer serial;
383    serial.serialize();
384}
385
386void
387debug_serialize(Tick when)
388{
389    new SerializeEvent(when, 0);
390}
391
392////////////////////////////////////////////////////////////////////////
393//
394// SerializeableClass member definitions
395//
396////////////////////////////////////////////////////////////////////////
397
398// Map of class names to SerializeableBuilder creation functions.
399// Need to make this a pointer so we can force initialization on the
400// first reference; otherwise, some SerializeableClass constructors
401// may be invoked before the classMap constructor.
402map<string,SerializeableClass::CreateFunc> *SerializeableClass::classMap = 0;
403
404// SerializeableClass constructor: add mapping to classMap
405SerializeableClass::SerializeableClass(const string &className,
406                                       CreateFunc createFunc)
407{
408    if (classMap == NULL)
409        classMap = new map<string,SerializeableClass::CreateFunc>();
410
411    if ((*classMap)[className])
412    {
413        cerr << "Error: simulation object class " << className << " redefined"
414             << endl;
415        fatal("");
416    }
417
418    // add className --> createFunc to class map
419    (*classMap)[className] = createFunc;
420}
421
422
423//
424//
425Serializeable *
426SerializeableClass::createObject(Checkpoint *cp,
427                                 const std::string &section)
428{
429    string className;
430
431    if (!cp->find(section, "type", className)) {
432        fatal("Serializeable::create: no 'type' entry in section '%s'.\n",
433              section);
434    }
435
436    CreateFunc createFunc = (*classMap)[className];
437
438    if (createFunc == NULL) {
439        fatal("Serializeable::create: no create function for class '%s'.\n",
440              className);
441    }
442
443    Serializeable *object = createFunc(cp, section);
444
445    assert(object != NULL);
446
447    return object;
448}
449
450
451Serializeable *
452Serializeable::create(Checkpoint *cp, const std::string &section)
453{
454    Serializeable *object = SerializeableClass::createObject(cp, section);
455    object->unserialize(cp, section);
456    return object;
457}
458
459
460Checkpoint::Checkpoint(const std::string &filename, const std::string &path,
461                       const ConfigNode *_configNode)
462    : db(new IniFile), basePath(path), configNode(_configNode)
463{
464    if (!db->load(filename)) {
465        fatal("Can't load checkpoint file '%s'\n", filename);
466    }
467
468    mainEventQueue.unserialize(this, "MainEventQueue");
469}
470
471
472bool
473Checkpoint::find(const std::string &section, const std::string &entry,
474                 std::string &value)
475{
476    return db->find(section, entry, value);
477}
478
479
480bool
481Checkpoint::findObj(const std::string &section, const std::string &entry,
482                    Serializeable *&value)
483{
484    string path;
485
486    if (!db->find(section, entry, path))
487        return false;
488
489    if ((value = configNode->resolveSimObject(path)) != NULL)
490        return true;
491
492    if ((value = objMap[path]) != NULL)
493        return true;
494
495    return false;
496}
497
498
499bool
500Checkpoint::sectionExists(const std::string &section)
501{
502    return db->sectionExists(section);
503}
504