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