serialize.cc revision 4762
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 std::string &name, const T ¶m) 175{ 176 os << name << "="; 177 showParam(os, param); 178 os << "\n"; 179} 180 181 182template <class T> 183void 184paramIn(Checkpoint *cp, const std::string §ion, 185 const std::string &name, T ¶m) 186{ 187 std::string str; 188 if (!cp->find(section, name, str) || !parseParam(str, param)) { 189 fatal("Can't unserialize '%s:%s'\n", section, name); 190 } 191} 192 193 194template <class T> 195void 196arrayParamOut(ostream &os, const std::string &name, 197 const T *param, int size) 198{ 199 os << name << "="; 200 if (size > 0) 201 showParam(os, param[0]); 202 for (int i = 1; i < size; ++i) { 203 os << " "; 204 showParam(os, param[i]); 205 } 206 os << "\n"; 207} 208 209 210template <class T> 211void 212arrayParamIn(Checkpoint *cp, const std::string §ion, 213 const std::string &name, T *param, int size) 214{ 215 std::string str; 216 if (!cp->find(section, name, str)) { 217 fatal("Can't unserialize '%s:%s'\n", section, name); 218 } 219 220 // code below stolen from VectorParam<T>::parse(). 221 // it would be nice to unify these somehow... 222 223 vector<string> tokens; 224 225 tokenize(tokens, str, ' '); 226 227 // Need this if we were doing a vector 228 // value.resize(tokens.size()); 229 230 if (tokens.size() != size) { 231 fatal("Array size mismatch on %s:%s'\n", section, name); 232 } 233 234 for (int i = 0; i < tokens.size(); i++) { 235 // need to parse into local variable to handle vector<bool>, 236 // for which operator[] returns a special reference class 237 // that's not the same as 'bool&', (since it's a packed 238 // vector) 239 T scalar_value; 240 if (!parseParam(tokens[i], scalar_value)) { 241 string err("could not parse \""); 242 243 err += str; 244 err += "\""; 245 246 fatal(err); 247 } 248 249 // assign parsed value to vector 250 param[i] = scalar_value; 251 } 252} 253 254 255void 256objParamIn(Checkpoint *cp, const std::string §ion, 257 const std::string &name, SimObject * ¶m) 258{ 259 if (!cp->findObj(section, name, param)) { 260 fatal("Can't unserialize '%s:%s'\n", section, name); 261 } 262} 263 264 265#define INSTANTIATE_PARAM_TEMPLATES(type) \ 266template void \ 267paramOut(ostream &os, const std::string &name, type const ¶m); \ 268template void \ 269paramIn(Checkpoint *cp, const std::string §ion, \ 270 const std::string &name, type & param); \ 271template void \ 272arrayParamOut(ostream &os, const std::string &name, \ 273 type const *param, int size); \ 274template void \ 275arrayParamIn(Checkpoint *cp, const std::string §ion, \ 276 const std::string &name, type *param, int size); 277 278INSTANTIATE_PARAM_TEMPLATES(signed char) 279INSTANTIATE_PARAM_TEMPLATES(unsigned char) 280INSTANTIATE_PARAM_TEMPLATES(signed short) 281INSTANTIATE_PARAM_TEMPLATES(unsigned short) 282INSTANTIATE_PARAM_TEMPLATES(signed int) 283INSTANTIATE_PARAM_TEMPLATES(unsigned int) 284INSTANTIATE_PARAM_TEMPLATES(signed long) 285INSTANTIATE_PARAM_TEMPLATES(unsigned long) 286INSTANTIATE_PARAM_TEMPLATES(signed long long) 287INSTANTIATE_PARAM_TEMPLATES(unsigned long long) 288INSTANTIATE_PARAM_TEMPLATES(bool) 289INSTANTIATE_PARAM_TEMPLATES(string) 290 291 292///////////////////////////// 293 294/// Container for serializing global variables (not associated with 295/// any serialized object). 296class Globals : public Serializable 297{ 298 public: 299 const string name() const; 300 void serialize(ostream &os); 301 void unserialize(Checkpoint *cp); 302}; 303 304/// The one and only instance of the Globals class. 305Globals globals; 306 307const string 308Globals::name() const 309{ 310 return "Globals"; 311} 312 313void 314Globals::serialize(ostream &os) 315{ 316 nameOut(os); 317 SERIALIZE_SCALAR(curTick); 318 319 nameOut(os, "MainEventQueue"); 320 mainEventQueue.serialize(os); 321} 322 323void 324Globals::unserialize(Checkpoint *cp) 325{ 326 const string §ion = name(); 327 UNSERIALIZE_SCALAR(curTick); 328 329 mainEventQueue.unserialize(cp, "MainEventQueue"); 330} 331 332void 333Serializable::serializeAll(const std::string &cpt_dir) 334{ 335 setCheckpointDir(cpt_dir); 336 string dir = Checkpoint::dir(); 337 if (mkdir(dir.c_str(), 0775) == -1 && errno != EEXIST) 338 fatal("couldn't mkdir %s\n", dir); 339 340 string cpt_file = dir + Checkpoint::baseFilename; 341 ofstream outstream(cpt_file.c_str()); 342 time_t t = time(NULL); 343 outstream << "// checkpoint generated: " << ctime(&t); 344 345 globals.serialize(outstream); 346 SimObject::serializeAll(outstream); 347} 348 349void 350Serializable::unserializeAll(const std::string &cpt_dir) 351{ 352 setCheckpointDir(cpt_dir); 353 string dir = Checkpoint::dir(); 354 string cpt_file = dir + Checkpoint::baseFilename; 355 string section = ""; 356 357 DPRINTFR(Config, "Loading checkpoint dir '%s'\n", 358 dir); 359 Checkpoint *cp = new Checkpoint(dir, section); 360 unserializeGlobals(cp); 361 362 SimObject::unserializeAll(cp); 363} 364 365void 366Serializable::unserializeGlobals(Checkpoint *cp) 367{ 368 globals.unserialize(cp); 369} 370 371const char *Checkpoint::baseFilename = "m5.cpt"; 372 373static string checkpointDirBase; 374 375void 376setCheckpointDir(const std::string &name) 377{ 378 checkpointDirBase = name; 379 if (checkpointDirBase[checkpointDirBase.size() - 1] != '/') 380 checkpointDirBase += "/"; 381} 382 383string 384Checkpoint::dir() 385{ 386 // use csprintf to insert curTick into directory name if it 387 // appears to have a format placeholder in it. 388 return (checkpointDirBase.find("%") != string::npos) ? 389 csprintf(checkpointDirBase, curTick) : checkpointDirBase; 390} 391 392void 393debug_serialize(const std::string &cpt_dir) 394{ 395 Serializable::serializeAll(cpt_dir); 396} 397 398 399//////////////////////////////////////////////////////////////////////// 400// 401// SerializableClass member definitions 402// 403//////////////////////////////////////////////////////////////////////// 404 405// Map of class names to SerializableBuilder creation functions. 406// Need to make this a pointer so we can force initialization on the 407// first reference; otherwise, some SerializableClass constructors 408// may be invoked before the classMap constructor. 409map<string,SerializableClass::CreateFunc> *SerializableClass::classMap = 0; 410 411// SerializableClass constructor: add mapping to classMap 412SerializableClass::SerializableClass(const string &className, 413 CreateFunc createFunc) 414{ 415 if (classMap == NULL) 416 classMap = new map<string,SerializableClass::CreateFunc>(); 417 418 if ((*classMap)[className]) 419 { 420 cerr << "Error: simulation object class " << className << " redefined" 421 << endl; 422 fatal(""); 423 } 424 425 // add className --> createFunc to class map 426 (*classMap)[className] = createFunc; 427} 428 429 430// 431// 432Serializable * 433SerializableClass::createObject(Checkpoint *cp, 434 const std::string §ion) 435{ 436 string className; 437 438 if (!cp->find(section, "type", className)) { 439 fatal("Serializable::create: no 'type' entry in section '%s'.\n", 440 section); 441 } 442 443 CreateFunc createFunc = (*classMap)[className]; 444 445 if (createFunc == NULL) { 446 fatal("Serializable::create: no create function for class '%s'.\n", 447 className); 448 } 449 450 Serializable *object = createFunc(cp, section); 451 452 assert(object != NULL); 453 454 return object; 455} 456 457 458Serializable * 459Serializable::create(Checkpoint *cp, const std::string §ion) 460{ 461 Serializable *object = SerializableClass::createObject(cp, section); 462 object->unserialize(cp, section); 463 return object; 464} 465 466 467Checkpoint::Checkpoint(const std::string &cpt_dir, const std::string &path) 468 : db(new IniFile), basePath(path), cptDir(cpt_dir) 469{ 470 string filename = cpt_dir + "/" + Checkpoint::baseFilename; 471 if (!db->load(filename)) { 472 fatal("Can't load checkpoint file '%s'\n", filename); 473 } 474} 475 476 477bool 478Checkpoint::find(const std::string §ion, const std::string &entry, 479 std::string &value) 480{ 481 return db->find(section, entry, value); 482} 483 484 485bool 486Checkpoint::findObj(const std::string §ion, const std::string &entry, 487 SimObject *&value) 488{ 489 string path; 490 491 if (!db->find(section, entry, path)) 492 return false; 493 494 value = resolveSimObject(path); 495 return true; 496} 497 498 499bool 500Checkpoint::sectionExists(const std::string §ion) 501{ 502 return db->sectionExists(section); 503} 504