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