serialize.cc revision 10386:c81407818741
1/*
2 * Copyright (c) 2002-2005 The Regents of The University of Michigan
3 * Copyright (c) 2013 Advanced Micro Devices, Inc.
4 * Copyright (c) 2013 Mark D. Hill and David A. Wood
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions are
9 * met: redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer;
11 * redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution;
14 * neither the name of the copyright holders nor the names of its
15 * contributors may be used to endorse or promote products derived from
16 * this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 *
30 * Authors: Nathan Binkert
31 *          Erik Hallnor
32 *          Steve Reinhardt
33 */
34
35#include <sys/stat.h>
36#include <sys/time.h>
37#include <sys/types.h>
38
39#include <cerrno>
40#include <fstream>
41#include <list>
42#include <string>
43#include <vector>
44
45#include "base/inifile.hh"
46#include "base/misc.hh"
47#include "base/output.hh"
48#include "base/str.hh"
49#include "base/trace.hh"
50#include "sim/eventq.hh"
51#include "sim/serialize.hh"
52#include "sim/sim_events.hh"
53#include "sim/sim_exit.hh"
54#include "sim/sim_object.hh"
55
56// For stat reset hack
57#include "sim/stat_control.hh"
58
59using namespace std;
60
61extern SimObject *resolveSimObject(const string &);
62
63//
64// The base implementations use to_number for parsing and '<<' for
65// displaying, suitable for integer types.
66//
67template <class T>
68bool
69parseParam(const string &s, T &value)
70{
71    return to_number(s, value);
72}
73
74template <class T>
75void
76showParam(ostream &os, const T &value)
77{
78    os << value;
79}
80
81//
82// Template specializations:
83// - char (8-bit integer)
84// - floating-point types
85// - bool
86// - string
87//
88
89// Treat 8-bit ints (chars) as ints on output, not as chars
90template <>
91void
92showParam(ostream &os, const char &value)
93{
94    os << (int)value;
95}
96
97
98template <>
99void
100showParam(ostream &os, const signed char &value)
101{
102    os << (int)value;
103}
104
105
106template <>
107void
108showParam(ostream &os, const unsigned char &value)
109{
110    os << (unsigned int)value;
111}
112
113
114template <>
115bool
116parseParam(const string &s, float &value)
117{
118    return to_number(s, value);
119}
120
121template <>
122bool
123parseParam(const string &s, double &value)
124{
125    return to_number(s, value);
126}
127
128template <>
129bool
130parseParam(const string &s, bool &value)
131{
132    return to_bool(s, value);
133}
134
135// Display bools as strings
136template <>
137void
138showParam(ostream &os, const bool &value)
139{
140    os << (value ? "true" : "false");
141}
142
143
144// String requires no processing to speak of
145template <>
146bool
147parseParam(const string &s, string &value)
148{
149    value = s;
150    return true;
151}
152
153int Serializable::ckptMaxCount = 0;
154int Serializable::ckptCount = 0;
155int Serializable::ckptPrevCount = -1;
156
157void
158Serializable::nameOut(ostream &os)
159{
160    os << "\n[" << name() << "]\n";
161}
162
163void
164Serializable::nameOut(ostream &os, const string &_name)
165{
166    os << "\n[" << _name << "]\n";
167}
168
169template <class T>
170void
171paramOut(ostream &os, const string &name, const T &param)
172{
173    os << name << "=";
174    showParam(os, param);
175    os << "\n";
176}
177
178template <class T>
179void
180arrayParamOut(ostream &os, const string &name, const vector<T> &param)
181{
182    typename vector<T>::size_type size = param.size();
183    os << name << "=";
184    if (size > 0)
185        showParam(os, param[0]);
186    for (typename vector<T>::size_type i = 1; i < size; ++i) {
187        os << " ";
188        showParam(os, param[i]);
189    }
190    os << "\n";
191}
192
193template <class T>
194void
195arrayParamOut(ostream &os, const string &name, const list<T> &param)
196{
197    typename list<T>::const_iterator it = param.begin();
198
199    os << name << "=";
200    if (param.size() > 0)
201        showParam(os, *it);
202    it++;
203    while (it != param.end()) {
204        os << " ";
205        showParam(os, *it);
206        it++;
207    }
208    os << "\n";
209}
210
211template <class T>
212void
213paramIn(Checkpoint *cp, const string &section, const string &name, T &param)
214{
215    string str;
216    if (!cp->find(section, name, str) || !parseParam(str, param)) {
217        fatal("Can't unserialize '%s:%s'\n", section, name);
218    }
219}
220
221template <class T>
222bool
223optParamIn(Checkpoint *cp, const string &section, const string &name, T &param)
224{
225    string str;
226    if (!cp->find(section, name, str) || !parseParam(str, param)) {
227        warn("optional parameter %s:%s not present\n", section, name);
228        return false;
229    } else {
230        return true;
231    }
232}
233
234template <class T>
235void
236arrayParamOut(ostream &os, const string &name, const T *param, unsigned size)
237{
238    os << name << "=";
239    if (size > 0)
240        showParam(os, param[0]);
241    for (unsigned i = 1; i < size; ++i) {
242        os << " ";
243        showParam(os, param[i]);
244    }
245    os << "\n";
246}
247
248
249template <class T>
250void
251arrayParamIn(Checkpoint *cp, const string &section, const string &name,
252             T *param, unsigned size)
253{
254    string str;
255    if (!cp->find(section, name, str)) {
256        fatal("Can't unserialize '%s:%s'\n", section, name);
257    }
258
259    // code below stolen from VectorParam<T>::parse().
260    // it would be nice to unify these somehow...
261
262    vector<string> tokens;
263
264    tokenize(tokens, str, ' ');
265
266    // Need this if we were doing a vector
267    // value.resize(tokens.size());
268
269    if (tokens.size() != size) {
270        fatal("Array size mismatch on %s:%s'\n", section, name);
271    }
272
273    for (vector<string>::size_type i = 0; i < tokens.size(); i++) {
274        // need to parse into local variable to handle vector<bool>,
275        // for which operator[] returns a special reference class
276        // that's not the same as 'bool&', (since it's a packed
277        // vector)
278        T scalar_value = 0;
279        if (!parseParam(tokens[i], scalar_value)) {
280            string err("could not parse \"");
281
282            err += str;
283            err += "\"";
284
285            fatal(err);
286        }
287
288        // assign parsed value to vector
289        param[i] = scalar_value;
290    }
291}
292
293template <class T>
294void
295arrayParamIn(Checkpoint *cp, const string &section,
296             const string &name, vector<T> &param)
297{
298    string str;
299    if (!cp->find(section, name, str)) {
300        fatal("Can't unserialize '%s:%s'\n", section, name);
301    }
302
303    // code below stolen from VectorParam<T>::parse().
304    // it would be nice to unify these somehow...
305
306    vector<string> tokens;
307
308    tokenize(tokens, str, ' ');
309
310    // Need this if we were doing a vector
311    // value.resize(tokens.size());
312
313    param.resize(tokens.size());
314
315    for (vector<string>::size_type i = 0; i < tokens.size(); i++) {
316        // need to parse into local variable to handle vector<bool>,
317        // for which operator[] returns a special reference class
318        // that's not the same as 'bool&', (since it's a packed
319        // vector)
320        T scalar_value = 0;
321        if (!parseParam(tokens[i], scalar_value)) {
322            string err("could not parse \"");
323
324            err += str;
325            err += "\"";
326
327            fatal(err);
328        }
329
330        // assign parsed value to vector
331        param[i] = scalar_value;
332    }
333}
334
335template <class T>
336void
337arrayParamIn(Checkpoint *cp, const string &section,
338             const string &name, list<T> &param)
339{
340    string str;
341    if (!cp->find(section, name, str)) {
342        fatal("Can't unserialize '%s:%s'\n", section, name);
343    }
344    param.clear();
345
346    vector<string> tokens;
347    tokenize(tokens, str, ' ');
348
349    for (vector<string>::size_type i = 0; i < tokens.size(); i++) {
350        T scalar_value = 0;
351        if (!parseParam(tokens[i], scalar_value)) {
352            string err("could not parse \"");
353
354            err += str;
355            err += "\"";
356
357            fatal(err);
358        }
359
360        // assign parsed value to vector
361        param.push_back(scalar_value);
362    }
363}
364
365
366void
367objParamIn(Checkpoint *cp, const string &section,
368           const string &name, SimObject * &param)
369{
370    if (!cp->findObj(section, name, param)) {
371        fatal("Can't unserialize '%s:%s'\n", section, name);
372    }
373}
374
375
376#define INSTANTIATE_PARAM_TEMPLATES(type)                               \
377template void                                                           \
378paramOut(ostream &os, const string &name, type const &param);           \
379template void                                                           \
380paramIn(Checkpoint *cp, const string &section,                          \
381        const string &name, type & param);                              \
382template bool                                                           \
383optParamIn(Checkpoint *cp, const string &section,                       \
384        const string &name, type & param);                              \
385template void                                                           \
386arrayParamOut(ostream &os, const string &name,                          \
387              type const *param, unsigned size);                        \
388template void                                                           \
389arrayParamIn(Checkpoint *cp, const string &section,                     \
390             const string &name, type *param, unsigned size);           \
391template void                                                           \
392arrayParamOut(ostream &os, const string &name,                          \
393              const vector<type> &param);                               \
394template void                                                           \
395arrayParamIn(Checkpoint *cp, const string &section,                     \
396             const string &name, vector<type> &param);                  \
397template void                                                           \
398arrayParamOut(ostream &os, const string &name,                          \
399              const list<type> &param);                                 \
400template void                                                           \
401arrayParamIn(Checkpoint *cp, const string &section,                     \
402             const string &name, list<type> &param);
403
404INSTANTIATE_PARAM_TEMPLATES(char)
405INSTANTIATE_PARAM_TEMPLATES(signed char)
406INSTANTIATE_PARAM_TEMPLATES(unsigned char)
407INSTANTIATE_PARAM_TEMPLATES(signed short)
408INSTANTIATE_PARAM_TEMPLATES(unsigned short)
409INSTANTIATE_PARAM_TEMPLATES(signed int)
410INSTANTIATE_PARAM_TEMPLATES(unsigned int)
411INSTANTIATE_PARAM_TEMPLATES(signed long)
412INSTANTIATE_PARAM_TEMPLATES(unsigned long)
413INSTANTIATE_PARAM_TEMPLATES(signed long long)
414INSTANTIATE_PARAM_TEMPLATES(unsigned long long)
415INSTANTIATE_PARAM_TEMPLATES(bool)
416INSTANTIATE_PARAM_TEMPLATES(float)
417INSTANTIATE_PARAM_TEMPLATES(double)
418INSTANTIATE_PARAM_TEMPLATES(string)
419
420
421/////////////////////////////
422
423/// Container for serializing global variables (not associated with
424/// any serialized object).
425class Globals : public Serializable
426{
427  public:
428    const string name() const;
429    void serialize(ostream &os);
430    void unserialize(Checkpoint *cp, const std::string &section);
431};
432
433/// The one and only instance of the Globals class.
434Globals globals;
435
436const string
437Globals::name() const
438{
439    return "Globals";
440}
441
442void
443Globals::serialize(ostream &os)
444{
445    nameOut(os);
446    paramOut(os, "curTick", curTick());
447
448    paramOut(os, "numMainEventQueues", numMainEventQueues);
449
450    for (uint32_t i = 0; i < numMainEventQueues; ++i) {
451        nameOut(os, "MainEventQueue");
452        mainEventQueue[i]->serialize(os);
453    }
454}
455
456void
457Globals::unserialize(Checkpoint *cp, const std::string &section)
458{
459    Tick tick;
460    paramIn(cp, section, "curTick", tick);
461    paramIn(cp, section, "numMainEventQueues", numMainEventQueues);
462
463    for (uint32_t i = 0; i < numMainEventQueues; ++i) {
464        mainEventQueue[i]->setCurTick(tick);
465        mainEventQueue[i]->unserialize(cp, "MainEventQueue");
466    }
467}
468
469Serializable::Serializable()
470{
471}
472
473Serializable::~Serializable()
474{
475}
476
477void
478Serializable::serialize(ostream &os)
479{
480}
481
482void
483Serializable::unserialize(Checkpoint *cp, const string &section)
484{
485}
486
487void
488Serializable::serializeAll(const string &cpt_dir)
489{
490    string dir = Checkpoint::setDir(cpt_dir);
491    if (mkdir(dir.c_str(), 0775) == -1 && errno != EEXIST)
492            fatal("couldn't mkdir %s\n", dir);
493
494    string cpt_file = dir + Checkpoint::baseFilename;
495    ofstream outstream(cpt_file.c_str());
496    time_t t = time(NULL);
497    if (!outstream.is_open())
498        fatal("Unable to open file %s for writing\n", cpt_file.c_str());
499    outstream << "## checkpoint generated: " << ctime(&t);
500
501    globals.serialize(outstream);
502    SimObject::serializeAll(outstream);
503}
504
505void
506Serializable::unserializeGlobals(Checkpoint *cp)
507{
508  globals.unserialize(cp, globals.name());
509}
510
511void
512debug_serialize(const string &cpt_dir)
513{
514    Serializable::serializeAll(cpt_dir);
515}
516
517
518////////////////////////////////////////////////////////////////////////
519//
520// SerializableClass member definitions
521//
522////////////////////////////////////////////////////////////////////////
523
524// Map of class names to SerializableBuilder creation functions.
525// Need to make this a pointer so we can force initialization on the
526// first reference; otherwise, some SerializableClass constructors
527// may be invoked before the classMap constructor.
528map<string, SerializableClass::CreateFunc> *SerializableClass::classMap = 0;
529
530// SerializableClass constructor: add mapping to classMap
531SerializableClass::SerializableClass(const string &className,
532                                     CreateFunc createFunc)
533{
534    if (classMap == NULL)
535        classMap = new map<string, SerializableClass::CreateFunc>();
536
537    if ((*classMap)[className])
538        fatal("Error: simulation object class %s redefined\n", className);
539
540    // add className --> createFunc to class map
541    (*classMap)[className] = createFunc;
542}
543
544//
545//
546Serializable *
547SerializableClass::createObject(Checkpoint *cp, const string &section)
548{
549    string className;
550
551    if (!cp->find(section, "type", className)) {
552        fatal("Serializable::create: no 'type' entry in section '%s'.\n",
553              section);
554    }
555
556    CreateFunc createFunc = (*classMap)[className];
557
558    if (createFunc == NULL) {
559        fatal("Serializable::create: no create function for class '%s'.\n",
560              className);
561    }
562
563    Serializable *object = createFunc(cp, section);
564
565    assert(object != NULL);
566
567    return object;
568}
569
570
571Serializable *
572Serializable::create(Checkpoint *cp, const string &section)
573{
574    Serializable *object = SerializableClass::createObject(cp, section);
575    object->unserialize(cp, section);
576    return object;
577}
578
579
580const char *Checkpoint::baseFilename = "m5.cpt";
581
582string Checkpoint::currentDirectory;
583
584string
585Checkpoint::setDir(const string &name)
586{
587    // use csprintf to insert curTick() into directory name if it
588    // appears to have a format placeholder in it.
589    currentDirectory = (name.find("%") != string::npos) ?
590        csprintf(name, curTick()) : name;
591    if (currentDirectory[currentDirectory.size() - 1] != '/')
592        currentDirectory += "/";
593    return currentDirectory;
594}
595
596string
597Checkpoint::dir()
598{
599    return currentDirectory;
600}
601
602
603Checkpoint::Checkpoint(const string &cpt_dir)
604    : db(new IniFile), cptDir(setDir(cpt_dir))
605{
606    string filename = cptDir + "/" + Checkpoint::baseFilename;
607    if (!db->load(filename)) {
608        fatal("Can't load checkpoint file '%s'\n", filename);
609    }
610}
611
612Checkpoint::~Checkpoint()
613{
614    delete db;
615}
616
617bool
618Checkpoint::find(const string &section, const string &entry, string &value)
619{
620    return db->find(section, entry, value);
621}
622
623
624bool
625Checkpoint::findObj(const string &section, const string &entry,
626                    SimObject *&value)
627{
628    string path;
629
630    if (!db->find(section, entry, path))
631        return false;
632
633    value = resolveSimObject(path);
634    return true;
635}
636
637
638bool
639Checkpoint::sectionExists(const string &section)
640{
641    return db->sectionExists(section);
642}
643