serialize.cc revision 11793:ef606668d247
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 "sim/serialize.hh"
49
50#include <sys/stat.h>
51#include <sys/time.h>
52#include <sys/types.h>
53
54#include <cerrno>
55#include <fstream>
56#include <list>
57#include <string>
58#include <vector>
59
60#include "base/framebuffer.hh"
61#include "base/inifile.hh"
62#include "base/misc.hh"
63#include "base/output.hh"
64#include "base/str.hh"
65#include "base/trace.hh"
66#include "debug/Checkpoint.hh"
67#include "sim/eventq.hh"
68#include "sim/sim_events.hh"
69#include "sim/sim_exit.hh"
70#include "sim/sim_object.hh"
71
72// For stat reset hack
73#include "sim/stat_control.hh"
74
75using namespace std;
76
77//
78// The base implementations use to_number for parsing and '<<' for
79// displaying, suitable for integer types.
80//
81template <class T>
82bool
83parseParam(const string &s, T &value)
84{
85    return to_number(s, value);
86}
87
88template <class T>
89void
90showParam(CheckpointOut &os, const T &value)
91{
92    os << value;
93}
94
95//
96// Template specializations:
97// - char (8-bit integer)
98// - floating-point types
99// - bool
100// - string
101//
102
103// Treat 8-bit ints (chars) as ints on output, not as chars
104template <>
105void
106showParam(CheckpointOut &os, const char &value)
107{
108    os << (int)value;
109}
110
111
112template <>
113void
114showParam(CheckpointOut &os, const signed char &value)
115{
116    os << (int)value;
117}
118
119
120template <>
121void
122showParam(CheckpointOut &os, const unsigned char &value)
123{
124    os << (unsigned int)value;
125}
126
127
128template <>
129bool
130parseParam(const string &s, float &value)
131{
132    return to_number(s, value);
133}
134
135template <>
136bool
137parseParam(const string &s, double &value)
138{
139    return to_number(s, value);
140}
141
142template <>
143bool
144parseParam(const string &s, bool &value)
145{
146    return to_bool(s, value);
147}
148
149// Display bools as strings
150template <>
151void
152showParam(CheckpointOut &os, const bool &value)
153{
154    os << (value ? "true" : "false");
155}
156
157
158// String requires no processing to speak of
159template <>
160bool
161parseParam(const string &s, string &value)
162{
163    value = s;
164    return true;
165}
166
167int Serializable::ckptMaxCount = 0;
168int Serializable::ckptCount = 0;
169int Serializable::ckptPrevCount = -1;
170std::stack<std::string> Serializable::path;
171
172template <class T>
173void
174paramOut(CheckpointOut &os, const string &name, const T &param)
175{
176    os << name << "=";
177    showParam(os, param);
178    os << "\n";
179}
180
181template <class T>
182void
183arrayParamOut(CheckpointOut &os, const string &name, const vector<T> &param)
184{
185    typename vector<T>::size_type size = param.size();
186    os << name << "=";
187    if (size > 0)
188        showParam(os, param[0]);
189    for (typename vector<T>::size_type i = 1; i < size; ++i) {
190        os << " ";
191        showParam(os, param[i]);
192    }
193    os << "\n";
194}
195
196template <class T>
197void
198arrayParamOut(CheckpointOut &os, const string &name, const list<T> &param)
199{
200    typename list<T>::const_iterator it = param.begin();
201
202    os << name << "=";
203    if (param.size() > 0)
204        showParam(os, *it);
205    it++;
206    while (it != param.end()) {
207        os << " ";
208        showParam(os, *it);
209        it++;
210    }
211    os << "\n";
212}
213
214template <class T>
215void
216arrayParamOut(CheckpointOut &os, const string &name, const set<T> &param)
217{
218    typename set<T>::const_iterator it = param.begin();
219
220    os << name << "=";
221    if (param.size() > 0)
222        showParam(os, *it);
223    it++;
224    while (it != param.end()) {
225        os << " ";
226        showParam(os, *it);
227        it++;
228    }
229    os << "\n";
230}
231
232template <class T>
233void
234paramIn(CheckpointIn &cp, const string &name, T &param)
235{
236    const string &section(Serializable::currentSection());
237    string str;
238    if (!cp.find(section, name, str) || !parseParam(str, param)) {
239        fatal("Can't unserialize '%s:%s'\n", section, name);
240    }
241}
242
243template <class T>
244bool
245optParamIn(CheckpointIn &cp, const string &name, T &param, bool warn)
246{
247    const string &section(Serializable::currentSection());
248    string str;
249    if (!cp.find(section, name, str) || !parseParam(str, param)) {
250        if (warn)
251            warn("optional parameter %s:%s not present\n", section, name);
252        return false;
253    } else {
254        return true;
255    }
256}
257
258template <class T>
259void
260arrayParamOut(CheckpointOut &os, const string &name,
261              const T *param, unsigned size)
262{
263    os << name << "=";
264    if (size > 0)
265        showParam(os, param[0]);
266    for (unsigned i = 1; i < size; ++i) {
267        os << " ";
268        showParam(os, param[i]);
269    }
270    os << "\n";
271}
272
273
274template <class T>
275void
276arrayParamIn(CheckpointIn &cp, const string &name, T *param, unsigned size)
277{
278    const string &section(Serializable::currentSection());
279    string str;
280    if (!cp.find(section, name, str)) {
281        fatal("Can't unserialize '%s:%s'\n", section, name);
282    }
283
284    // code below stolen from VectorParam<T>::parse().
285    // it would be nice to unify these somehow...
286
287    vector<string> tokens;
288
289    tokenize(tokens, str, ' ');
290
291    // Need this if we were doing a vector
292    // value.resize(tokens.size());
293
294    if (tokens.size() != size) {
295        fatal("Array size mismatch on %s:%s'\n", section, name);
296    }
297
298    for (vector<string>::size_type i = 0; i < tokens.size(); i++) {
299        // need to parse into local variable to handle vector<bool>,
300        // for which operator[] returns a special reference class
301        // that's not the same as 'bool&', (since it's a packed
302        // vector)
303        T scalar_value;
304        if (!parseParam(tokens[i], scalar_value)) {
305            string err("could not parse \"");
306
307            err += str;
308            err += "\"";
309
310            fatal(err);
311        }
312
313        // assign parsed value to vector
314        param[i] = scalar_value;
315    }
316}
317
318template <class T>
319void
320arrayParamIn(CheckpointIn &cp, const string &name, vector<T> &param)
321{
322    const string &section(Serializable::currentSection());
323    string str;
324    if (!cp.find(section, name, str)) {
325        fatal("Can't unserialize '%s:%s'\n", section, name);
326    }
327
328    // code below stolen from VectorParam<T>::parse().
329    // it would be nice to unify these somehow...
330
331    vector<string> tokens;
332
333    tokenize(tokens, str, ' ');
334
335    // Need this if we were doing a vector
336    // value.resize(tokens.size());
337
338    param.resize(tokens.size());
339
340    for (vector<string>::size_type i = 0; i < tokens.size(); i++) {
341        // need to parse into local variable to handle vector<bool>,
342        // for which operator[] returns a special reference class
343        // that's not the same as 'bool&', (since it's a packed
344        // vector)
345        T scalar_value;
346        if (!parseParam(tokens[i], scalar_value)) {
347            string err("could not parse \"");
348
349            err += str;
350            err += "\"";
351
352            fatal(err);
353        }
354
355        // assign parsed value to vector
356        param[i] = scalar_value;
357    }
358}
359
360template <class T>
361void
362arrayParamIn(CheckpointIn &cp, const string &name, list<T> &param)
363{
364    const string &section(Serializable::currentSection());
365    string str;
366    if (!cp.find(section, name, str)) {
367        fatal("Can't unserialize '%s:%s'\n", section, name);
368    }
369    param.clear();
370
371    vector<string> tokens;
372    tokenize(tokens, str, ' ');
373
374    for (vector<string>::size_type i = 0; i < tokens.size(); i++) {
375        T scalar_value;
376        if (!parseParam(tokens[i], scalar_value)) {
377            string err("could not parse \"");
378
379            err += str;
380            err += "\"";
381
382            fatal(err);
383        }
384
385        // assign parsed value to vector
386        param.push_back(scalar_value);
387    }
388}
389
390template <class T>
391void
392arrayParamIn(CheckpointIn &cp, const string &name, set<T> &param)
393{
394    const string &section(Serializable::currentSection());
395    string str;
396    if (!cp.find(section, name, str)) {
397        fatal("Can't unserialize '%s:%s'\n", section, name);
398    }
399    param.clear();
400
401    vector<string> tokens;
402    tokenize(tokens, str, ' ');
403
404    for (vector<string>::size_type i = 0; i < tokens.size(); i++) {
405        T scalar_value;
406        if (!parseParam(tokens[i], scalar_value)) {
407            string err("could not parse \"");
408
409            err += str;
410            err += "\"";
411
412            fatal(err);
413        }
414
415        // assign parsed value to vector
416        param.insert(scalar_value);
417    }
418}
419
420
421void
422objParamIn(CheckpointIn &cp, const string &name, SimObject * &param)
423{
424    const string &section(Serializable::currentSection());
425    if (!cp.findObj(section, name, param)) {
426        fatal("Can't unserialize '%s:%s'\n", section, name);
427    }
428}
429
430
431#define INSTANTIATE_PARAM_TEMPLATES(type)                               \
432    template void                                                       \
433    paramOut(CheckpointOut &os, const string &name, type const &param); \
434    template void                                                       \
435    paramIn(CheckpointIn &cp, const string &name, type & param);        \
436    template bool                                                       \
437    optParamIn(CheckpointIn &cp, const string &name, type & param,      \
438               bool warn);                                              \
439    template void                                                       \
440    arrayParamOut(CheckpointOut &os, const string &name,                \
441                  type const *param, unsigned size);                    \
442    template void                                                       \
443    arrayParamIn(CheckpointIn &cp, const string &name,                  \
444                 type *param, unsigned size);                           \
445    template void                                                       \
446    arrayParamOut(CheckpointOut &os, const string &name,                \
447                  const vector<type> &param);                           \
448    template void                                                       \
449    arrayParamIn(CheckpointIn &cp, const string &name,                  \
450                 vector<type> &param);                                  \
451    template void                                                       \
452    arrayParamOut(CheckpointOut &os, const string &name,                \
453                  const list<type> &param);                             \
454    template void                                                       \
455    arrayParamIn(CheckpointIn &cp, const string &name,                  \
456                 list<type> &param);
457
458INSTANTIATE_PARAM_TEMPLATES(char)
459INSTANTIATE_PARAM_TEMPLATES(signed char)
460INSTANTIATE_PARAM_TEMPLATES(unsigned char)
461INSTANTIATE_PARAM_TEMPLATES(signed short)
462INSTANTIATE_PARAM_TEMPLATES(unsigned short)
463INSTANTIATE_PARAM_TEMPLATES(signed int)
464INSTANTIATE_PARAM_TEMPLATES(unsigned int)
465INSTANTIATE_PARAM_TEMPLATES(signed long)
466INSTANTIATE_PARAM_TEMPLATES(unsigned long)
467INSTANTIATE_PARAM_TEMPLATES(signed long long)
468INSTANTIATE_PARAM_TEMPLATES(unsigned long long)
469INSTANTIATE_PARAM_TEMPLATES(bool)
470INSTANTIATE_PARAM_TEMPLATES(float)
471INSTANTIATE_PARAM_TEMPLATES(double)
472INSTANTIATE_PARAM_TEMPLATES(string)
473INSTANTIATE_PARAM_TEMPLATES(Pixel)
474
475// set is only used with strings and furthermore doesn't agree with Pixel
476template void
477arrayParamOut(CheckpointOut &, const string &, const set<string> &);
478template void
479arrayParamIn(CheckpointIn &, const string &, set<string> &);
480
481/////////////////////////////
482
483/// Container for serializing global variables (not associated with
484/// any serialized object).
485class Globals : public Serializable
486{
487  public:
488    Globals()
489        : unserializedCurTick(0) {}
490
491    void serialize(CheckpointOut &cp) const override;
492    void unserialize(CheckpointIn &cp) override;
493
494    Tick unserializedCurTick;
495};
496
497/// The one and only instance of the Globals class.
498Globals globals;
499
500/// The version tags for this build of the simulator, to be stored in the
501/// Globals section during serialization and compared upon unserialization.
502extern std::set<std::string> version_tags;
503
504void
505Globals::serialize(CheckpointOut &cp) const
506{
507    paramOut(cp, "curTick", curTick());
508    SERIALIZE_CONTAINER(version_tags);
509}
510
511void
512Globals::unserialize(CheckpointIn &cp)
513{
514    paramIn(cp, "curTick", unserializedCurTick);
515
516    const std::string &section(Serializable::currentSection());
517    std::string str;
518    if (!cp.find(section, "version_tags", str)) {
519        warn("**********************************************************\n");
520        warn("!!!! Checkpoint uses an old versioning scheme.        !!!!\n");
521        warn("Run the checkpoint upgrader (util/cpt_upgrader.py) on your "
522             "checkpoint\n");
523        warn("**********************************************************\n");
524        return;
525    }
526
527    std::set<std::string> cpt_tags;
528    arrayParamIn(cp, "version_tags", cpt_tags); // UNSERIALIZE_CONTAINER
529
530    bool err = false;
531    for (const auto& t : version_tags) {
532        if (cpt_tags.find(t) == cpt_tags.end()) {
533            // checkpoint is missing tag that this binary has
534            if (!err) {
535                warn("*****************************************************\n");
536                warn("!!!! Checkpoint is missing the following version tags:\n");
537                err = true;
538            }
539            warn("  %s\n", t);
540        }
541    }
542    if (err) {
543        warn("You might experience some issues when restoring and should run "
544             "the checkpoint upgrader (util/cpt_upgrader.py) on your "
545             "checkpoint\n");
546        warn("**********************************************************\n");
547    }
548
549    err = false;
550    for (const auto& t : cpt_tags) {
551        if (version_tags.find(t) == version_tags.end()) {
552            // gem5 binary is missing tag that this checkpoint has
553            if (!err) {
554                warn("*****************************************************\n");
555                warn("!!!! gem5 is missing the following version tags:\n");
556                err = true;
557            }
558            warn("  %s\n", t);
559        }
560    }
561    if (err) {
562        warn("Running a checkpoint with incompatible version tags is not "
563             "supported. While it might work, you may experience incorrect "
564             "behavior or crashes.\n");
565        warn("**********************************************************\n");
566     }
567}
568
569Serializable::Serializable()
570{
571}
572
573Serializable::~Serializable()
574{
575}
576
577void
578Serializable::serializeSection(CheckpointOut &cp, const char *name) const
579{
580    Serializable::ScopedCheckpointSection sec(cp, name);
581    serialize(cp);
582}
583
584void
585Serializable::unserializeSection(CheckpointIn &cp, const char *name)
586{
587    Serializable::ScopedCheckpointSection sec(cp, name);
588    unserialize(cp);
589}
590
591void
592Serializable::serializeAll(const string &cpt_dir)
593{
594    string dir = CheckpointIn::setDir(cpt_dir);
595    if (mkdir(dir.c_str(), 0775) == -1 && errno != EEXIST)
596            fatal("couldn't mkdir %s\n", dir);
597
598    string cpt_file = dir + CheckpointIn::baseFilename;
599    ofstream outstream(cpt_file.c_str());
600    time_t t = time(NULL);
601    if (!outstream.is_open())
602        fatal("Unable to open file %s for writing\n", cpt_file.c_str());
603    outstream << "## checkpoint generated: " << ctime(&t);
604
605    globals.serializeSection(outstream, "Globals");
606
607    SimObject::serializeAll(outstream);
608}
609
610void
611Serializable::unserializeGlobals(CheckpointIn &cp)
612{
613    globals.unserializeSection(cp, "Globals");
614
615    for (uint32_t i = 0; i < numMainEventQueues; ++i)
616        mainEventQueue[i]->setCurTick(globals.unserializedCurTick);
617}
618
619Serializable::ScopedCheckpointSection::~ScopedCheckpointSection()
620{
621    assert(!path.empty());
622    DPRINTF(Checkpoint, "Popping: %s\n", path.top());
623    path.pop();
624}
625
626void
627Serializable::ScopedCheckpointSection::pushName(const char *obj_name)
628{
629    if (path.empty()) {
630        path.push(obj_name);
631    } else {
632        path.push(csprintf("%s.%s", path.top(), obj_name));
633    }
634    DPRINTF(Checkpoint, "ScopedCheckpointSection::pushName: %s\n", obj_name);
635}
636
637void
638Serializable::ScopedCheckpointSection::nameOut(CheckpointOut &cp)
639{
640    DPRINTF(Checkpoint, "ScopedCheckpointSection::nameOut: %s\n",
641            Serializable::currentSection());
642    cp << "\n[" << Serializable::currentSection() << "]\n";
643}
644
645void
646debug_serialize(const string &cpt_dir)
647{
648    Serializable::serializeAll(cpt_dir);
649}
650
651const std::string &
652Serializable::currentSection()
653{
654    assert(!path.empty());
655
656    return path.top();
657}
658
659const char *CheckpointIn::baseFilename = "m5.cpt";
660
661string CheckpointIn::currentDirectory;
662
663string
664CheckpointIn::setDir(const string &name)
665{
666    // use csprintf to insert curTick() into directory name if it
667    // appears to have a format placeholder in it.
668    currentDirectory = (name.find("%") != string::npos) ?
669        csprintf(name, curTick()) : name;
670    if (currentDirectory[currentDirectory.size() - 1] != '/')
671        currentDirectory += "/";
672    return currentDirectory;
673}
674
675string
676CheckpointIn::dir()
677{
678    return currentDirectory;
679}
680
681
682CheckpointIn::CheckpointIn(const string &cpt_dir, SimObjectResolver &resolver)
683    : db(new IniFile), objNameResolver(resolver), cptDir(setDir(cpt_dir))
684{
685    string filename = cptDir + "/" + CheckpointIn::baseFilename;
686    if (!db->load(filename)) {
687        fatal("Can't load checkpoint file '%s'\n", filename);
688    }
689}
690
691CheckpointIn::~CheckpointIn()
692{
693    delete db;
694}
695
696bool
697CheckpointIn::entryExists(const string &section, const string &entry)
698{
699    return db->entryExists(section, entry);
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