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