serialize.hh revision 13415
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 §ion, const std::string &entry, 87 std::string &value); 88 89 bool findObj(const std::string §ion, const std::string &entry, 90 SimObject *&value); 91 92 93 bool entryExists(const std::string §ion, const std::string &entry); 94 bool sectionExists(const std::string §ion); 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 ¤tSection(); 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 288template <class T> 289bool 290parseParam(const std::string &s, BitUnionType<T> &value) 291{ 292 auto storage = static_cast<BitUnionBaseType<T>>(value); 293 auto res = to_number(s, storage); 294 value = storage; 295 return res; 296} 297 298template <class T> 299void 300showParam(CheckpointOut &os, const BitUnionType<T> &value) 301{ 302 auto storage = static_cast<BitUnionBaseType<T>>(value); 303 304 // For a BitUnion8, the storage type is an unsigned char. 305 // Since we want to serialize a number we need to cast to 306 // unsigned int 307 os << ((sizeof(storage) == 1) ? 308 static_cast<unsigned int>(storage) : storage); 309} 310 311// Treat 8-bit ints (chars) as ints on output, not as chars 312template <> 313inline void 314showParam(CheckpointOut &os, const char &value) 315{ 316 os << (int)value; 317} 318 319template <> 320inline void 321showParam(CheckpointOut &os, const signed char &value) 322{ 323 os << (int)value; 324} 325 326template <> 327inline void 328showParam(CheckpointOut &os, const unsigned char &value) 329{ 330 os << (unsigned int)value; 331} 332 333template <> 334inline bool 335parseParam(const std::string &s, float &value) 336{ 337 return to_number(s, value); 338} 339 340template <> 341inline bool 342parseParam(const std::string &s, double &value) 343{ 344 return to_number(s, value); 345} 346 347template <> 348inline bool 349parseParam(const std::string &s, bool &value) 350{ 351 return to_bool(s, value); 352} 353 354// Display bools as strings 355template <> 356inline void 357showParam(CheckpointOut &os, const bool &value) 358{ 359 os << (value ? "true" : "false"); 360} 361 362// String requires no processing to speak of 363template <> 364inline bool 365parseParam(const std::string &s, std::string &value) 366{ 367 value = s; 368 return true; 369} 370 371template <class T> 372void 373paramOut(CheckpointOut &os, const std::string &name, const T ¶m) 374{ 375 os << name << "="; 376 showParam(os, param); 377 os << "\n"; 378} 379 380template <class T> 381void 382paramIn(CheckpointIn &cp, const std::string &name, T ¶m) 383{ 384 const std::string §ion(Serializable::currentSection()); 385 std::string str; 386 if (!cp.find(section, name, str) || !parseParam(str, param)) { 387 fatal("Can't unserialize '%s:%s'\n", section, name); 388 } 389} 390 391template <class T> 392bool 393optParamIn(CheckpointIn &cp, const std::string &name, 394 T ¶m, bool warn = true) 395{ 396 const std::string §ion(Serializable::currentSection()); 397 std::string str; 398 if (!cp.find(section, name, str) || !parseParam(str, param)) { 399 if (warn) 400 warn("optional parameter %s:%s not present\n", section, name); 401 return false; 402 } else { 403 return true; 404 } 405} 406 407template <class T> 408void 409arrayParamOut(CheckpointOut &os, const std::string &name, 410 const std::vector<T> ¶m) 411{ 412 typename std::vector<T>::size_type size = param.size(); 413 os << name << "="; 414 if (size > 0) 415 showParam(os, param[0]); 416 for (typename std::vector<T>::size_type i = 1; i < size; ++i) { 417 os << " "; 418 showParam(os, param[i]); 419 } 420 os << "\n"; 421} 422 423template <class T> 424void 425arrayParamOut(CheckpointOut &os, const std::string &name, 426 const std::list<T> ¶m) 427{ 428 typename std::list<T>::const_iterator it = param.begin(); 429 430 os << name << "="; 431 if (param.size() > 0) 432 showParam(os, *it); 433 it++; 434 while (it != param.end()) { 435 os << " "; 436 showParam(os, *it); 437 it++; 438 } 439 os << "\n"; 440} 441 442template <class T> 443void 444arrayParamOut(CheckpointOut &os, const std::string &name, 445 const std::set<T> ¶m) 446{ 447 typename std::set<T>::const_iterator it = param.begin(); 448 449 os << name << "="; 450 if (param.size() > 0) 451 showParam(os, *it); 452 it++; 453 while (it != param.end()) { 454 os << " "; 455 showParam(os, *it); 456 it++; 457 } 458 os << "\n"; 459} 460 461template <class T> 462void 463arrayParamOut(CheckpointOut &os, const std::string &name, 464 const T *param, unsigned size) 465{ 466 os << name << "="; 467 if (size > 0) 468 showParam(os, param[0]); 469 for (unsigned i = 1; i < size; ++i) { 470 os << " "; 471 showParam(os, param[i]); 472 } 473 os << "\n"; 474} 475 476 477template <class T> 478void 479arrayParamIn(CheckpointIn &cp, const std::string &name, 480 T *param, unsigned size) 481{ 482 const std::string §ion(Serializable::currentSection()); 483 std::string str; 484 if (!cp.find(section, name, str)) { 485 fatal("Can't unserialize '%s:%s'\n", section, name); 486 } 487 488 // code below stolen from VectorParam<T>::parse(). 489 // it would be nice to unify these somehow... 490 491 std::vector<std::string> tokens; 492 493 tokenize(tokens, str, ' '); 494 495 // Need this if we were doing a vector 496 // value.resize(tokens.size()); 497 498 if (tokens.size() != size) { 499 fatal("Array size mismatch on %s:%s'\n", section, name); 500 } 501 502 for (std::vector<std::string>::size_type i = 0; i < tokens.size(); i++) { 503 // need to parse into local variable to handle vector<bool>, 504 // for which operator[] returns a special reference class 505 // that's not the same as 'bool&', (since it's a packed 506 // vector) 507 T scalar_value; 508 if (!parseParam(tokens[i], scalar_value)) { 509 std::string err("could not parse \""); 510 511 err += str; 512 err += "\""; 513 514 fatal(err); 515 } 516 517 // assign parsed value to vector 518 param[i] = scalar_value; 519 } 520} 521 522template <class T> 523void 524arrayParamIn(CheckpointIn &cp, const std::string &name, std::vector<T> ¶m) 525{ 526 const std::string §ion(Serializable::currentSection()); 527 std::string str; 528 if (!cp.find(section, name, str)) { 529 fatal("Can't unserialize '%s:%s'\n", section, name); 530 } 531 532 // code below stolen from VectorParam<T>::parse(). 533 // it would be nice to unify these somehow... 534 535 std::vector<std::string> tokens; 536 537 tokenize(tokens, str, ' '); 538 539 // Need this if we were doing a vector 540 // value.resize(tokens.size()); 541 542 param.resize(tokens.size()); 543 544 for (std::vector<std::string>::size_type i = 0; i < tokens.size(); i++) { 545 // need to parse into local variable to handle vector<bool>, 546 // for which operator[] returns a special reference class 547 // that's not the same as 'bool&', (since it's a packed 548 // vector) 549 T scalar_value; 550 if (!parseParam(tokens[i], scalar_value)) { 551 std::string err("could not parse \""); 552 553 err += str; 554 err += "\""; 555 556 fatal(err); 557 } 558 559 // assign parsed value to vector 560 param[i] = scalar_value; 561 } 562} 563 564template <class T> 565void 566arrayParamIn(CheckpointIn &cp, const std::string &name, std::list<T> ¶m) 567{ 568 const std::string §ion(Serializable::currentSection()); 569 std::string str; 570 if (!cp.find(section, name, str)) { 571 fatal("Can't unserialize '%s:%s'\n", section, name); 572 } 573 param.clear(); 574 575 std::vector<std::string> tokens; 576 tokenize(tokens, str, ' '); 577 578 for (std::vector<std::string>::size_type i = 0; i < tokens.size(); i++) { 579 T scalar_value; 580 if (!parseParam(tokens[i], scalar_value)) { 581 std::string err("could not parse \""); 582 583 err += str; 584 err += "\""; 585 586 fatal(err); 587 } 588 589 // assign parsed value to vector 590 param.push_back(scalar_value); 591 } 592} 593 594template <class T> 595void 596arrayParamIn(CheckpointIn &cp, const std::string &name, std::set<T> ¶m) 597{ 598 const std::string §ion(Serializable::currentSection()); 599 std::string str; 600 if (!cp.find(section, name, str)) { 601 fatal("Can't unserialize '%s:%s'\n", section, name); 602 } 603 param.clear(); 604 605 std::vector<std::string> tokens; 606 tokenize(tokens, str, ' '); 607 608 for (std::vector<std::string>::size_type i = 0; i < tokens.size(); i++) { 609 T scalar_value; 610 if (!parseParam(tokens[i], scalar_value)) { 611 std::string err("could not parse \""); 612 613 err += str; 614 err += "\""; 615 616 fatal(err); 617 } 618 619 // assign parsed value to vector 620 param.insert(scalar_value); 621 } 622} 623 624void 625debug_serialize(const std::string &cpt_dir); 626 627void 628objParamIn(CheckpointIn &cp, const std::string &name, SimObject * ¶m); 629 630// 631// These macros are streamlined to use in serialize/unserialize 632// functions. It's assumed that serialize() has a parameter 'os' for 633// the ostream, and unserialize() has parameters 'cp' and 'section'. 634#define SERIALIZE_SCALAR(scalar) paramOut(cp, #scalar, scalar) 635 636#define UNSERIALIZE_SCALAR(scalar) paramIn(cp, #scalar, scalar) 637#define UNSERIALIZE_OPT_SCALAR(scalar) optParamIn(cp, #scalar, scalar) 638 639// ENUMs are like SCALARs, but we cast them to ints on the way out 640#define SERIALIZE_ENUM(scalar) paramOut(cp, #scalar, (int)scalar) 641 642#define UNSERIALIZE_ENUM(scalar) \ 643 do { \ 644 int tmp; \ 645 paramIn(cp, #scalar, tmp); \ 646 scalar = static_cast<decltype(scalar)>(tmp); \ 647 } while (0) 648 649#define SERIALIZE_ARRAY(member, size) \ 650 arrayParamOut(cp, #member, member, size) 651 652#define UNSERIALIZE_ARRAY(member, size) \ 653 arrayParamIn(cp, #member, member, size) 654 655#define SERIALIZE_CONTAINER(member) \ 656 arrayParamOut(cp, #member, member) 657 658#define UNSERIALIZE_CONTAINER(member) \ 659 arrayParamIn(cp, #member, member) 660 661#define SERIALIZE_EVENT(event) event.serializeSection(cp, #event); 662 663#define UNSERIALIZE_EVENT(event) \ 664 do { \ 665 event.unserializeSection(cp, #event); \ 666 eventQueue()->checkpointReschedule(&event); \ 667 } while (0) 668 669#define SERIALIZE_OBJ(obj) obj.serializeSection(cp, #obj) 670#define UNSERIALIZE_OBJ(obj) obj.unserializeSection(cp, #obj) 671 672#define SERIALIZE_OBJPTR(objptr) paramOut(cp, #objptr, (objptr)->name()) 673 674#define UNSERIALIZE_OBJPTR(objptr) \ 675 do { \ 676 SimObject *sptr; \ 677 objParamIn(cp, #objptr, sptr); \ 678 objptr = dynamic_cast<decltype(objptr)>(sptr); \ 679 } while (0) 680 681#endif // __SERIALIZE_HH__ 682