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