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