serialize.cc revision 11793:ef606668d247
1/* 2 * Copyright (c) 2015 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 * Copyright (c) 2013 Advanced Micro Devices, Inc. 16 * Copyright (c) 2013 Mark D. Hill and David A. Wood 17 * All rights reserved. 18 * 19 * Redistribution and use in source and binary forms, with or without 20 * modification, are permitted provided that the following conditions are 21 * met: redistributions of source code must retain the above copyright 22 * notice, this list of conditions and the following disclaimer; 23 * redistributions in binary form must reproduce the above copyright 24 * notice, this list of conditions and the following disclaimer in the 25 * documentation and/or other materials provided with the distribution; 26 * neither the name of the copyright holders nor the names of its 27 * contributors may be used to endorse or promote products derived from 28 * this software without specific prior written permission. 29 * 30 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 31 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 32 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 33 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 34 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 35 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 36 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 37 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 38 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 39 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 40 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 41 * 42 * Authors: Nathan Binkert 43 * Erik Hallnor 44 * Steve Reinhardt 45 * Andreas Sandberg 46 */ 47 48#include "sim/serialize.hh" 49 50#include <sys/stat.h> 51#include <sys/time.h> 52#include <sys/types.h> 53 54#include <cerrno> 55#include <fstream> 56#include <list> 57#include <string> 58#include <vector> 59 60#include "base/framebuffer.hh" 61#include "base/inifile.hh" 62#include "base/misc.hh" 63#include "base/output.hh" 64#include "base/str.hh" 65#include "base/trace.hh" 66#include "debug/Checkpoint.hh" 67#include "sim/eventq.hh" 68#include "sim/sim_events.hh" 69#include "sim/sim_exit.hh" 70#include "sim/sim_object.hh" 71 72// For stat reset hack 73#include "sim/stat_control.hh" 74 75using namespace std; 76 77// 78// The base implementations use to_number for parsing and '<<' for 79// displaying, suitable for integer types. 80// 81template <class T> 82bool 83parseParam(const string &s, T &value) 84{ 85 return to_number(s, value); 86} 87 88template <class T> 89void 90showParam(CheckpointOut &os, const T &value) 91{ 92 os << value; 93} 94 95// 96// Template specializations: 97// - char (8-bit integer) 98// - floating-point types 99// - bool 100// - string 101// 102 103// Treat 8-bit ints (chars) as ints on output, not as chars 104template <> 105void 106showParam(CheckpointOut &os, const char &value) 107{ 108 os << (int)value; 109} 110 111 112template <> 113void 114showParam(CheckpointOut &os, const signed char &value) 115{ 116 os << (int)value; 117} 118 119 120template <> 121void 122showParam(CheckpointOut &os, const unsigned char &value) 123{ 124 os << (unsigned int)value; 125} 126 127 128template <> 129bool 130parseParam(const string &s, float &value) 131{ 132 return to_number(s, value); 133} 134 135template <> 136bool 137parseParam(const string &s, double &value) 138{ 139 return to_number(s, value); 140} 141 142template <> 143bool 144parseParam(const string &s, bool &value) 145{ 146 return to_bool(s, value); 147} 148 149// Display bools as strings 150template <> 151void 152showParam(CheckpointOut &os, const bool &value) 153{ 154 os << (value ? "true" : "false"); 155} 156 157 158// String requires no processing to speak of 159template <> 160bool 161parseParam(const string &s, string &value) 162{ 163 value = s; 164 return true; 165} 166 167int Serializable::ckptMaxCount = 0; 168int Serializable::ckptCount = 0; 169int Serializable::ckptPrevCount = -1; 170std::stack<std::string> Serializable::path; 171 172template <class T> 173void 174paramOut(CheckpointOut &os, const string &name, const T ¶m) 175{ 176 os << name << "="; 177 showParam(os, param); 178 os << "\n"; 179} 180 181template <class T> 182void 183arrayParamOut(CheckpointOut &os, const string &name, const vector<T> ¶m) 184{ 185 typename vector<T>::size_type size = param.size(); 186 os << name << "="; 187 if (size > 0) 188 showParam(os, param[0]); 189 for (typename vector<T>::size_type i = 1; i < size; ++i) { 190 os << " "; 191 showParam(os, param[i]); 192 } 193 os << "\n"; 194} 195 196template <class T> 197void 198arrayParamOut(CheckpointOut &os, const string &name, const list<T> ¶m) 199{ 200 typename list<T>::const_iterator it = param.begin(); 201 202 os << name << "="; 203 if (param.size() > 0) 204 showParam(os, *it); 205 it++; 206 while (it != param.end()) { 207 os << " "; 208 showParam(os, *it); 209 it++; 210 } 211 os << "\n"; 212} 213 214template <class T> 215void 216arrayParamOut(CheckpointOut &os, const string &name, const set<T> ¶m) 217{ 218 typename set<T>::const_iterator it = param.begin(); 219 220 os << name << "="; 221 if (param.size() > 0) 222 showParam(os, *it); 223 it++; 224 while (it != param.end()) { 225 os << " "; 226 showParam(os, *it); 227 it++; 228 } 229 os << "\n"; 230} 231 232template <class T> 233void 234paramIn(CheckpointIn &cp, const string &name, T ¶m) 235{ 236 const string §ion(Serializable::currentSection()); 237 string str; 238 if (!cp.find(section, name, str) || !parseParam(str, param)) { 239 fatal("Can't unserialize '%s:%s'\n", section, name); 240 } 241} 242 243template <class T> 244bool 245optParamIn(CheckpointIn &cp, const string &name, T ¶m, bool warn) 246{ 247 const string §ion(Serializable::currentSection()); 248 string str; 249 if (!cp.find(section, name, str) || !parseParam(str, param)) { 250 if (warn) 251 warn("optional parameter %s:%s not present\n", section, name); 252 return false; 253 } else { 254 return true; 255 } 256} 257 258template <class T> 259void 260arrayParamOut(CheckpointOut &os, const string &name, 261 const T *param, unsigned size) 262{ 263 os << name << "="; 264 if (size > 0) 265 showParam(os, param[0]); 266 for (unsigned i = 1; i < size; ++i) { 267 os << " "; 268 showParam(os, param[i]); 269 } 270 os << "\n"; 271} 272 273 274template <class T> 275void 276arrayParamIn(CheckpointIn &cp, const string &name, T *param, unsigned size) 277{ 278 const string §ion(Serializable::currentSection()); 279 string str; 280 if (!cp.find(section, name, str)) { 281 fatal("Can't unserialize '%s:%s'\n", section, name); 282 } 283 284 // code below stolen from VectorParam<T>::parse(). 285 // it would be nice to unify these somehow... 286 287 vector<string> tokens; 288 289 tokenize(tokens, str, ' '); 290 291 // Need this if we were doing a vector 292 // value.resize(tokens.size()); 293 294 if (tokens.size() != size) { 295 fatal("Array size mismatch on %s:%s'\n", section, name); 296 } 297 298 for (vector<string>::size_type i = 0; i < tokens.size(); i++) { 299 // need to parse into local variable to handle vector<bool>, 300 // for which operator[] returns a special reference class 301 // that's not the same as 'bool&', (since it's a packed 302 // vector) 303 T scalar_value; 304 if (!parseParam(tokens[i], scalar_value)) { 305 string err("could not parse \""); 306 307 err += str; 308 err += "\""; 309 310 fatal(err); 311 } 312 313 // assign parsed value to vector 314 param[i] = scalar_value; 315 } 316} 317 318template <class T> 319void 320arrayParamIn(CheckpointIn &cp, const string &name, vector<T> ¶m) 321{ 322 const string §ion(Serializable::currentSection()); 323 string str; 324 if (!cp.find(section, name, str)) { 325 fatal("Can't unserialize '%s:%s'\n", section, name); 326 } 327 328 // code below stolen from VectorParam<T>::parse(). 329 // it would be nice to unify these somehow... 330 331 vector<string> tokens; 332 333 tokenize(tokens, str, ' '); 334 335 // Need this if we were doing a vector 336 // value.resize(tokens.size()); 337 338 param.resize(tokens.size()); 339 340 for (vector<string>::size_type i = 0; i < tokens.size(); i++) { 341 // need to parse into local variable to handle vector<bool>, 342 // for which operator[] returns a special reference class 343 // that's not the same as 'bool&', (since it's a packed 344 // vector) 345 T scalar_value; 346 if (!parseParam(tokens[i], scalar_value)) { 347 string err("could not parse \""); 348 349 err += str; 350 err += "\""; 351 352 fatal(err); 353 } 354 355 // assign parsed value to vector 356 param[i] = scalar_value; 357 } 358} 359 360template <class T> 361void 362arrayParamIn(CheckpointIn &cp, const string &name, list<T> ¶m) 363{ 364 const string §ion(Serializable::currentSection()); 365 string str; 366 if (!cp.find(section, name, str)) { 367 fatal("Can't unserialize '%s:%s'\n", section, name); 368 } 369 param.clear(); 370 371 vector<string> tokens; 372 tokenize(tokens, str, ' '); 373 374 for (vector<string>::size_type i = 0; i < tokens.size(); i++) { 375 T scalar_value; 376 if (!parseParam(tokens[i], scalar_value)) { 377 string err("could not parse \""); 378 379 err += str; 380 err += "\""; 381 382 fatal(err); 383 } 384 385 // assign parsed value to vector 386 param.push_back(scalar_value); 387 } 388} 389 390template <class T> 391void 392arrayParamIn(CheckpointIn &cp, const string &name, set<T> ¶m) 393{ 394 const string §ion(Serializable::currentSection()); 395 string str; 396 if (!cp.find(section, name, str)) { 397 fatal("Can't unserialize '%s:%s'\n", section, name); 398 } 399 param.clear(); 400 401 vector<string> tokens; 402 tokenize(tokens, str, ' '); 403 404 for (vector<string>::size_type i = 0; i < tokens.size(); i++) { 405 T scalar_value; 406 if (!parseParam(tokens[i], scalar_value)) { 407 string err("could not parse \""); 408 409 err += str; 410 err += "\""; 411 412 fatal(err); 413 } 414 415 // assign parsed value to vector 416 param.insert(scalar_value); 417 } 418} 419 420 421void 422objParamIn(CheckpointIn &cp, const string &name, SimObject * ¶m) 423{ 424 const string §ion(Serializable::currentSection()); 425 if (!cp.findObj(section, name, param)) { 426 fatal("Can't unserialize '%s:%s'\n", section, name); 427 } 428} 429 430 431#define INSTANTIATE_PARAM_TEMPLATES(type) \ 432 template void \ 433 paramOut(CheckpointOut &os, const string &name, type const ¶m); \ 434 template void \ 435 paramIn(CheckpointIn &cp, const string &name, type & param); \ 436 template bool \ 437 optParamIn(CheckpointIn &cp, const string &name, type & param, \ 438 bool warn); \ 439 template void \ 440 arrayParamOut(CheckpointOut &os, const string &name, \ 441 type const *param, unsigned size); \ 442 template void \ 443 arrayParamIn(CheckpointIn &cp, const string &name, \ 444 type *param, unsigned size); \ 445 template void \ 446 arrayParamOut(CheckpointOut &os, const string &name, \ 447 const vector<type> ¶m); \ 448 template void \ 449 arrayParamIn(CheckpointIn &cp, const string &name, \ 450 vector<type> ¶m); \ 451 template void \ 452 arrayParamOut(CheckpointOut &os, const string &name, \ 453 const list<type> ¶m); \ 454 template void \ 455 arrayParamIn(CheckpointIn &cp, const string &name, \ 456 list<type> ¶m); 457 458INSTANTIATE_PARAM_TEMPLATES(char) 459INSTANTIATE_PARAM_TEMPLATES(signed char) 460INSTANTIATE_PARAM_TEMPLATES(unsigned char) 461INSTANTIATE_PARAM_TEMPLATES(signed short) 462INSTANTIATE_PARAM_TEMPLATES(unsigned short) 463INSTANTIATE_PARAM_TEMPLATES(signed int) 464INSTANTIATE_PARAM_TEMPLATES(unsigned int) 465INSTANTIATE_PARAM_TEMPLATES(signed long) 466INSTANTIATE_PARAM_TEMPLATES(unsigned long) 467INSTANTIATE_PARAM_TEMPLATES(signed long long) 468INSTANTIATE_PARAM_TEMPLATES(unsigned long long) 469INSTANTIATE_PARAM_TEMPLATES(bool) 470INSTANTIATE_PARAM_TEMPLATES(float) 471INSTANTIATE_PARAM_TEMPLATES(double) 472INSTANTIATE_PARAM_TEMPLATES(string) 473INSTANTIATE_PARAM_TEMPLATES(Pixel) 474 475// set is only used with strings and furthermore doesn't agree with Pixel 476template void 477arrayParamOut(CheckpointOut &, const string &, const set<string> &); 478template void 479arrayParamIn(CheckpointIn &, const string &, set<string> &); 480 481///////////////////////////// 482 483/// Container for serializing global variables (not associated with 484/// any serialized object). 485class Globals : public Serializable 486{ 487 public: 488 Globals() 489 : unserializedCurTick(0) {} 490 491 void serialize(CheckpointOut &cp) const override; 492 void unserialize(CheckpointIn &cp) override; 493 494 Tick unserializedCurTick; 495}; 496 497/// The one and only instance of the Globals class. 498Globals globals; 499 500/// The version tags for this build of the simulator, to be stored in the 501/// Globals section during serialization and compared upon unserialization. 502extern std::set<std::string> version_tags; 503 504void 505Globals::serialize(CheckpointOut &cp) const 506{ 507 paramOut(cp, "curTick", curTick()); 508 SERIALIZE_CONTAINER(version_tags); 509} 510 511void 512Globals::unserialize(CheckpointIn &cp) 513{ 514 paramIn(cp, "curTick", unserializedCurTick); 515 516 const std::string §ion(Serializable::currentSection()); 517 std::string str; 518 if (!cp.find(section, "version_tags", str)) { 519 warn("**********************************************************\n"); 520 warn("!!!! Checkpoint uses an old versioning scheme. !!!!\n"); 521 warn("Run the checkpoint upgrader (util/cpt_upgrader.py) on your " 522 "checkpoint\n"); 523 warn("**********************************************************\n"); 524 return; 525 } 526 527 std::set<std::string> cpt_tags; 528 arrayParamIn(cp, "version_tags", cpt_tags); // UNSERIALIZE_CONTAINER 529 530 bool err = false; 531 for (const auto& t : version_tags) { 532 if (cpt_tags.find(t) == cpt_tags.end()) { 533 // checkpoint is missing tag that this binary has 534 if (!err) { 535 warn("*****************************************************\n"); 536 warn("!!!! Checkpoint is missing the following version tags:\n"); 537 err = true; 538 } 539 warn(" %s\n", t); 540 } 541 } 542 if (err) { 543 warn("You might experience some issues when restoring and should run " 544 "the checkpoint upgrader (util/cpt_upgrader.py) on your " 545 "checkpoint\n"); 546 warn("**********************************************************\n"); 547 } 548 549 err = false; 550 for (const auto& t : cpt_tags) { 551 if (version_tags.find(t) == version_tags.end()) { 552 // gem5 binary is missing tag that this checkpoint has 553 if (!err) { 554 warn("*****************************************************\n"); 555 warn("!!!! gem5 is missing the following version tags:\n"); 556 err = true; 557 } 558 warn(" %s\n", t); 559 } 560 } 561 if (err) { 562 warn("Running a checkpoint with incompatible version tags is not " 563 "supported. While it might work, you may experience incorrect " 564 "behavior or crashes.\n"); 565 warn("**********************************************************\n"); 566 } 567} 568 569Serializable::Serializable() 570{ 571} 572 573Serializable::~Serializable() 574{ 575} 576 577void 578Serializable::serializeSection(CheckpointOut &cp, const char *name) const 579{ 580 Serializable::ScopedCheckpointSection sec(cp, name); 581 serialize(cp); 582} 583 584void 585Serializable::unserializeSection(CheckpointIn &cp, const char *name) 586{ 587 Serializable::ScopedCheckpointSection sec(cp, name); 588 unserialize(cp); 589} 590 591void 592Serializable::serializeAll(const string &cpt_dir) 593{ 594 string dir = CheckpointIn::setDir(cpt_dir); 595 if (mkdir(dir.c_str(), 0775) == -1 && errno != EEXIST) 596 fatal("couldn't mkdir %s\n", dir); 597 598 string cpt_file = dir + CheckpointIn::baseFilename; 599 ofstream outstream(cpt_file.c_str()); 600 time_t t = time(NULL); 601 if (!outstream.is_open()) 602 fatal("Unable to open file %s for writing\n", cpt_file.c_str()); 603 outstream << "## checkpoint generated: " << ctime(&t); 604 605 globals.serializeSection(outstream, "Globals"); 606 607 SimObject::serializeAll(outstream); 608} 609 610void 611Serializable::unserializeGlobals(CheckpointIn &cp) 612{ 613 globals.unserializeSection(cp, "Globals"); 614 615 for (uint32_t i = 0; i < numMainEventQueues; ++i) 616 mainEventQueue[i]->setCurTick(globals.unserializedCurTick); 617} 618 619Serializable::ScopedCheckpointSection::~ScopedCheckpointSection() 620{ 621 assert(!path.empty()); 622 DPRINTF(Checkpoint, "Popping: %s\n", path.top()); 623 path.pop(); 624} 625 626void 627Serializable::ScopedCheckpointSection::pushName(const char *obj_name) 628{ 629 if (path.empty()) { 630 path.push(obj_name); 631 } else { 632 path.push(csprintf("%s.%s", path.top(), obj_name)); 633 } 634 DPRINTF(Checkpoint, "ScopedCheckpointSection::pushName: %s\n", obj_name); 635} 636 637void 638Serializable::ScopedCheckpointSection::nameOut(CheckpointOut &cp) 639{ 640 DPRINTF(Checkpoint, "ScopedCheckpointSection::nameOut: %s\n", 641 Serializable::currentSection()); 642 cp << "\n[" << Serializable::currentSection() << "]\n"; 643} 644 645void 646debug_serialize(const string &cpt_dir) 647{ 648 Serializable::serializeAll(cpt_dir); 649} 650 651const std::string & 652Serializable::currentSection() 653{ 654 assert(!path.empty()); 655 656 return path.top(); 657} 658 659const char *CheckpointIn::baseFilename = "m5.cpt"; 660 661string CheckpointIn::currentDirectory; 662 663string 664CheckpointIn::setDir(const string &name) 665{ 666 // use csprintf to insert curTick() into directory name if it 667 // appears to have a format placeholder in it. 668 currentDirectory = (name.find("%") != string::npos) ? 669 csprintf(name, curTick()) : name; 670 if (currentDirectory[currentDirectory.size() - 1] != '/') 671 currentDirectory += "/"; 672 return currentDirectory; 673} 674 675string 676CheckpointIn::dir() 677{ 678 return currentDirectory; 679} 680 681 682CheckpointIn::CheckpointIn(const string &cpt_dir, SimObjectResolver &resolver) 683 : db(new IniFile), objNameResolver(resolver), cptDir(setDir(cpt_dir)) 684{ 685 string filename = cptDir + "/" + CheckpointIn::baseFilename; 686 if (!db->load(filename)) { 687 fatal("Can't load checkpoint file '%s'\n", filename); 688 } 689} 690 691CheckpointIn::~CheckpointIn() 692{ 693 delete db; 694} 695 696bool 697CheckpointIn::entryExists(const string §ion, const string &entry) 698{ 699 return db->entryExists(section, entry); 700} 701 702bool 703CheckpointIn::find(const string §ion, const string &entry, string &value) 704{ 705 return db->find(section, entry, value); 706} 707 708 709bool 710CheckpointIn::findObj(const string §ion, const string &entry, 711 SimObject *&value) 712{ 713 string path; 714 715 if (!db->find(section, entry, path)) 716 return false; 717 718 value = objNameResolver.resolveSimObject(path); 719 return true; 720} 721 722 723bool 724CheckpointIn::sectionExists(const string §ion) 725{ 726 return db->sectionExists(section); 727} 728