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