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