serialize.cc revision 7491
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 signed 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 207template <class T> 208bool 209optParamIn(Checkpoint *cp, const string §ion, const string &name, T ¶m) 210{ 211 string str; 212 if (!cp->find(section, name, str) || !parseParam(str, param)) { 213 warn("optional parameter %s:%s not present\n", section, name); 214 return false; 215 } else { 216 return true; 217 } 218} 219 220template <class T> 221void 222arrayParamOut(ostream &os, const string &name, const T *param, unsigned size) 223{ 224 os << name << "="; 225 if (size > 0) 226 showParam(os, param[0]); 227 for (unsigned i = 1; i < size; ++i) { 228 os << " "; 229 showParam(os, param[i]); 230 } 231 os << "\n"; 232} 233 234 235template <class T> 236void 237arrayParamIn(Checkpoint *cp, const string §ion, const string &name, 238 T *param, unsigned size) 239{ 240 string str; 241 if (!cp->find(section, name, str)) { 242 fatal("Can't unserialize '%s:%s'\n", section, name); 243 } 244 245 // code below stolen from VectorParam<T>::parse(). 246 // it would be nice to unify these somehow... 247 248 vector<string> tokens; 249 250 tokenize(tokens, str, ' '); 251 252 // Need this if we were doing a vector 253 // value.resize(tokens.size()); 254 255 if (tokens.size() != size) { 256 fatal("Array size mismatch on %s:%s'\n", section, name); 257 } 258 259 for (vector<string>::size_type i = 0; i < tokens.size(); i++) { 260 // need to parse into local variable to handle vector<bool>, 261 // for which operator[] returns a special reference class 262 // that's not the same as 'bool&', (since it's a packed 263 // vector) 264 T scalar_value; 265 if (!parseParam(tokens[i], scalar_value)) { 266 string err("could not parse \""); 267 268 err += str; 269 err += "\""; 270 271 fatal(err); 272 } 273 274 // assign parsed value to vector 275 param[i] = scalar_value; 276 } 277} 278 279template <class T> 280void 281arrayParamIn(Checkpoint *cp, const string §ion, 282 const string &name, vector<T> ¶m) 283{ 284 string str; 285 if (!cp->find(section, name, str)) { 286 fatal("Can't unserialize '%s:%s'\n", section, name); 287 } 288 289 // code below stolen from VectorParam<T>::parse(). 290 // it would be nice to unify these somehow... 291 292 vector<string> tokens; 293 294 tokenize(tokens, str, ' '); 295 296 // Need this if we were doing a vector 297 // value.resize(tokens.size()); 298 299 param.resize(tokens.size()); 300 301 for (vector<string>::size_type i = 0; i < tokens.size(); i++) { 302 // need to parse into local variable to handle vector<bool>, 303 // for which operator[] returns a special reference class 304 // that's not the same as 'bool&', (since it's a packed 305 // vector) 306 T scalar_value; 307 if (!parseParam(tokens[i], scalar_value)) { 308 string err("could not parse \""); 309 310 err += str; 311 err += "\""; 312 313 fatal(err); 314 } 315 316 // assign parsed value to vector 317 param[i] = scalar_value; 318 } 319} 320 321void 322objParamIn(Checkpoint *cp, const string §ion, 323 const string &name, SimObject * ¶m) 324{ 325 if (!cp->findObj(section, name, param)) { 326 fatal("Can't unserialize '%s:%s'\n", section, name); 327 } 328} 329 330 331#define INSTANTIATE_PARAM_TEMPLATES(type) \ 332template void \ 333paramOut(ostream &os, const string &name, type const ¶m); \ 334template void \ 335paramIn(Checkpoint *cp, const string §ion, \ 336 const string &name, type & param); \ 337template bool \ 338optParamIn(Checkpoint *cp, const string §ion, \ 339 const string &name, type & param); \ 340template void \ 341arrayParamOut(ostream &os, const string &name, \ 342 type const *param, unsigned size); \ 343template void \ 344arrayParamIn(Checkpoint *cp, const string §ion, \ 345 const string &name, type *param, unsigned size); \ 346template void \ 347arrayParamOut(ostream &os, const string &name, \ 348 const vector<type> ¶m); \ 349template void \ 350arrayParamIn(Checkpoint *cp, const string §ion, \ 351 const string &name, vector<type> ¶m); 352 353INSTANTIATE_PARAM_TEMPLATES(signed char) 354INSTANTIATE_PARAM_TEMPLATES(unsigned char) 355INSTANTIATE_PARAM_TEMPLATES(signed short) 356INSTANTIATE_PARAM_TEMPLATES(unsigned short) 357INSTANTIATE_PARAM_TEMPLATES(signed int) 358INSTANTIATE_PARAM_TEMPLATES(unsigned int) 359INSTANTIATE_PARAM_TEMPLATES(signed long) 360INSTANTIATE_PARAM_TEMPLATES(unsigned long) 361INSTANTIATE_PARAM_TEMPLATES(signed long long) 362INSTANTIATE_PARAM_TEMPLATES(unsigned long long) 363INSTANTIATE_PARAM_TEMPLATES(bool) 364INSTANTIATE_PARAM_TEMPLATES(float) 365INSTANTIATE_PARAM_TEMPLATES(double) 366INSTANTIATE_PARAM_TEMPLATES(string) 367 368 369///////////////////////////// 370 371/// Container for serializing global variables (not associated with 372/// any serialized object). 373class Globals : public Serializable 374{ 375 public: 376 const string name() const; 377 void serialize(ostream &os); 378 void unserialize(Checkpoint *cp); 379}; 380 381/// The one and only instance of the Globals class. 382Globals globals; 383 384const string 385Globals::name() const 386{ 387 return "Globals"; 388} 389 390void 391Globals::serialize(ostream &os) 392{ 393 nameOut(os); 394 SERIALIZE_SCALAR(curTick); 395 396 nameOut(os, "MainEventQueue"); 397 mainEventQueue.serialize(os); 398} 399 400void 401Globals::unserialize(Checkpoint *cp) 402{ 403 const string §ion = name(); 404 UNSERIALIZE_SCALAR(curTick); 405 406 mainEventQueue.unserialize(cp, "MainEventQueue"); 407} 408 409Serializable::Serializable() 410{ 411} 412 413Serializable::~Serializable() 414{ 415} 416 417void 418Serializable::serialize(ostream &os) 419{ 420} 421 422void 423Serializable::unserialize(Checkpoint *cp, const string §ion) 424{ 425} 426 427void 428Serializable::serializeAll(const string &cpt_dir) 429{ 430 string dir = Checkpoint::setDir(cpt_dir); 431 if (mkdir(dir.c_str(), 0775) == -1 && errno != EEXIST) 432 fatal("couldn't mkdir %s\n", dir); 433 434 string cpt_file = dir + Checkpoint::baseFilename; 435 ofstream outstream(cpt_file.c_str()); 436 time_t t = time(NULL); 437 if (!outstream.is_open()) 438 fatal("Unable to open file %s for writing\n", cpt_file.c_str()); 439 outstream << "## checkpoint generated: " << ctime(&t); 440 441 globals.serialize(outstream); 442 SimObject::serializeAll(outstream); 443} 444 445void 446Serializable::unserializeAll(const string &cpt_dir) 447{ 448 string dir = Checkpoint::setDir(cpt_dir); 449 450 DPRINTFR(Config, "Loading checkpoint dir '%s'\n", dir); 451 Checkpoint *cp = new Checkpoint(dir); 452 unserializeGlobals(cp); 453 SimObject::unserializeAll(cp); 454} 455 456void 457Serializable::unserializeGlobals(Checkpoint *cp) 458{ 459 globals.unserialize(cp); 460} 461 462void 463debug_serialize(const string &cpt_dir) 464{ 465 Serializable::serializeAll(cpt_dir); 466} 467 468 469//////////////////////////////////////////////////////////////////////// 470// 471// SerializableClass member definitions 472// 473//////////////////////////////////////////////////////////////////////// 474 475// Map of class names to SerializableBuilder creation functions. 476// Need to make this a pointer so we can force initialization on the 477// first reference; otherwise, some SerializableClass constructors 478// may be invoked before the classMap constructor. 479map<string, SerializableClass::CreateFunc> *SerializableClass::classMap = 0; 480 481// SerializableClass constructor: add mapping to classMap 482SerializableClass::SerializableClass(const string &className, 483 CreateFunc createFunc) 484{ 485 if (classMap == NULL) 486 classMap = new map<string, SerializableClass::CreateFunc>(); 487 488 if ((*classMap)[className]) 489 fatal("Error: simulation object class %s redefined\n", className); 490 491 // add className --> createFunc to class map 492 (*classMap)[className] = createFunc; 493} 494 495// 496// 497Serializable * 498SerializableClass::createObject(Checkpoint *cp, const string §ion) 499{ 500 string className; 501 502 if (!cp->find(section, "type", className)) { 503 fatal("Serializable::create: no 'type' entry in section '%s'.\n", 504 section); 505 } 506 507 CreateFunc createFunc = (*classMap)[className]; 508 509 if (createFunc == NULL) { 510 fatal("Serializable::create: no create function for class '%s'.\n", 511 className); 512 } 513 514 Serializable *object = createFunc(cp, section); 515 516 assert(object != NULL); 517 518 return object; 519} 520 521 522Serializable * 523Serializable::create(Checkpoint *cp, const string §ion) 524{ 525 Serializable *object = SerializableClass::createObject(cp, section); 526 object->unserialize(cp, section); 527 return object; 528} 529 530 531const char *Checkpoint::baseFilename = "m5.cpt"; 532 533string Checkpoint::currentDirectory; 534 535string 536Checkpoint::setDir(const string &name) 537{ 538 // use csprintf to insert curTick into directory name if it 539 // appears to have a format placeholder in it. 540 currentDirectory = (name.find("%") != string::npos) ? 541 csprintf(name, curTick) : name; 542 if (currentDirectory[currentDirectory.size() - 1] != '/') 543 currentDirectory += "/"; 544 return currentDirectory; 545} 546 547string 548Checkpoint::dir() 549{ 550 return currentDirectory; 551} 552 553 554Checkpoint::Checkpoint(const string &cpt_dir) 555 : db(new IniFile), cptDir(cpt_dir) 556{ 557 string filename = cpt_dir + "/" + Checkpoint::baseFilename; 558 if (!db->load(filename)) { 559 fatal("Can't load checkpoint file '%s'\n", filename); 560 } 561} 562 563 564bool 565Checkpoint::find(const string §ion, const string &entry, string &value) 566{ 567 return db->find(section, entry, value); 568} 569 570 571bool 572Checkpoint::findObj(const string §ion, const string &entry, 573 SimObject *&value) 574{ 575 string path; 576 577 if (!db->find(section, entry, path)) 578 return false; 579 580 value = resolveSimObject(path); 581 return true; 582} 583 584 585bool 586Checkpoint::sectionExists(const string §ion) 587{ 588 return db->sectionExists(section); 589} 590