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