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 §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 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 ¶m) 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 ¶m) 367{ 368 const std::string §ion(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 ¶m, bool warn = true) 388{ 389 const std::string §ion(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> ¶m) 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> ¶m) 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> ¶m) 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 §ion(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> ¶m) 532{ 533 const std::string §ion(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> ¶m) 574{ 575 const std::string §ion(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> ¶m) 604{ 605 const std::string §ion(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 * ¶m); 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