serialize.cc revision 221
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
47using namespace std;
48
49Serializer *Serializeable::serializer = NULL;
50
51Serializeable::Serializeable(const string &n)
52    : objName(n), serialized(false)
53{ }
54
55Serializeable::~Serializeable()
56{ }
57
58void
59Serializeable::mark()
60{
61    if (!serialized)
62        serializer->add_object(this);
63
64    serialized = true;
65}
66
67void
68Serializeable::nameOut(ostream &os)
69{
70    os << "\n[" << name() << "]\n";
71}
72
73void
74Serializeable::nameOut(ostream &os, const string &_name)
75{
76    os << "\n[" << _name << "]\n";
77}
78
79template <class T>
80void
81paramOut(ostream &os, const std::string &name, const T& param)
82{
83    os << name << "=";
84    showParam(os, param);
85    os << "\n";
86}
87
88
89template <class T>
90void
91paramIn(const IniFile *db, const std::string &section,
92        const std::string &name, T& param)
93{
94    std::string str;
95    if (!db->find(section, name, str) || !parseParam(str, param)) {
96        fatal("Can't unserialize '%s:%s'\n", section, name);
97    }
98}
99
100
101template <class T>
102void
103arrayParamOut(ostream &os, const std::string &name,
104              const T *param, int size)
105{
106    os << name << "=";
107    if (size > 0)
108        showParam(os, param[0]);
109    for (int i = 1; i < size; ++i) {
110        os << " ";
111        showParam(os, param[i]);
112    }
113    os << "\n";
114}
115
116
117template <class T>
118void
119arrayParamIn(const IniFile *db, const std::string &section,
120             const std::string &name, T *param, int size)
121{
122    std::string str;
123    if (!db->find(section, name, str)) {
124        fatal("Can't unserialize '%s:%s'\n", section, name);
125    }
126
127    // code below stolen from VectorParam<T>::parse().
128    // it would be nice to unify these somehow...
129
130    vector<string> tokens;
131
132    tokenize(tokens, str, ' ');
133
134    // Need this if we were doing a vector
135    // value.resize(tokens.size());
136
137    if (tokens.size() != size) {
138        fatal("Array size mismatch on %s:%s'\n", section, name);
139    }
140
141    for (int i = 0; i < tokens.size(); i++) {
142        // need to parse into local variable to handle vector<bool>,
143        // for which operator[] returns a special reference class
144        // that's not the same as 'bool&', (since it's a packed
145        // vector)
146        T scalar_value;
147        if (!parseParam(tokens[i], scalar_value)) {
148            string err("could not parse \"");
149
150            err += str;
151            err += "\"";
152
153            fatal(err);
154        }
155
156        // assign parsed value to vector
157        param[i] = scalar_value;
158    }
159}
160
161
162#define INSTANTIATE_PARAM_TEMPLATES(type)				\
163template void								\
164paramOut(ostream &os, const std::string &name, const type &param);	\
165template void								\
166paramIn(const IniFile *db, const std::string &section,			\
167        const std::string &name, type & param);				\
168template void								\
169arrayParamOut(ostream &os, const std::string &name,			\
170              const type *param, int size);				\
171template void								\
172arrayParamIn(const IniFile *db, const std::string &section,		\
173             const std::string &name, type *param, int size);
174
175
176INSTANTIATE_PARAM_TEMPLATES(int8_t)
177INSTANTIATE_PARAM_TEMPLATES(uint8_t)
178INSTANTIATE_PARAM_TEMPLATES(int16_t)
179INSTANTIATE_PARAM_TEMPLATES(uint16_t)
180INSTANTIATE_PARAM_TEMPLATES(int32_t)
181INSTANTIATE_PARAM_TEMPLATES(uint32_t)
182INSTANTIATE_PARAM_TEMPLATES(int64_t)
183INSTANTIATE_PARAM_TEMPLATES(uint64_t)
184INSTANTIATE_PARAM_TEMPLATES(bool)
185INSTANTIATE_PARAM_TEMPLATES(string)
186
187
188#if 0
189// unneeded?
190void
191Serializeable::childOut(const string &name, Serializeable *child)
192{
193    child->mark();
194    if (child->name() == "")
195        panic("child is unnamed");
196
197    out() << name << "=" << child->name() << "\n";
198}
199#endif
200
201void
202Serializeable::setName(const string &name)
203{
204    if (objName != "") {
205        cprintf("Renaming object '%s' to '%s'.\n", objName, name);
206    }
207
208    objName = name;
209}
210
211Serializer::Serializer()
212{ }
213
214Serializer::~Serializer()
215{ }
216
217ostream &
218Serializer::out() const
219{
220    if (!output)
221        panic("must set output before serializing");
222
223    return *output;
224}
225
226void
227Serializer::add_object(Serializeable *obj)
228{
229    objects.push_back(obj);
230}
231
232void
233Serializer::add_objects()
234{
235    mainEventQueue.mark();
236
237    SimObject::SimObjectList::iterator i = SimObject::simObjectList.begin();
238    SimObject::SimObjectList::iterator end = SimObject::simObjectList.end();
239
240    while (i != end) {
241        (*i)->mark();
242        ++i;
243    }
244}
245
246void
247Serializer::serialize(const string &f)
248{
249    if (Serializeable::serializer != NULL)
250        panic("in process of serializing!");
251
252    Serializeable::serializer = this;
253
254    file = f;
255    string cpt_file = file + ".cpt";
256    output = new ofstream(cpt_file.c_str());
257    time_t t = time(NULL);
258    *output << "// checkpoint generated: " << ctime(&t);
259
260    serlist_t list;
261
262    add_objects();
263    while (!objects.empty()) {
264        Serializeable *serial = objects.front();
265        DPRINTF(Serialize, "Naming children of %s\n", serial->name());
266        serial->nameChildren();
267        objects.pop_front();
268        list.push_back(serial);
269    }
270
271    while (!list.empty()) {
272        list.front()->serialized = false;
273        list.pop_front();
274    }
275
276    add_objects();
277    while (!objects.empty()) {
278        Serializeable *obj = objects.front();
279        DPRINTF(Serialize, "Serializing %s\n", obj->name());
280        obj->nameOut(out());
281        obj->serialize(out());
282        objects.pop_front();
283        list.push_back(obj);
284    }
285
286    while (!list.empty()) {
287        list.front()->serialized = false;
288        list.pop_front();
289    }
290
291    Serializeable::serializer = NULL;
292
293    delete output;
294    output = NULL;
295    file = "";
296}
297
298class SerializeEvent : public Event
299{
300  protected:
301    string file;
302
303  public:
304    SerializeEvent(EventQueue *q, Tick when, const string &file);
305    ~SerializeEvent();
306
307    virtual void process();
308    virtual void serialize(std::ostream &os);
309};
310
311SerializeEvent::SerializeEvent(EventQueue *q, Tick when, const string &f)
312    : Event(q), file(f)
313{
314    setFlags(AutoDelete);
315    schedule(when);
316}
317
318SerializeEvent::~SerializeEvent()
319{
320}
321
322void
323SerializeEvent::process()
324{
325    Serializer serial;
326    serial.serialize(file);
327    new SimExitEvent("Serialization caused exit");
328}
329
330void
331SerializeEvent::serialize(ostream &os)
332{
333    panic("Cannot serialize the SerializeEvent");
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<Counter> serialize_cycle(&serialParams,
350                                "cycle",
351                                "cycle to serialize",
352                                0);
353
354Param<string> serialize_file(&serialParams,
355                             "file",
356                             "file to write to", "");
357
358SerializeParamContext::SerializeParamContext(const string &section)
359    : ParamContext(section), event(NULL)
360{ }
361
362SerializeParamContext::~SerializeParamContext()
363{
364}
365
366void
367SerializeParamContext::checkParams()
368{
369    if (!((string)serialize_file).empty() && serialize_cycle > 0)
370    event = new SerializeEvent(&mainEventQueue, serialize_cycle,
371                               serialize_file);
372}
373
374void
375debug_serialize(const char *file)
376{
377    Serializer serial;
378    serial.serialize(file);
379    new SimExitEvent("Serialization caused exit");
380}
381
382
383
384
385////////////////////////////////////////////////////////////////////////
386//
387// SerializeableClass member definitions
388//
389////////////////////////////////////////////////////////////////////////
390
391// Map of class names to SerializeableBuilder creation functions.
392// Need to make this a pointer so we can force initialization on the
393// first reference; otherwise, some SerializeableClass constructors
394// may be invoked before the classMap constructor.
395map<string,SerializeableClass::CreateFunc> *SerializeableClass::classMap = 0;
396
397// SerializeableClass constructor: add mapping to classMap
398SerializeableClass::SerializeableClass(const string &className,
399                                       CreateFunc createFunc)
400{
401    if (classMap == NULL)
402        classMap = new map<string,SerializeableClass::CreateFunc>();
403
404    if ((*classMap)[className])
405    {
406        cerr << "Error: simulation object class " << className << " redefined"
407             << endl;
408        fatal("");
409    }
410
411    // add className --> createFunc to class map
412    (*classMap)[className] = createFunc;
413}
414
415
416//
417//
418Serializeable *
419SerializeableClass::createObject(IniFile &configDB,
420                                 const string &configClassName)
421{
422    // find simulation object class name from configuration class
423    // (specified by 'type=' parameter)
424    string simObjClassName;
425
426    if (!configDB.findDefault(configClassName, "type", simObjClassName)) {
427        cerr << "Configuration class '" << configClassName << "' not found."
428             << endl;
429        abort();
430    }
431
432    // look up className to get appropriate createFunc
433    if (classMap->find(simObjClassName) == classMap->end()) {
434        cerr << "Simulator object class '" << simObjClassName << "' not found."
435             << endl;
436        abort();
437    }
438
439    CreateFunc createFunc = (*classMap)[simObjClassName];
440
441    // builder instance
442    SerializeableBuilder *objectBuilder = (*createFunc)();
443
444    assert(objectBuilder != NULL);
445
446    // now create the actual simulation object
447    Serializeable *object = objectBuilder->create();
448
449    assert(object != NULL);
450
451    // done with the SerializeableBuilder now
452    delete objectBuilder;
453
454    return object;
455}
456
457