serialize.cc revision 363
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#include <sys/types.h>
31#include <sys/stat.h>
32
33#include <fstream>
34#include <list>
35#include <string>
36#include <vector>
37
38#include "base/inifile.hh"
39#include "base/misc.hh"
40#include "base/str.hh"
41#include "base/trace.hh"
42#include "sim/config_node.hh"
43#include "sim/eventq.hh"
44#include "sim/param.hh"
45#include "sim/serialize.hh"
46#include "sim/sim_events.hh"
47#include "sim/sim_object.hh"
48
49using namespace std;
50
51Serializer *Serializeable::serializer = NULL;
52
53Serializeable::Serializeable()
54    : serialized(false)
55{ }
56
57Serializeable::~Serializeable()
58{ }
59
60void
61Serializeable::mark()
62{
63    if (!serialized)
64        serializer->add_object(this);
65
66    serialized = true;
67}
68
69void
70Serializeable::nameOut(ostream &os)
71{
72    os << "\n[" << name() << "]\n";
73}
74
75void
76Serializeable::nameOut(ostream &os, const string &_name)
77{
78    os << "\n[" << _name << "]\n";
79}
80
81template <class T>
82void
83paramOut(ostream &os, const std::string &name, const T& param)
84{
85    os << name << "=";
86    showParam(os, param);
87    os << "\n";
88}
89
90
91template <class T>
92void
93paramIn(Checkpoint *cp, const std::string &section,
94        const std::string &name, T& param)
95{
96    std::string str;
97    if (!cp->find(section, name, str) || !parseParam(str, param)) {
98        fatal("Can't unserialize '%s:%s'\n", section, name);
99    }
100}
101
102
103template <class T>
104void
105arrayParamOut(ostream &os, const std::string &name,
106              const T *param, int size)
107{
108    os << name << "=";
109    if (size > 0)
110        showParam(os, param[0]);
111    for (int i = 1; i < size; ++i) {
112        os << " ";
113        showParam(os, param[i]);
114    }
115    os << "\n";
116}
117
118
119template <class T>
120void
121arrayParamIn(Checkpoint *cp, const std::string &section,
122             const std::string &name, T *param, int size)
123{
124    std::string str;
125    if (!cp->find(section, name, str)) {
126        fatal("Can't unserialize '%s:%s'\n", section, name);
127    }
128
129    // code below stolen from VectorParam<T>::parse().
130    // it would be nice to unify these somehow...
131
132    vector<string> tokens;
133
134    tokenize(tokens, str, ' ');
135
136    // Need this if we were doing a vector
137    // value.resize(tokens.size());
138
139    if (tokens.size() != size) {
140        fatal("Array size mismatch on %s:%s'\n", section, name);
141    }
142
143    for (int i = 0; i < tokens.size(); i++) {
144        // need to parse into local variable to handle vector<bool>,
145        // for which operator[] returns a special reference class
146        // that's not the same as 'bool&', (since it's a packed
147        // vector)
148        T scalar_value;
149        if (!parseParam(tokens[i], scalar_value)) {
150            string err("could not parse \"");
151
152            err += str;
153            err += "\"";
154
155            fatal(err);
156        }
157
158        // assign parsed value to vector
159        param[i] = scalar_value;
160    }
161}
162
163
164void
165objParamIn(Checkpoint *cp, const std::string &section,
166           const std::string &name, Serializeable * &param)
167{
168    if (!cp->findObj(section, name, param)) {
169        fatal("Can't unserialize '%s:%s'\n", section, name);
170    }
171}
172
173
174#define INSTANTIATE_PARAM_TEMPLATES(type)				\
175template void								\
176paramOut(ostream &os, const std::string &name, type const &param);	\
177template void								\
178paramIn(Checkpoint *cp, const std::string &section,			\
179        const std::string &name, type & param);				\
180template void								\
181arrayParamOut(ostream &os, const std::string &name,			\
182              type const *param, int size);				\
183template void								\
184arrayParamIn(Checkpoint *cp, const std::string &section,		\
185             const std::string &name, type *param, int size);
186
187
188INSTANTIATE_PARAM_TEMPLATES(int8_t)
189INSTANTIATE_PARAM_TEMPLATES(uint8_t)
190INSTANTIATE_PARAM_TEMPLATES(int16_t)
191INSTANTIATE_PARAM_TEMPLATES(uint16_t)
192INSTANTIATE_PARAM_TEMPLATES(int32_t)
193INSTANTIATE_PARAM_TEMPLATES(uint32_t)
194INSTANTIATE_PARAM_TEMPLATES(int64_t)
195INSTANTIATE_PARAM_TEMPLATES(uint64_t)
196INSTANTIATE_PARAM_TEMPLATES(bool)
197INSTANTIATE_PARAM_TEMPLATES(string)
198
199
200#if 0
201// unneeded?
202void
203Serializeable::childOut(const string &name, Serializeable *child)
204{
205    child->mark();
206    if (child->name() == "")
207        panic("child is unnamed");
208
209    out() << name << "=" << child->name() << "\n";
210}
211#endif
212
213Serializer::Serializer()
214{ }
215
216Serializer::~Serializer()
217{ }
218
219ostream &
220Serializer::out() const
221{
222    if (!output)
223        panic("must set output before serializing");
224
225    return *output;
226}
227
228void
229Serializer::add_object(Serializeable *obj)
230{
231    objects.push_back(obj);
232}
233
234void
235Serializer::add_objects()
236{
237    mainEventQueue.mark();
238
239    SimObject::SimObjectList::iterator i = SimObject::simObjectList.begin();
240    SimObject::SimObjectList::iterator end = SimObject::simObjectList.end();
241
242    while (i != end) {
243        (*i)->mark();
244        ++i;
245    }
246}
247
248void
249Serializer::serialize()
250{
251    if (Serializeable::serializer != NULL)
252        panic("in process of serializing!");
253
254    Serializeable::serializer = this;
255
256    string dir = CheckpointDir();
257    if (mkdir(dir.c_str(), 0775) == -1 && errno != EEXIST)
258            warn("could mkdir %s\n", dir);
259
260    string cpt_file = dir + "m5.cpt";
261    output = new ofstream(cpt_file.c_str());
262    time_t t = time(NULL);
263    *output << "// checkpoint generated: " << ctime(&t);
264
265    serlist_t list;
266
267    add_objects();
268    while (!objects.empty()) {
269        Serializeable *obj = objects.front();
270        DPRINTF(Serialize, "Serializing %s\n", obj->name());
271        obj->nameOut(out());
272        obj->serialize(out());
273        objects.pop_front();
274        list.push_back(obj);
275    }
276
277    while (!list.empty()) {
278        list.front()->serialized = false;
279        list.pop_front();
280    }
281
282    Serializeable::serializer = NULL;
283
284    delete output;
285    output = NULL;
286}
287
288class SerializeEvent : public Event
289{
290  protected:
291    Tick repeat;
292
293  public:
294    SerializeEvent(Tick _when, Tick _repeat);
295    virtual void process();
296    virtual void serialize(std::ostream &os)
297    {
298        panic("Cannot serialize the SerializeEvent");
299    }
300
301};
302
303SerializeEvent::SerializeEvent(Tick _when, Tick _repeat)
304    : Event(&mainEventQueue, 990), repeat(_repeat)
305{
306    setFlags(AutoDelete);
307    schedule(_when);
308}
309
310void
311SerializeEvent::process()
312{
313    Serializer serial;
314    serial.serialize();
315    if (repeat)
316        schedule(curTick + repeat);
317}
318
319string __CheckpointDirBase;
320
321string
322CheckpointDir()
323{
324    if (__CheckpointDirBase.empty())
325        return __CheckpointDirBase;
326
327    return csprintf("%s/m5.%012d/", __CheckpointDirBase, curTick);
328}
329
330void
331SetupCheckpoint(Tick when, Tick period)
332{
333    new SerializeEvent(when, period);
334}
335
336class SerializeParamContext : public ParamContext
337{
338  private:
339    SerializeEvent *event;
340
341  public:
342    SerializeParamContext(const string &section);
343    ~SerializeParamContext();
344    void checkParams();
345};
346
347SerializeParamContext serialParams("serialize");
348
349Param<string> serialize_dir(&serialParams,
350                             "dir",
351                             "dir to stick checkpoint in", ".");
352
353Param<Counter> serialize_cycle(&serialParams,
354                                "cycle",
355                                "cycle to serialize",
356                                0);
357
358Param<Counter> serialize_period(&serialParams,
359                                "period",
360                                "period to repeat serializations",
361                                0);
362
363
364
365SerializeParamContext::SerializeParamContext(const string &section)
366    : ParamContext(section), event(NULL)
367{ }
368
369SerializeParamContext::~SerializeParamContext()
370{
371}
372
373void
374SerializeParamContext::checkParams()
375{
376    __CheckpointDirBase = serialize_dir;
377    if (serialize_cycle > 0)
378        SetupCheckpoint(serialize_cycle, serialize_period);
379}
380
381void
382debug_serialize()
383{
384    Serializer serial;
385    serial.serialize();
386}
387
388void
389debug_serialize(Tick when)
390{
391    new SerializeEvent(when, 0);
392}
393
394////////////////////////////////////////////////////////////////////////
395//
396// SerializeableClass member definitions
397//
398////////////////////////////////////////////////////////////////////////
399
400// Map of class names to SerializeableBuilder creation functions.
401// Need to make this a pointer so we can force initialization on the
402// first reference; otherwise, some SerializeableClass constructors
403// may be invoked before the classMap constructor.
404map<string,SerializeableClass::CreateFunc> *SerializeableClass::classMap = 0;
405
406// SerializeableClass constructor: add mapping to classMap
407SerializeableClass::SerializeableClass(const string &className,
408                                       CreateFunc createFunc)
409{
410    if (classMap == NULL)
411        classMap = new map<string,SerializeableClass::CreateFunc>();
412
413    if ((*classMap)[className])
414    {
415        cerr << "Error: simulation object class " << className << " redefined"
416             << endl;
417        fatal("");
418    }
419
420    // add className --> createFunc to class map
421    (*classMap)[className] = createFunc;
422}
423
424
425//
426//
427Serializeable *
428SerializeableClass::createObject(Checkpoint *cp,
429                                 const std::string &section)
430{
431    string className;
432
433    if (!cp->find(section, "type", className)) {
434        fatal("Serializeable::create: no 'type' entry in section '%s'.\n",
435              section);
436    }
437
438    CreateFunc createFunc = (*classMap)[className];
439
440    if (createFunc == NULL) {
441        fatal("Serializeable::create: no create function for class '%s'.\n",
442              className);
443    }
444
445    Serializeable *object = createFunc(cp, section);
446
447    assert(object != NULL);
448
449    return object;
450}
451
452
453Serializeable *
454Serializeable::create(Checkpoint *cp, const std::string &section)
455{
456    Serializeable *object = SerializeableClass::createObject(cp, section);
457    object->unserialize(cp, section);
458    return object;
459}
460
461
462Checkpoint::Checkpoint(const std::string &filename, const std::string &path,
463                       const ConfigNode *_configNode)
464    : db(new IniFile), basePath(path), configNode(_configNode)
465{
466    if (!db->load(filename)) {
467        fatal("Can't load checkpoint file '%s'\n", filename);
468    }
469
470    mainEventQueue.unserialize(this, "MainEventQueue");
471}
472
473
474bool
475Checkpoint::find(const std::string &section, const std::string &entry,
476                 std::string &value)
477{
478    return db->find(section, entry, value);
479}
480
481
482bool
483Checkpoint::findObj(const std::string &section, const std::string &entry,
484                    Serializeable *&value)
485{
486    string path;
487
488    if (!db->find(section, entry, path))
489        return false;
490
491    if ((value = configNode->resolveSimObject(path)) != NULL)
492        return true;
493
494    if ((value = objMap[path]) != NULL)
495        return true;
496
497    return false;
498}
499
500
501bool
502Checkpoint::sectionExists(const std::string &section)
503{
504    return db->sectionExists(section);
505}
506