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