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