serialize.hh revision 13414
1/*
2 * Copyright (c) 2015, 2018 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 * All rights reserved.
16 *
17 * Redistribution and use in source and binary forms, with or without
18 * modification, are permitted provided that the following conditions are
19 * met: redistributions of source code must retain the above copyright
20 * notice, this list of conditions and the following disclaimer;
21 * redistributions in binary form must reproduce the above copyright
22 * notice, this list of conditions and the following disclaimer in the
23 * documentation and/or other materials provided with the distribution;
24 * neither the name of the copyright holders nor the names of its
25 * contributors may be used to endorse or promote products derived from
26 * this software without specific prior written permission.
27 *
28 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
29 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
30 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
31 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
32 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
33 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
34 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
35 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
36 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
37 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
38 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
39 *
40 * Authors: Nathan Binkert
41 *          Erik Hallnor
42 *          Steve Reinhardt
43 *          Andreas Sandberg
44 */
45
46/* @file
47 * Serialization Interface Declarations
48 */
49
50#ifndef __SERIALIZE_HH__
51#define __SERIALIZE_HH__
52
53
54#include <algorithm>
55#include <iostream>
56#include <list>
57#include <map>
58#include <stack>
59#include <set>
60#include <vector>
61
62#include "base/bitunion.hh"
63#include "base/logging.hh"
64#include "base/str.hh"
65
66class IniFile;
67class SimObject;
68class SimObjectResolver;
69
70typedef std::ostream CheckpointOut;
71
72class CheckpointIn
73{
74  private:
75
76    IniFile *db;
77
78    SimObjectResolver &objNameResolver;
79
80  public:
81    CheckpointIn(const std::string &cpt_dir, SimObjectResolver &resolver);
82    ~CheckpointIn();
83
84    const std::string cptDir;
85
86    bool find(const std::string &section, const std::string &entry,
87              std::string &value);
88
89    bool findObj(const std::string &section, const std::string &entry,
90                 SimObject *&value);
91
92
93    bool entryExists(const std::string &section, const std::string &entry);
94    bool sectionExists(const std::string &section);
95
96    // The following static functions have to do with checkpoint
97    // creation rather than restoration.  This class makes a handy
98    // namespace for them though.  Currently no Checkpoint object is
99    // created on serialization (only unserialization) so we track the
100    // directory name as a global.  It would be nice to change this
101    // someday
102
103  private:
104    // current directory we're serializing into.
105    static std::string currentDirectory;
106
107  public:
108    // Set the current directory.  This function takes care of
109    // inserting curTick() if there's a '%d' in the argument, and
110    // appends a '/' if necessary.  The final name is returned.
111    static std::string setDir(const std::string &base_name);
112
113    // Export current checkpoint directory name so other objects can
114    // derive filenames from it (e.g., memory).  The return value is
115    // guaranteed to end in '/' so filenames can be directly appended.
116    // This function is only valid while a checkpoint is being created.
117    static std::string dir();
118
119    // Filename for base checkpoint file within directory.
120    static const char *baseFilename;
121};
122
123/**
124 * Basic support for object serialization.
125 *
126 * Objects that support serialization should derive from this
127 * class. Such objects can largely be divided into two categories: 1)
128 * True SimObjects (deriving from SimObject), and 2) child objects
129 * (non-SimObjects).
130 *
131 * SimObjects are serialized automatically into their own sections
132 * automatically by the SimObject base class (see
133 * SimObject::serializeAll().
134 *
135 * SimObjects can contain other serializable objects that are not
136 * SimObjects. Much like normal serialized members are not serialized
137 * automatically, these objects will not be serialized automatically
138 * and it is expected that the objects owning such serializable
139 * objects call the required serialization/unserialization methods on
140 * child objects. The preferred method to serialize a child object is
141 * to call serializeSection() on the child, which serializes the
142 * object into a new subsection in the current section. Another option
143 * is to call serialize() directly, which serializes the object into
144 * the current section. The latter is not recommended as it can lead
145 * to naming clashes between objects.
146 *
147 * @note Many objects that support serialization need to be put in a
148 * consistent state when serialization takes place. We refer to the
149 * action of forcing an object into a consistent state as
150 * 'draining'. Objects that need draining inherit from Drainable. See
151 * Drainable for more information.
152 */
153class Serializable
154{
155  protected:
156    /**
157     * Scoped checkpoint section helper class
158     *
159     * This helper class creates a section within a checkpoint without
160     * the need for a separate serializeable object. It is mainly used
161     * within the Serializable class when serializing or unserializing
162     * section (see serializeSection() and unserializeSection()). It
163     * can also be used to maintain backwards compatibility in
164     * existing code that serializes structs that are not inheriting
165     * from Serializable into subsections.
166     *
167     * When the class is instantiated, it appends a name to the active
168     * path in a checkpoint. The old path is later restored when the
169     * instance is destroyed. For example, serializeSection() could be
170     * implemented by instantiating a ScopedCheckpointSection and then
171     * calling serialize() on an object.
172     */
173    class ScopedCheckpointSection {
174      public:
175        template<class CP>
176        ScopedCheckpointSection(CP &cp, const char *name) {
177            pushName(name);
178            nameOut(cp);
179        }
180
181        template<class CP>
182        ScopedCheckpointSection(CP &cp, const std::string &name) {
183            pushName(name.c_str());
184            nameOut(cp);
185        }
186
187        ~ScopedCheckpointSection();
188
189        ScopedCheckpointSection() = delete;
190        ScopedCheckpointSection(const ScopedCheckpointSection &) = delete;
191        ScopedCheckpointSection &operator=(
192            const ScopedCheckpointSection &) = delete;
193        ScopedCheckpointSection &operator=(
194            ScopedCheckpointSection &&) = delete;
195
196      private:
197        void pushName(const char *name);
198        void nameOut(CheckpointOut &cp);
199        void nameOut(CheckpointIn &cp) {};
200    };
201
202  public:
203    Serializable();
204    virtual ~Serializable();
205
206    /**
207     * Serialize an object
208     *
209     * Output an object's state into the current checkpoint section.
210     *
211     * @param cp Checkpoint state
212     */
213    virtual void serialize(CheckpointOut &cp) const = 0;
214
215    /**
216     * Unserialize an object
217     *
218     * Read an object's state from the current checkpoint section.
219     *
220     * @param cp Checkpoint state
221     */
222    virtual void unserialize(CheckpointIn &cp) = 0;
223
224    /**
225     * Serialize an object into a new section
226     *
227     * This method creates a new section in a checkpoint and calls
228     * serialize() to serialize the current object into that
229     * section. The name of the section is appended to the current
230     * checkpoint path.
231     *
232     * @param cp Checkpoint state
233     * @param name Name to append to the active path
234     */
235    void serializeSection(CheckpointOut &cp, const char *name) const;
236
237    void serializeSection(CheckpointOut &cp, const std::string &name) const {
238        serializeSection(cp, name.c_str());
239    }
240
241    /**
242     * Unserialize an a child object
243     *
244     * This method loads a child object from a checkpoint. The object
245     * name is appended to the active path to form a fully qualified
246     * section name and unserialize() is called.
247     *
248     * @param cp Checkpoint state
249     * @param name Name to append to the active path
250     */
251    void unserializeSection(CheckpointIn &cp, const char *name);
252
253    void unserializeSection(CheckpointIn &cp, const std::string &name) {
254        unserializeSection(cp, name.c_str());
255    }
256
257    /** Get the fully-qualified name of the active section */
258    static const std::string &currentSection();
259
260    static int ckptCount;
261    static int ckptMaxCount;
262    static int ckptPrevCount;
263    static void serializeAll(const std::string &cpt_dir);
264    static void unserializeGlobals(CheckpointIn &cp);
265
266  private:
267    static std::stack<std::string> path;
268};
269
270//
271// The base implementations use to_number for parsing and '<<' for
272// displaying, suitable for integer types.
273//
274template <class T>
275bool
276parseParam(const std::string &s, T &value)
277{
278    return to_number(s, value);
279}
280
281template <class T>
282void
283showParam(CheckpointOut &os, const T &value)
284{
285    os << value;
286}
287
288// Treat 8-bit ints (chars) as ints on output, not as chars
289template <>
290inline void
291showParam(CheckpointOut &os, const char &value)
292{
293    os << (int)value;
294}
295
296template <>
297inline void
298showParam(CheckpointOut &os, const signed char &value)
299{
300    os << (int)value;
301}
302
303template <>
304inline void
305showParam(CheckpointOut &os, const unsigned char &value)
306{
307    os << (unsigned int)value;
308}
309
310template <>
311inline bool
312parseParam(const std::string &s, float &value)
313{
314    return to_number(s, value);
315}
316
317template <>
318inline bool
319parseParam(const std::string &s, double &value)
320{
321    return to_number(s, value);
322}
323
324template <>
325inline bool
326parseParam(const std::string &s, bool &value)
327{
328    return to_bool(s, value);
329}
330
331// Display bools as strings
332template <>
333inline void
334showParam(CheckpointOut &os, const bool &value)
335{
336    os << (value ? "true" : "false");
337}
338
339// String requires no processing to speak of
340template <>
341inline bool
342parseParam(const std::string &s, std::string &value)
343{
344    value = s;
345    return true;
346}
347
348template <class T>
349void
350paramOut(CheckpointOut &os, const std::string &name, const T &param)
351{
352    os << name << "=";
353    showParam(os, param);
354    os << "\n";
355}
356
357template <typename T>
358void
359paramOut(CheckpointOut &cp, const std::string &name, const BitUnionType<T> &p)
360{
361    paramOut(cp, name, static_cast<BitUnionBaseType<T> >(p));
362}
363
364template <class T>
365void
366paramIn(CheckpointIn &cp, const std::string &name, T &param)
367{
368    const std::string &section(Serializable::currentSection());
369    std::string str;
370    if (!cp.find(section, name, str) || !parseParam(str, param)) {
371        fatal("Can't unserialize '%s:%s'\n", section, name);
372    }
373}
374
375template <typename T>
376void
377paramIn(CheckpointIn &cp, const std::string &name, BitUnionType<T> &p)
378{
379    BitUnionBaseType<T> b;
380    paramIn(cp, name, b);
381    p = b;
382}
383
384template <class T>
385bool
386optParamIn(CheckpointIn &cp, const std::string &name,
387           T &param, bool warn = true)
388{
389    const std::string &section(Serializable::currentSection());
390    std::string str;
391    if (!cp.find(section, name, str) || !parseParam(str, param)) {
392        if (warn)
393            warn("optional parameter %s:%s not present\n", section, name);
394        return false;
395    } else {
396        return true;
397    }
398}
399
400template <typename T>
401bool
402optParamIn(CheckpointIn &cp, const std::string &name,
403           BitUnionType<T> &p, bool warn = true)
404{
405    BitUnionBaseType<T> b;
406    if (optParamIn(cp, name, b, warn)) {
407        p = b;
408        return true;
409    } else {
410        return false;
411    }
412}
413
414template <class T>
415void
416arrayParamOut(CheckpointOut &os, const std::string &name,
417              const std::vector<T> &param)
418{
419    typename std::vector<T>::size_type size = param.size();
420    os << name << "=";
421    if (size > 0)
422        showParam(os, param[0]);
423    for (typename std::vector<T>::size_type i = 1; i < size; ++i) {
424        os << " ";
425        showParam(os, param[i]);
426    }
427    os << "\n";
428}
429
430template <class T>
431void
432arrayParamOut(CheckpointOut &os, const std::string &name,
433              const std::list<T> &param)
434{
435    typename std::list<T>::const_iterator it = param.begin();
436
437    os << name << "=";
438    if (param.size() > 0)
439        showParam(os, *it);
440    it++;
441    while (it != param.end()) {
442        os << " ";
443        showParam(os, *it);
444        it++;
445    }
446    os << "\n";
447}
448
449template <class T>
450void
451arrayParamOut(CheckpointOut &os, const std::string &name,
452              const std::set<T> &param)
453{
454    typename std::set<T>::const_iterator it = param.begin();
455
456    os << name << "=";
457    if (param.size() > 0)
458        showParam(os, *it);
459    it++;
460    while (it != param.end()) {
461        os << " ";
462        showParam(os, *it);
463        it++;
464    }
465    os << "\n";
466}
467
468template <class T>
469void
470arrayParamOut(CheckpointOut &os, const std::string &name,
471              const T *param, unsigned size)
472{
473    os << name << "=";
474    if (size > 0)
475        showParam(os, param[0]);
476    for (unsigned i = 1; i < size; ++i) {
477        os << " ";
478        showParam(os, param[i]);
479    }
480    os << "\n";
481}
482
483
484template <class T>
485void
486arrayParamIn(CheckpointIn &cp, const std::string &name,
487             T *param, unsigned size)
488{
489    const std::string &section(Serializable::currentSection());
490    std::string str;
491    if (!cp.find(section, name, str)) {
492        fatal("Can't unserialize '%s:%s'\n", section, name);
493    }
494
495    // code below stolen from VectorParam<T>::parse().
496    // it would be nice to unify these somehow...
497
498    std::vector<std::string> tokens;
499
500    tokenize(tokens, str, ' ');
501
502    // Need this if we were doing a vector
503    // value.resize(tokens.size());
504
505    if (tokens.size() != size) {
506        fatal("Array size mismatch on %s:%s'\n", section, name);
507    }
508
509    for (std::vector<std::string>::size_type i = 0; i < tokens.size(); i++) {
510        // need to parse into local variable to handle vector<bool>,
511        // for which operator[] returns a special reference class
512        // that's not the same as 'bool&', (since it's a packed
513        // vector)
514        T scalar_value;
515        if (!parseParam(tokens[i], scalar_value)) {
516            std::string err("could not parse \"");
517
518            err += str;
519            err += "\"";
520
521            fatal(err);
522        }
523
524        // assign parsed value to vector
525        param[i] = scalar_value;
526    }
527}
528
529template <class T>
530void
531arrayParamIn(CheckpointIn &cp, const std::string &name, std::vector<T> &param)
532{
533    const std::string &section(Serializable::currentSection());
534    std::string str;
535    if (!cp.find(section, name, str)) {
536        fatal("Can't unserialize '%s:%s'\n", section, name);
537    }
538
539    // code below stolen from VectorParam<T>::parse().
540    // it would be nice to unify these somehow...
541
542    std::vector<std::string> tokens;
543
544    tokenize(tokens, str, ' ');
545
546    // Need this if we were doing a vector
547    // value.resize(tokens.size());
548
549    param.resize(tokens.size());
550
551    for (std::vector<std::string>::size_type i = 0; i < tokens.size(); i++) {
552        // need to parse into local variable to handle vector<bool>,
553        // for which operator[] returns a special reference class
554        // that's not the same as 'bool&', (since it's a packed
555        // vector)
556        T scalar_value;
557        if (!parseParam(tokens[i], scalar_value)) {
558            std::string err("could not parse \"");
559
560            err += str;
561            err += "\"";
562
563            fatal(err);
564        }
565
566        // assign parsed value to vector
567        param[i] = scalar_value;
568    }
569}
570
571template <class T>
572void
573arrayParamIn(CheckpointIn &cp, const std::string &name, std::list<T> &param)
574{
575    const std::string &section(Serializable::currentSection());
576    std::string str;
577    if (!cp.find(section, name, str)) {
578        fatal("Can't unserialize '%s:%s'\n", section, name);
579    }
580    param.clear();
581
582    std::vector<std::string> tokens;
583    tokenize(tokens, str, ' ');
584
585    for (std::vector<std::string>::size_type i = 0; i < tokens.size(); i++) {
586        T scalar_value;
587        if (!parseParam(tokens[i], scalar_value)) {
588            std::string err("could not parse \"");
589
590            err += str;
591            err += "\"";
592
593            fatal(err);
594        }
595
596        // assign parsed value to vector
597        param.push_back(scalar_value);
598    }
599}
600
601template <class T>
602void
603arrayParamIn(CheckpointIn &cp, const std::string &name, std::set<T> &param)
604{
605    const std::string &section(Serializable::currentSection());
606    std::string str;
607    if (!cp.find(section, name, str)) {
608        fatal("Can't unserialize '%s:%s'\n", section, name);
609    }
610    param.clear();
611
612    std::vector<std::string> tokens;
613    tokenize(tokens, str, ' ');
614
615    for (std::vector<std::string>::size_type i = 0; i < tokens.size(); i++) {
616        T scalar_value;
617        if (!parseParam(tokens[i], scalar_value)) {
618            std::string err("could not parse \"");
619
620            err += str;
621            err += "\"";
622
623            fatal(err);
624        }
625
626        // assign parsed value to vector
627        param.insert(scalar_value);
628    }
629}
630
631template <class T>
632static void
633arrayParamOut(CheckpointOut &cp, const std::string &name,
634              const BitUnionType<T> *param, unsigned size)
635{
636    // We copy the array into a vector. This is needed since we cannot
637    // directly typecast a pointer to BitUnionType<T> into a pointer
638    // of BitUnionBaseType<T> but we can typecast BitUnionType<T>
639    // to BitUnionBaseType<T> since we overloaded the typecast operator
640    std::vector<BitUnionBaseType<T>> bitunion_vec(param, param + size);
641
642    arrayParamOut(cp, name, bitunion_vec);
643}
644
645template <class T>
646static void
647arrayParamIn(CheckpointIn &cp, const std::string &name,
648             BitUnionType<T> *param, unsigned size)
649{
650    std::vector<BitUnionBaseType<T>> bitunion_vec(size);
651
652    arrayParamIn(cp, name, bitunion_vec);
653    std::copy(bitunion_vec.begin(), bitunion_vec.end(), param);
654}
655
656void
657debug_serialize(const std::string &cpt_dir);
658
659void
660objParamIn(CheckpointIn &cp, const std::string &name, SimObject * &param);
661
662//
663// These macros are streamlined to use in serialize/unserialize
664// functions.  It's assumed that serialize() has a parameter 'os' for
665// the ostream, and unserialize() has parameters 'cp' and 'section'.
666#define SERIALIZE_SCALAR(scalar)        paramOut(cp, #scalar, scalar)
667
668#define UNSERIALIZE_SCALAR(scalar)      paramIn(cp, #scalar, scalar)
669#define UNSERIALIZE_OPT_SCALAR(scalar)      optParamIn(cp, #scalar, scalar)
670
671// ENUMs are like SCALARs, but we cast them to ints on the way out
672#define SERIALIZE_ENUM(scalar)          paramOut(cp, #scalar, (int)scalar)
673
674#define UNSERIALIZE_ENUM(scalar)                        \
675    do {                                                \
676        int tmp;                                        \
677        paramIn(cp, #scalar, tmp);                      \
678        scalar = static_cast<decltype(scalar)>(tmp);    \
679    } while (0)
680
681#define SERIALIZE_ARRAY(member, size)           \
682        arrayParamOut(cp, #member, member, size)
683
684#define UNSERIALIZE_ARRAY(member, size)         \
685        arrayParamIn(cp, #member, member, size)
686
687#define SERIALIZE_CONTAINER(member)             \
688        arrayParamOut(cp, #member, member)
689
690#define UNSERIALIZE_CONTAINER(member)           \
691        arrayParamIn(cp, #member, member)
692
693#define SERIALIZE_EVENT(event) event.serializeSection(cp, #event);
694
695#define UNSERIALIZE_EVENT(event)                        \
696    do {                                                \
697        event.unserializeSection(cp, #event);           \
698        eventQueue()->checkpointReschedule(&event);     \
699    } while (0)
700
701#define SERIALIZE_OBJ(obj) obj.serializeSection(cp, #obj)
702#define UNSERIALIZE_OBJ(obj) obj.unserializeSection(cp, #obj)
703
704#define SERIALIZE_OBJPTR(objptr)        paramOut(cp, #objptr, (objptr)->name())
705
706#define UNSERIALIZE_OBJPTR(objptr)                      \
707    do {                                                \
708        SimObject *sptr;                                \
709        objParamIn(cp, #objptr, sptr);                  \
710        objptr = dynamic_cast<decltype(objptr)>(sptr);  \
711    } while (0)
712
713#endif // __SERIALIZE_HH__
714