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