serialize.cc revision 10386:c81407818741
1848SN/A/*
29956SN/A * Copyright (c) 2002-2005 The Regents of The University of Michigan
39956SN/A * Copyright (c) 2013 Advanced Micro Devices, Inc.
49956SN/A * Copyright (c) 2013 Mark D. Hill and David A. Wood
59956SN/A * All rights reserved.
69956SN/A *
79956SN/A * Redistribution and use in source and binary forms, with or without
89956SN/A * modification, are permitted provided that the following conditions are
99956SN/A * met: redistributions of source code must retain the above copyright
109956SN/A * notice, this list of conditions and the following disclaimer;
119956SN/A * redistributions in binary form must reproduce the above copyright
129956SN/A * notice, this list of conditions and the following disclaimer in the
139956SN/A * documentation and/or other materials provided with the distribution;
141762SN/A * neither the name of the copyright holders nor the names of its
15848SN/A * contributors may be used to endorse or promote products derived from
16848SN/A * this software without specific prior written permission.
17848SN/A *
18848SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19848SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20848SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21848SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22848SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23848SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24848SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25848SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26848SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27848SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28848SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29848SN/A *
30848SN/A * Authors: Nathan Binkert
31848SN/A *          Erik Hallnor
32848SN/A *          Steve Reinhardt
33848SN/A */
34848SN/A
35848SN/A#include <sys/stat.h>
36848SN/A#include <sys/time.h>
37848SN/A#include <sys/types.h>
38848SN/A
392665SN/A#include <cerrno>
402665SN/A#include <fstream>
41848SN/A#include <list>
42848SN/A#include <string>
43848SN/A#include <vector>
44848SN/A
45848SN/A#include "base/inifile.hh"
46848SN/A#include "base/misc.hh"
4711264Sandreas.sandberg@arm.com#include "base/output.hh"
4811264Sandreas.sandberg@arm.com#include "base/str.hh"
49848SN/A#include "base/trace.hh"
502275SN/A#include "sim/eventq.hh"
51848SN/A#include "sim/serialize.hh"
5211264Sandreas.sandberg@arm.com#include "sim/sim_events.hh"
5311264Sandreas.sandberg@arm.com#include "sim/sim_exit.hh"
5411264Sandreas.sandberg@arm.com#include "sim/sim_object.hh"
5511264Sandreas.sandberg@arm.com
568229SN/A// For stat reset hack
57849SN/A#include "sim/stat_control.hh"
58848SN/A
593090SN/Ausing namespace std;
603090SN/A
618522SN/Aextern SimObject *resolveSimObject(const string &);
62849SN/A
638522SN/A//
648522SN/A// The base implementations use to_number for parsing and '<<' for
658522SN/A// displaying, suitable for integer types.
66849SN/A//
67849SN/Atemplate <class T>
68849SN/Abool
69849SN/AparseParam(const string &s, T &value)
70849SN/A{
71849SN/A    return to_number(s, value);
72849SN/A}
73849SN/A
74849SN/Atemplate <class T>
75849SN/Avoid
76849SN/AshowParam(ostream &os, const T &value)
77849SN/A{
78849SN/A    os << value;
79849SN/A}
80849SN/A
81849SN/A//
82849SN/A// Template specializations:
83849SN/A// - char (8-bit integer)
84849SN/A// - floating-point types
85849SN/A// - bool
86896SN/A// - string
87849SN/A//
888522SN/A
89849SN/A// Treat 8-bit ints (chars) as ints on output, not as chars
90849SN/Atemplate <>
91849SN/Avoid
92849SN/AshowParam(ostream &os, const char &value)
93849SN/A{
94849SN/A    os << (int)value;
95849SN/A}
96849SN/A
97849SN/A
98849SN/Atemplate <>
99849SN/Avoid
100849SN/AshowParam(ostream &os, const signed char &value)
101849SN/A{
102849SN/A    os << (int)value;
103849SN/A}
104849SN/A
105849SN/A
1061817SN/Atemplate <>
107849SN/Avoid
108849SN/AshowParam(ostream &os, const unsigned char &value)
109849SN/A{
110849SN/A    os << (unsigned int)value;
111849SN/A}
112849SN/A
113849SN/A
114849SN/Atemplate <>
115849SN/Abool
116849SN/AparseParam(const string &s, float &value)
117849SN/A{
118849SN/A    return to_number(s, value);
119893SN/A}
120893SN/A
121864SN/Atemplate <>
122849SN/Abool
123849SN/AparseParam(const string &s, double &value)
124849SN/A{
125849SN/A    return to_number(s, value);
126849SN/A}
1271817SN/A
1281817SN/Atemplate <>
129849SN/Abool
130849SN/AparseParam(const string &s, bool &value)
131849SN/A{
132849SN/A    return to_bool(s, value);
133849SN/A}
134849SN/A
135849SN/A// Display bools as strings
136849SN/Atemplate <>
137893SN/Avoid
138849SN/AshowParam(ostream &os, const bool &value)
139849SN/A{
140864SN/A    os << (value ? "true" : "false");
141864SN/A}
142864SN/A
143864SN/A
144864SN/A// String requires no processing to speak of
145864SN/Atemplate <>
146864SN/Abool
147864SN/AparseParam(const string &s, string &value)
148864SN/A{
149864SN/A    value = s;
150849SN/A    return true;
151849SN/A}
152849SN/A
153849SN/Aint Serializable::ckptMaxCount = 0;
154849SN/Aint Serializable::ckptCount = 0;
155893SN/Aint Serializable::ckptPrevCount = -1;
156849SN/A
157849SN/Avoid
158849SN/ASerializable::nameOut(ostream &os)
159849SN/A{
160849SN/A    os << "\n[" << name() << "]\n";
161849SN/A}
162849SN/A
163893SN/Avoid
164893SN/ASerializable::nameOut(ostream &os, const string &_name)
165893SN/A{
166849SN/A    os << "\n[" << _name << "]\n";
167849SN/A}
168849SN/A
169849SN/Atemplate <class T>
170849SN/Avoid
171849SN/AparamOut(ostream &os, const string &name, const T &param)
172849SN/A{
173849SN/A    os << name << "=";
174893SN/A    showParam(os, param);
175893SN/A    os << "\n";
176893SN/A}
177849SN/A
178849SN/Atemplate <class T>
179849SN/Avoid
180849SN/AarrayParamOut(ostream &os, const string &name, const vector<T> &param)
181849SN/A{
182849SN/A    typename vector<T>::size_type size = param.size();
183849SN/A    os << name << "=";
184849SN/A    if (size > 0)
185849SN/A        showParam(os, param[0]);
186849SN/A    for (typename vector<T>::size_type i = 1; i < size; ++i) {
187849SN/A        os << " ";
188849SN/A        showParam(os, param[i]);
189849SN/A    }
190849SN/A    os << "\n";
191849SN/A}
1929956SN/A
1939956SN/Atemplate <class T>
194849SN/Avoid
195849SN/AarrayParamOut(ostream &os, const string &name, const list<T> &param)
196849SN/A{
197849SN/A    typename list<T>::const_iterator it = param.begin();
198849SN/A
199849SN/A    os << name << "=";
200849SN/A    if (param.size() > 0)
201849SN/A        showParam(os, *it);
202848SN/A    it++;
203848SN/A    while (it != param.end()) {
204848SN/A        os << " ";
205849SN/A        showParam(os, *it);
206848SN/A        it++;
207848SN/A    }
208848SN/A    os << "\n";
209848SN/A}
210848SN/A
211848SN/Atemplate <class T>
212848SN/Avoid
213848SN/AparamIn(Checkpoint *cp, const string &section, const string &name, T &param)
214848SN/A{
215848SN/A    string str;
216864SN/A    if (!cp->find(section, name, str) || !parseParam(str, param)) {
217848SN/A        fatal("Can't unserialize '%s:%s'\n", section, name);
218848SN/A    }
219849SN/A}
220849SN/A
2211722SN/Atemplate <class T>
222849SN/Abool
223849SN/AoptParamIn(Checkpoint *cp, const string &section, const string &name, T &param)
224893SN/A{
225893SN/A    string str;
226849SN/A    if (!cp->find(section, name, str) || !parseParam(str, param)) {
227849SN/A        warn("optional parameter %s:%s not present\n", section, name);
228849SN/A        return false;
229849SN/A    } else {
230849SN/A        return true;
231849SN/A    }
232849SN/A}
233849SN/A
234893SN/Atemplate <class T>
235893SN/Avoid
236849SN/AarrayParamOut(ostream &os, const string &name, const T *param, unsigned size)
237849SN/A{
238849SN/A    os << name << "=";
239849SN/A    if (size > 0)
240849SN/A        showParam(os, param[0]);
241849SN/A    for (unsigned i = 1; i < size; ++i) {
242849SN/A        os << " ";
243849SN/A        showParam(os, param[i]);
244849SN/A    }
245849SN/A    os << "\n";
246849SN/A}
247849SN/A
248849SN/A
249849SN/Atemplate <class T>
250849SN/Avoid
251849SN/AarrayParamIn(Checkpoint *cp, const string &section, const string &name,
2529956SN/A             T *param, unsigned size)
2539956SN/A{
254849SN/A    string str;
2555999SN/A    if (!cp->find(section, name, str)) {
2565999SN/A        fatal("Can't unserialize '%s:%s'\n", section, name);
2575999SN/A    }
2585999SN/A
2595999SN/A    // code below stolen from VectorParam<T>::parse().
2605999SN/A    // it would be nice to unify these somehow...
2612275SN/A
262848SN/A    vector<string> tokens;
2635034SN/A
2645034SN/A    tokenize(tokens, str, ' ');
265848SN/A
266848SN/A    // Need this if we were doing a vector
267848SN/A    // value.resize(tokens.size());
268848SN/A
269848SN/A    if (tokens.size() != size) {
270848SN/A        fatal("Array size mismatch on %s:%s'\n", section, name);
271848SN/A    }
272893SN/A
273893SN/A    for (vector<string>::size_type i = 0; i < tokens.size(); i++) {
274893SN/A        // need to parse into local variable to handle vector<bool>,
275893SN/A        // for which operator[] returns a special reference class
276893SN/A        // that's not the same as 'bool&', (since it's a packed
2772629SN/A        // vector)
2782629SN/A        T scalar_value = 0;
27911169SN/A        if (!parseParam(tokens[i], scalar_value)) {
2802629SN/A            string err("could not parse \"");
2812629SN/A
282848SN/A            err += str;
283848SN/A            err += "\"";
284848SN/A
2852565SN/A            fatal(err);
286848SN/A        }
287848SN/A
288848SN/A        // assign parsed value to vector
289848SN/A        param[i] = scalar_value;
290849SN/A    }
2915772SN/A}
2925772SN/A
2935772SN/Atemplate <class T>
2945772SN/Avoid
295848SN/AarrayParamIn(Checkpoint *cp, const string &section,
296849SN/A             const string &name, vector<T> &param)
297849SN/A{
298849SN/A    string str;
299849SN/A    if (!cp->find(section, name, str)) {
300849SN/A        fatal("Can't unserialize '%s:%s'\n", section, name);
301849SN/A    }
302849SN/A
303849SN/A    // code below stolen from VectorParam<T>::parse().
304849SN/A    // it would be nice to unify these somehow...
305849SN/A
306849SN/A    vector<string> tokens;
307849SN/A
308849SN/A    tokenize(tokens, str, ' ');
30912087Sspwilson2@wisc.edu
310849SN/A    // Need this if we were doing a vector
3112565SN/A    // value.resize(tokens.size());
3122565SN/A
313849SN/A    param.resize(tokens.size());
3142565SN/A
31512087Sspwilson2@wisc.edu    for (vector<string>::size_type i = 0; i < tokens.size(); i++) {
316849SN/A        // need to parse into local variable to handle vector<bool>,
3172565SN/A        // for which operator[] returns a special reference class
3182565SN/A        // that's not the same as 'bool&', (since it's a packed
319849SN/A        // vector)
3202565SN/A        T scalar_value = 0;
32112087Sspwilson2@wisc.edu        if (!parseParam(tokens[i], scalar_value)) {
322849SN/A            string err("could not parse \"");
323849SN/A
32412087Sspwilson2@wisc.edu            err += str;
325849SN/A            err += "\"";
326849SN/A
32712087Sspwilson2@wisc.edu            fatal(err);
328849SN/A        }
329849SN/A
33012087Sspwilson2@wisc.edu        // assign parsed value to vector
331849SN/A        param[i] = scalar_value;
332849SN/A    }
333849SN/A}
334849SN/A
335849SN/Atemplate <class T>
336849SN/Avoid
337849SN/AarrayParamIn(Checkpoint *cp, const string &section,
338849SN/A             const string &name, list<T> &param)
339849SN/A{
340893SN/A    string str;
341849SN/A    if (!cp->find(section, name, str)) {
342929SN/A        fatal("Can't unserialize '%s:%s'\n", section, name);
343849SN/A    }
344849SN/A    param.clear();
345849SN/A
346849SN/A    vector<string> tokens;
347893SN/A    tokenize(tokens, str, ' ');
348849SN/A
349893SN/A    for (vector<string>::size_type i = 0; i < tokens.size(); i++) {
350893SN/A        T scalar_value = 0;
351893SN/A        if (!parseParam(tokens[i], scalar_value)) {
352849SN/A            string err("could not parse \"");
353849SN/A
354849SN/A            err += str;
355849SN/A            err += "\"";
356849SN/A
357849SN/A            fatal(err);
358849SN/A        }
359848SN/A
360864SN/A        // assign parsed value to vector
361864SN/A        param.push_back(scalar_value);
36211168SN/A    }
36311168SN/A}
364848SN/A
365848SN/A
366848SN/Avoid
36711264Sandreas.sandberg@arm.comobjParamIn(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