2 * Copyright (c) 2015, 2018 ARM Limited
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.
14 * Copyright (c) 2002-2005 The Regents of The University of Michigan
15 * All rights reserved.
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.
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.
42 * Serialization Interface Declarations
45 #ifndef __SERIALIZE_HH__
46 #define __SERIALIZE_HH__
57 #include "base/bitunion.hh"
58 #include "base/logging.hh"
59 #include "base/str.hh"
63 class SimObjectResolver;
65 typedef std::ostream CheckpointOut;
73 SimObjectResolver &objNameResolver;
76 CheckpointIn(const std::string &cpt_dir, SimObjectResolver &resolver);
79 const std::string cptDir;
81 bool find(const std::string §ion, const std::string &entry,
84 bool findObj(const std::string §ion, const std::string &entry,
88 bool entryExists(const std::string §ion, const std::string &entry);
89 bool sectionExists(const std::string §ion);
91 // The following static functions have to do with checkpoint
92 // creation rather than restoration. This class makes a handy
93 // namespace for them though. Currently no Checkpoint object is
94 // created on serialization (only unserialization) so we track the
95 // directory name as a global. It would be nice to change this
99 // current directory we're serializing into.
100 static std::string currentDirectory;
103 // Set the current directory. This function takes care of
104 // inserting curTick() if there's a '%d' in the argument, and
105 // appends a '/' if necessary. The final name is returned.
106 static std::string setDir(const std::string &base_name);
108 // Export current checkpoint directory name so other objects can
109 // derive filenames from it (e.g., memory). The return value is
110 // guaranteed to end in '/' so filenames can be directly appended.
111 // This function is only valid while a checkpoint is being created.
112 static std::string dir();
114 // Filename for base checkpoint file within directory.
115 static const char *baseFilename;
119 * Basic support for object serialization.
121 * Objects that support serialization should derive from this
122 * class. Such objects can largely be divided into two categories: 1)
123 * True SimObjects (deriving from SimObject), and 2) child objects
126 * SimObjects are serialized automatically into their own sections
127 * automatically by the SimObject base class (see
128 * SimObject::serializeAll().
130 * SimObjects can contain other serializable objects that are not
131 * SimObjects. Much like normal serialized members are not serialized
132 * automatically, these objects will not be serialized automatically
133 * and it is expected that the objects owning such serializable
134 * objects call the required serialization/unserialization methods on
135 * child objects. The preferred method to serialize a child object is
136 * to call serializeSection() on the child, which serializes the
137 * object into a new subsection in the current section. Another option
138 * is to call serialize() directly, which serializes the object into
139 * the current section. The latter is not recommended as it can lead
140 * to naming clashes between objects.
142 * @note Many objects that support serialization need to be put in a
143 * consistent state when serialization takes place. We refer to the
144 * action of forcing an object into a consistent state as
145 * 'draining'. Objects that need draining inherit from Drainable. See
146 * Drainable for more information.
152 * Scoped checkpoint section helper class
154 * This helper class creates a section within a checkpoint without
155 * the need for a separate serializeable object. It is mainly used
156 * within the Serializable class when serializing or unserializing
157 * section (see serializeSection() and unserializeSection()). It
158 * can also be used to maintain backwards compatibility in
159 * existing code that serializes structs that are not inheriting
160 * from Serializable into subsections.
162 * When the class is instantiated, it appends a name to the active
163 * path in a checkpoint. The old path is later restored when the
164 * instance is destroyed. For example, serializeSection() could be
165 * implemented by instantiating a ScopedCheckpointSection and then
166 * calling serialize() on an object.
168 class ScopedCheckpointSection {
171 ScopedCheckpointSection(CP &cp, const char *name) {
177 ScopedCheckpointSection(CP &cp, const std::string &name) {
178 pushName(name.c_str());
182 ~ScopedCheckpointSection();
184 ScopedCheckpointSection() = delete;
185 ScopedCheckpointSection(const ScopedCheckpointSection &) = delete;
186 ScopedCheckpointSection &operator=(
187 const ScopedCheckpointSection &) = delete;
188 ScopedCheckpointSection &operator=(
189 ScopedCheckpointSection &&) = delete;
192 void pushName(const char *name);
193 void nameOut(CheckpointOut &cp);
194 void nameOut(CheckpointIn &cp) {};
199 virtual ~Serializable();
202 * Serialize an object
204 * Output an object's state into the current checkpoint section.
206 * @param cp Checkpoint state
208 virtual void serialize(CheckpointOut &cp) const = 0;
211 * Unserialize an object
213 * Read an object's state from the current checkpoint section.
215 * @param cp Checkpoint state
217 virtual void unserialize(CheckpointIn &cp) = 0;
220 * Serialize an object into a new section
222 * This method creates a new section in a checkpoint and calls
223 * serialize() to serialize the current object into that
224 * section. The name of the section is appended to the current
227 * @param cp Checkpoint state
228 * @param name Name to append to the active path
230 void serializeSection(CheckpointOut &cp, const char *name) const;
232 void serializeSection(CheckpointOut &cp, const std::string &name) const {
233 serializeSection(cp, name.c_str());
237 * Unserialize an a child object
239 * This method loads a child object from a checkpoint. The object
240 * name is appended to the active path to form a fully qualified
241 * section name and unserialize() is called.
243 * @param cp Checkpoint state
244 * @param name Name to append to the active path
246 void unserializeSection(CheckpointIn &cp, const char *name);
248 void unserializeSection(CheckpointIn &cp, const std::string &name) {
249 unserializeSection(cp, name.c_str());
252 /** Get the fully-qualified name of the active section */
253 static const std::string ¤tSection();
255 static int ckptCount;
256 static int ckptMaxCount;
257 static int ckptPrevCount;
258 static void serializeAll(const std::string &cpt_dir);
259 static void unserializeGlobals(CheckpointIn &cp);
262 static std::stack<std::string> path;
266 // The base implementations use to_number for parsing and '<<' for
267 // displaying, suitable for integer types.
271 parseParam(const std::string &s, T &value)
273 return to_number(s, value);
278 showParam(CheckpointOut &os, const T &value)
285 parseParam(const std::string &s, BitUnionType<T> &value)
287 // Zero initialize storage to avoid leaking an uninitialized value
288 BitUnionBaseType<T> storage = BitUnionBaseType<T>();
289 auto res = to_number(s, storage);
296 showParam(CheckpointOut &os, const BitUnionType<T> &value)
298 auto storage = static_cast<BitUnionBaseType<T>>(value);
300 // For a BitUnion8, the storage type is an unsigned char.
301 // Since we want to serialize a number we need to cast to
303 os << ((sizeof(storage) == 1) ?
304 static_cast<unsigned int>(storage) : storage);
307 // Treat 8-bit ints (chars) as ints on output, not as chars
310 showParam(CheckpointOut &os, const char &value)
317 showParam(CheckpointOut &os, const signed char &value)
324 showParam(CheckpointOut &os, const unsigned char &value)
326 os << (unsigned int)value;
331 parseParam(const std::string &s, float &value)
333 return to_number(s, value);
338 parseParam(const std::string &s, double &value)
340 return to_number(s, value);
345 parseParam(const std::string &s, bool &value)
347 return to_bool(s, value);
350 // Display bools as strings
353 showParam(CheckpointOut &os, const bool &value)
355 os << (value ? "true" : "false");
358 // String requires no processing to speak of
361 parseParam(const std::string &s, std::string &value)
369 paramOut(CheckpointOut &os, const std::string &name, const T ¶m)
372 showParam(os, param);
378 paramIn(CheckpointIn &cp, const std::string &name, T ¶m)
380 const std::string §ion(Serializable::currentSection());
382 if (!cp.find(section, name, str) || !parseParam(str, param)) {
383 fatal("Can't unserialize '%s:%s'\n", section, name);
389 optParamIn(CheckpointIn &cp, const std::string &name,
390 T ¶m, bool warn = true)
392 const std::string §ion(Serializable::currentSection());
394 if (!cp.find(section, name, str) || !parseParam(str, param)) {
396 warn("optional parameter %s:%s not present\n", section, name);
405 arrayParamOut(CheckpointOut &os, const std::string &name,
406 const std::vector<T> ¶m)
408 typename std::vector<T>::size_type size = param.size();
411 showParam(os, param[0]);
412 for (typename std::vector<T>::size_type i = 1; i < size; ++i) {
414 showParam(os, param[i]);
421 arrayParamOut(CheckpointOut &os, const std::string &name,
422 const std::list<T> ¶m)
424 typename std::list<T>::const_iterator it = param.begin();
427 if (param.size() > 0)
430 while (it != param.end()) {
440 arrayParamOut(CheckpointOut &os, const std::string &name,
441 const std::set<T> ¶m)
443 typename std::set<T>::const_iterator it = param.begin();
446 if (param.size() > 0)
449 while (it != param.end()) {
459 arrayParamOut(CheckpointOut &os, const std::string &name,
460 const T *param, unsigned size)
464 showParam(os, param[0]);
465 for (unsigned i = 1; i < size; ++i) {
467 showParam(os, param[i]);
473 * Extract values stored in the checkpoint, and assign them to the provided
476 * @param cp The checkpoint to be parsed.
477 * @param name Name of the container.
478 * @param param The array container.
479 * @param size The expected number of entries to be extracted.
483 arrayParamIn(CheckpointIn &cp, const std::string &name,
484 T *param, unsigned size)
486 const std::string §ion(Serializable::currentSection());
488 if (!cp.find(section, name, str)) {
489 fatal("Can't unserialize '%s:%s'\n", section, name);
492 // code below stolen from VectorParam<T>::parse().
493 // it would be nice to unify these somehow...
495 std::vector<std::string> tokens;
497 tokenize(tokens, str, ' ');
499 // Need this if we were doing a vector
500 // value.resize(tokens.size());
502 fatal_if(tokens.size() != size,
503 "Array size mismatch on %s:%s (Got %u, expected %u)'\n",
504 section, name, tokens.size(), size);
506 for (std::vector<std::string>::size_type i = 0; i < tokens.size(); i++) {
507 // need to parse into local variable to handle vector<bool>,
508 // for which operator[] returns a special reference class
509 // that's not the same as 'bool&', (since it's a packed
512 if (!parseParam(tokens[i], scalar_value)) {
513 std::string err("could not parse \"");
521 // assign parsed value to vector
522 param[i] = scalar_value;
528 arrayParamIn(CheckpointIn &cp, const std::string &name, std::vector<T> ¶m)
530 const std::string §ion(Serializable::currentSection());
532 if (!cp.find(section, name, str)) {
533 fatal("Can't unserialize '%s:%s'\n", section, name);
536 // code below stolen from VectorParam<T>::parse().
537 // it would be nice to unify these somehow...
539 std::vector<std::string> tokens;
541 tokenize(tokens, str, ' ');
543 // Need this if we were doing a vector
544 // value.resize(tokens.size());
546 param.resize(tokens.size());
548 for (std::vector<std::string>::size_type i = 0; i < tokens.size(); i++) {
549 // need to parse into local variable to handle vector<bool>,
550 // for which operator[] returns a special reference class
551 // that's not the same as 'bool&', (since it's a packed
554 if (!parseParam(tokens[i], scalar_value)) {
555 std::string err("could not parse \"");
563 // assign parsed value to vector
564 param[i] = scalar_value;
570 arrayParamIn(CheckpointIn &cp, const std::string &name, std::list<T> ¶m)
572 const std::string §ion(Serializable::currentSection());
574 if (!cp.find(section, name, str)) {
575 fatal("Can't unserialize '%s:%s'\n", section, name);
579 std::vector<std::string> tokens;
580 tokenize(tokens, str, ' ');
582 for (std::vector<std::string>::size_type i = 0; i < tokens.size(); i++) {
584 if (!parseParam(tokens[i], scalar_value)) {
585 std::string err("could not parse \"");
593 // assign parsed value to vector
594 param.push_back(scalar_value);
600 arrayParamIn(CheckpointIn &cp, const std::string &name, std::set<T> ¶m)
602 const std::string §ion(Serializable::currentSection());
604 if (!cp.find(section, name, str)) {
605 fatal("Can't unserialize '%s:%s'\n", section, name);
609 std::vector<std::string> tokens;
610 tokenize(tokens, str, ' ');
612 for (std::vector<std::string>::size_type i = 0; i < tokens.size(); i++) {
614 if (!parseParam(tokens[i], scalar_value)) {
615 std::string err("could not parse \"");
623 // assign parsed value to vector
624 param.insert(scalar_value);
629 debug_serialize(const std::string &cpt_dir);
632 objParamIn(CheckpointIn &cp, const std::string &name, SimObject * ¶m);
635 // These macros are streamlined to use in serialize/unserialize
636 // functions. It's assumed that serialize() has a parameter 'os' for
637 // the ostream, and unserialize() has parameters 'cp' and 'section'.
638 #define SERIALIZE_SCALAR(scalar) paramOut(cp, #scalar, scalar)
640 #define UNSERIALIZE_SCALAR(scalar) paramIn(cp, #scalar, scalar)
641 #define UNSERIALIZE_OPT_SCALAR(scalar) optParamIn(cp, #scalar, scalar)
643 // ENUMs are like SCALARs, but we cast them to ints on the way out
644 #define SERIALIZE_ENUM(scalar) paramOut(cp, #scalar, (int)scalar)
646 #define UNSERIALIZE_ENUM(scalar) \
649 paramIn(cp, #scalar, tmp); \
650 scalar = static_cast<decltype(scalar)>(tmp); \
653 #define SERIALIZE_ARRAY(member, size) \
654 arrayParamOut(cp, #member, member, size)
656 #define UNSERIALIZE_ARRAY(member, size) \
657 arrayParamIn(cp, #member, member, size)
659 #define SERIALIZE_CONTAINER(member) \
660 arrayParamOut(cp, #member, member)
662 #define UNSERIALIZE_CONTAINER(member) \
663 arrayParamIn(cp, #member, member)
665 #define SERIALIZE_EVENT(event) event.serializeSection(cp, #event);
667 #define UNSERIALIZE_EVENT(event) \
669 event.unserializeSection(cp, #event); \
670 eventQueue()->checkpointReschedule(&event); \
673 #define SERIALIZE_OBJ(obj) obj.serializeSection(cp, #obj)
674 #define UNSERIALIZE_OBJ(obj) obj.unserializeSection(cp, #obj)
676 #define SERIALIZE_OBJPTR(objptr) paramOut(cp, #objptr, (objptr)->name())
678 #define UNSERIALIZE_OBJPTR(objptr) \
681 objParamIn(cp, #objptr, sptr); \
682 objptr = dynamic_cast<decltype(objptr)>(sptr); \
685 #endif // __SERIALIZE_HH__