92b14a9ffff5d09d7ceafb428aab7d1451283cc6
[gem5.git] / src / sim / serialize.hh
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
41 /* @file
42 * Serialization Interface Declarations
43 */
44
45 #ifndef __SERIALIZE_HH__
46 #define __SERIALIZE_HH__
47
48
49 #include <algorithm>
50 #include <iostream>
51 #include <list>
52 #include <map>
53 #include <stack>
54 #include <set>
55 #include <vector>
56
57 #include "base/bitunion.hh"
58 #include "base/logging.hh"
59 #include "base/str.hh"
60
61 class IniFile;
62 class SimObject;
63 class SimObjectResolver;
64
65 typedef std::ostream CheckpointOut;
66
67 class CheckpointIn
68 {
69 private:
70
71 IniFile *db;
72
73 SimObjectResolver &objNameResolver;
74
75 public:
76 CheckpointIn(const std::string &cpt_dir, SimObjectResolver &resolver);
77 ~CheckpointIn();
78
79 const std::string cptDir;
80
81 bool find(const std::string &section, const std::string &entry,
82 std::string &value);
83
84 bool findObj(const std::string &section, const std::string &entry,
85 SimObject *&value);
86
87
88 bool entryExists(const std::string &section, const std::string &entry);
89 bool sectionExists(const std::string &section);
90
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
96 // someday
97
98 private:
99 // current directory we're serializing into.
100 static std::string currentDirectory;
101
102 public:
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);
107
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();
113
114 // Filename for base checkpoint file within directory.
115 static const char *baseFilename;
116 };
117
118 /**
119 * Basic support for object serialization.
120 *
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
124 * (non-SimObjects).
125 *
126 * SimObjects are serialized automatically into their own sections
127 * automatically by the SimObject base class (see
128 * SimObject::serializeAll().
129 *
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.
141 *
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.
147 */
148 class Serializable
149 {
150 protected:
151 /**
152 * Scoped checkpoint section helper class
153 *
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.
161 *
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.
167 */
168 class ScopedCheckpointSection {
169 public:
170 template<class CP>
171 ScopedCheckpointSection(CP &cp, const char *name) {
172 pushName(name);
173 nameOut(cp);
174 }
175
176 template<class CP>
177 ScopedCheckpointSection(CP &cp, const std::string &name) {
178 pushName(name.c_str());
179 nameOut(cp);
180 }
181
182 ~ScopedCheckpointSection();
183
184 ScopedCheckpointSection() = delete;
185 ScopedCheckpointSection(const ScopedCheckpointSection &) = delete;
186 ScopedCheckpointSection &operator=(
187 const ScopedCheckpointSection &) = delete;
188 ScopedCheckpointSection &operator=(
189 ScopedCheckpointSection &&) = delete;
190
191 private:
192 void pushName(const char *name);
193 void nameOut(CheckpointOut &cp);
194 void nameOut(CheckpointIn &cp) {};
195 };
196
197 public:
198 Serializable();
199 virtual ~Serializable();
200
201 /**
202 * Serialize an object
203 *
204 * Output an object's state into the current checkpoint section.
205 *
206 * @param cp Checkpoint state
207 */
208 virtual void serialize(CheckpointOut &cp) const = 0;
209
210 /**
211 * Unserialize an object
212 *
213 * Read an object's state from the current checkpoint section.
214 *
215 * @param cp Checkpoint state
216 */
217 virtual void unserialize(CheckpointIn &cp) = 0;
218
219 /**
220 * Serialize an object into a new section
221 *
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
225 * checkpoint path.
226 *
227 * @param cp Checkpoint state
228 * @param name Name to append to the active path
229 */
230 void serializeSection(CheckpointOut &cp, const char *name) const;
231
232 void serializeSection(CheckpointOut &cp, const std::string &name) const {
233 serializeSection(cp, name.c_str());
234 }
235
236 /**
237 * Unserialize an a child object
238 *
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.
242 *
243 * @param cp Checkpoint state
244 * @param name Name to append to the active path
245 */
246 void unserializeSection(CheckpointIn &cp, const char *name);
247
248 void unserializeSection(CheckpointIn &cp, const std::string &name) {
249 unserializeSection(cp, name.c_str());
250 }
251
252 /** Get the fully-qualified name of the active section */
253 static const std::string &currentSection();
254
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);
260
261 private:
262 static std::stack<std::string> path;
263 };
264
265 //
266 // The base implementations use to_number for parsing and '<<' for
267 // displaying, suitable for integer types.
268 //
269 template <class T>
270 bool
271 parseParam(const std::string &s, T &value)
272 {
273 return to_number(s, value);
274 }
275
276 template <class T>
277 void
278 showParam(CheckpointOut &os, const T &value)
279 {
280 os << value;
281 }
282
283 template <class T>
284 bool
285 parseParam(const std::string &s, BitUnionType<T> &value)
286 {
287 // Zero initialize storage to avoid leaking an uninitialized value
288 BitUnionBaseType<T> storage = BitUnionBaseType<T>();
289 auto res = to_number(s, storage);
290 value = storage;
291 return res;
292 }
293
294 template <class T>
295 void
296 showParam(CheckpointOut &os, const BitUnionType<T> &value)
297 {
298 auto storage = static_cast<BitUnionBaseType<T>>(value);
299
300 // For a BitUnion8, the storage type is an unsigned char.
301 // Since we want to serialize a number we need to cast to
302 // unsigned int
303 os << ((sizeof(storage) == 1) ?
304 static_cast<unsigned int>(storage) : storage);
305 }
306
307 // Treat 8-bit ints (chars) as ints on output, not as chars
308 template <>
309 inline void
310 showParam(CheckpointOut &os, const char &value)
311 {
312 os << (int)value;
313 }
314
315 template <>
316 inline void
317 showParam(CheckpointOut &os, const signed char &value)
318 {
319 os << (int)value;
320 }
321
322 template <>
323 inline void
324 showParam(CheckpointOut &os, const unsigned char &value)
325 {
326 os << (unsigned int)value;
327 }
328
329 template <>
330 inline bool
331 parseParam(const std::string &s, float &value)
332 {
333 return to_number(s, value);
334 }
335
336 template <>
337 inline bool
338 parseParam(const std::string &s, double &value)
339 {
340 return to_number(s, value);
341 }
342
343 template <>
344 inline bool
345 parseParam(const std::string &s, bool &value)
346 {
347 return to_bool(s, value);
348 }
349
350 // Display bools as strings
351 template <>
352 inline void
353 showParam(CheckpointOut &os, const bool &value)
354 {
355 os << (value ? "true" : "false");
356 }
357
358 // String requires no processing to speak of
359 template <>
360 inline bool
361 parseParam(const std::string &s, std::string &value)
362 {
363 value = s;
364 return true;
365 }
366
367 template <class T>
368 void
369 paramOut(CheckpointOut &os, const std::string &name, const T &param)
370 {
371 os << name << "=";
372 showParam(os, param);
373 os << "\n";
374 }
375
376 template <class T>
377 void
378 paramIn(CheckpointIn &cp, const std::string &name, T &param)
379 {
380 const std::string &section(Serializable::currentSection());
381 std::string str;
382 if (!cp.find(section, name, str) || !parseParam(str, param)) {
383 fatal("Can't unserialize '%s:%s'\n", section, name);
384 }
385 }
386
387 template <class T>
388 bool
389 optParamIn(CheckpointIn &cp, const std::string &name,
390 T &param, bool warn = true)
391 {
392 const std::string &section(Serializable::currentSection());
393 std::string str;
394 if (!cp.find(section, name, str) || !parseParam(str, param)) {
395 if (warn)
396 warn("optional parameter %s:%s not present\n", section, name);
397 return false;
398 } else {
399 return true;
400 }
401 }
402
403 template <class T>
404 void
405 arrayParamOut(CheckpointOut &os, const std::string &name,
406 const std::vector<T> &param)
407 {
408 typename std::vector<T>::size_type size = param.size();
409 os << name << "=";
410 if (size > 0)
411 showParam(os, param[0]);
412 for (typename std::vector<T>::size_type i = 1; i < size; ++i) {
413 os << " ";
414 showParam(os, param[i]);
415 }
416 os << "\n";
417 }
418
419 template <class T>
420 void
421 arrayParamOut(CheckpointOut &os, const std::string &name,
422 const std::list<T> &param)
423 {
424 typename std::list<T>::const_iterator it = param.begin();
425
426 os << name << "=";
427 if (param.size() > 0)
428 showParam(os, *it);
429 it++;
430 while (it != param.end()) {
431 os << " ";
432 showParam(os, *it);
433 it++;
434 }
435 os << "\n";
436 }
437
438 template <class T>
439 void
440 arrayParamOut(CheckpointOut &os, const std::string &name,
441 const std::set<T> &param)
442 {
443 typename std::set<T>::const_iterator it = param.begin();
444
445 os << name << "=";
446 if (param.size() > 0)
447 showParam(os, *it);
448 it++;
449 while (it != param.end()) {
450 os << " ";
451 showParam(os, *it);
452 it++;
453 }
454 os << "\n";
455 }
456
457 template <class T>
458 void
459 arrayParamOut(CheckpointOut &os, const std::string &name,
460 const T *param, unsigned size)
461 {
462 os << name << "=";
463 if (size > 0)
464 showParam(os, param[0]);
465 for (unsigned i = 1; i < size; ++i) {
466 os << " ";
467 showParam(os, param[i]);
468 }
469 os << "\n";
470 }
471
472 /**
473 * Extract values stored in the checkpoint, and assign them to the provided
474 * array container.
475 *
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.
480 */
481 template <class T>
482 void
483 arrayParamIn(CheckpointIn &cp, const std::string &name,
484 T *param, unsigned size)
485 {
486 const std::string &section(Serializable::currentSection());
487 std::string str;
488 if (!cp.find(section, name, str)) {
489 fatal("Can't unserialize '%s:%s'\n", section, name);
490 }
491
492 // code below stolen from VectorParam<T>::parse().
493 // it would be nice to unify these somehow...
494
495 std::vector<std::string> tokens;
496
497 tokenize(tokens, str, ' ');
498
499 // Need this if we were doing a vector
500 // value.resize(tokens.size());
501
502 fatal_if(tokens.size() != size,
503 "Array size mismatch on %s:%s (Got %u, expected %u)'\n",
504 section, name, tokens.size(), size);
505
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
510 // vector)
511 T scalar_value;
512 if (!parseParam(tokens[i], scalar_value)) {
513 std::string err("could not parse \"");
514
515 err += str;
516 err += "\"";
517
518 fatal(err);
519 }
520
521 // assign parsed value to vector
522 param[i] = scalar_value;
523 }
524 }
525
526 template <class T>
527 void
528 arrayParamIn(CheckpointIn &cp, const std::string &name, std::vector<T> &param)
529 {
530 const std::string &section(Serializable::currentSection());
531 std::string str;
532 if (!cp.find(section, name, str)) {
533 fatal("Can't unserialize '%s:%s'\n", section, name);
534 }
535
536 // code below stolen from VectorParam<T>::parse().
537 // it would be nice to unify these somehow...
538
539 std::vector<std::string> tokens;
540
541 tokenize(tokens, str, ' ');
542
543 // Need this if we were doing a vector
544 // value.resize(tokens.size());
545
546 param.resize(tokens.size());
547
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
552 // vector)
553 T scalar_value;
554 if (!parseParam(tokens[i], scalar_value)) {
555 std::string err("could not parse \"");
556
557 err += str;
558 err += "\"";
559
560 fatal(err);
561 }
562
563 // assign parsed value to vector
564 param[i] = scalar_value;
565 }
566 }
567
568 template <class T>
569 void
570 arrayParamIn(CheckpointIn &cp, const std::string &name, std::list<T> &param)
571 {
572 const std::string &section(Serializable::currentSection());
573 std::string str;
574 if (!cp.find(section, name, str)) {
575 fatal("Can't unserialize '%s:%s'\n", section, name);
576 }
577 param.clear();
578
579 std::vector<std::string> tokens;
580 tokenize(tokens, str, ' ');
581
582 for (std::vector<std::string>::size_type i = 0; i < tokens.size(); i++) {
583 T scalar_value;
584 if (!parseParam(tokens[i], scalar_value)) {
585 std::string err("could not parse \"");
586
587 err += str;
588 err += "\"";
589
590 fatal(err);
591 }
592
593 // assign parsed value to vector
594 param.push_back(scalar_value);
595 }
596 }
597
598 template <class T>
599 void
600 arrayParamIn(CheckpointIn &cp, const std::string &name, std::set<T> &param)
601 {
602 const std::string &section(Serializable::currentSection());
603 std::string str;
604 if (!cp.find(section, name, str)) {
605 fatal("Can't unserialize '%s:%s'\n", section, name);
606 }
607 param.clear();
608
609 std::vector<std::string> tokens;
610 tokenize(tokens, str, ' ');
611
612 for (std::vector<std::string>::size_type i = 0; i < tokens.size(); i++) {
613 T scalar_value;
614 if (!parseParam(tokens[i], scalar_value)) {
615 std::string err("could not parse \"");
616
617 err += str;
618 err += "\"";
619
620 fatal(err);
621 }
622
623 // assign parsed value to vector
624 param.insert(scalar_value);
625 }
626 }
627
628 void
629 debug_serialize(const std::string &cpt_dir);
630
631 void
632 objParamIn(CheckpointIn &cp, const std::string &name, SimObject * &param);
633
634 //
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)
639
640 #define UNSERIALIZE_SCALAR(scalar) paramIn(cp, #scalar, scalar)
641 #define UNSERIALIZE_OPT_SCALAR(scalar) optParamIn(cp, #scalar, scalar)
642
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)
645
646 #define UNSERIALIZE_ENUM(scalar) \
647 do { \
648 int tmp; \
649 paramIn(cp, #scalar, tmp); \
650 scalar = static_cast<decltype(scalar)>(tmp); \
651 } while (0)
652
653 #define SERIALIZE_ARRAY(member, size) \
654 arrayParamOut(cp, #member, member, size)
655
656 #define UNSERIALIZE_ARRAY(member, size) \
657 arrayParamIn(cp, #member, member, size)
658
659 #define SERIALIZE_CONTAINER(member) \
660 arrayParamOut(cp, #member, member)
661
662 #define UNSERIALIZE_CONTAINER(member) \
663 arrayParamIn(cp, #member, member)
664
665 #define SERIALIZE_EVENT(event) event.serializeSection(cp, #event);
666
667 #define UNSERIALIZE_EVENT(event) \
668 do { \
669 event.unserializeSection(cp, #event); \
670 eventQueue()->checkpointReschedule(&event); \
671 } while (0)
672
673 #define SERIALIZE_OBJ(obj) obj.serializeSection(cp, #obj)
674 #define UNSERIALIZE_OBJ(obj) obj.unserializeSection(cp, #obj)
675
676 #define SERIALIZE_OBJPTR(objptr) paramOut(cp, #objptr, (objptr)->name())
677
678 #define UNSERIALIZE_OBJPTR(objptr) \
679 do { \
680 SimObject *sptr; \
681 objParamIn(cp, #objptr, sptr); \
682 objptr = dynamic_cast<decltype(objptr)>(sptr); \
683 } while (0)
684
685 #endif // __SERIALIZE_HH__