serialize.cc revision 6225
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 int size = param.size(); 186 os << name << "="; 187 if (size > 0) 188 showParam(os, param[0]); 189 for (int 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, int size) 211{ 212 os << name << "="; 213 if (size > 0) 214 showParam(os, param[0]); 215 for (int 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, int 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 (int 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 (int 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 309 310 311void 312objParamIn(Checkpoint *cp, const string §ion, 313 const string &name, SimObject * ¶m) 314{ 315 if (!cp->findObj(section, name, param)) { 316 fatal("Can't unserialize '%s:%s'\n", section, name); 317 } 318} 319 320 321#define INSTANTIATE_PARAM_TEMPLATES(type) \ 322template void \ 323paramOut(ostream &os, const string &name, type const ¶m); \ 324template void \ 325paramIn(Checkpoint *cp, const string §ion, \ 326 const string &name, type & param); \ 327template void \ 328arrayParamOut(ostream &os, const string &name, \ 329 type const *param, int size); \ 330template void \ 331arrayParamIn(Checkpoint *cp, const string §ion, \ 332 const string &name, type *param, int size); \ 333template void \ 334arrayParamOut(ostream &os, const string &name, \ 335 const vector<type> ¶m); \ 336template void \ 337arrayParamIn(Checkpoint *cp, const string §ion, \ 338 const string &name, vector<type> ¶m); 339 340INSTANTIATE_PARAM_TEMPLATES(signed char) 341INSTANTIATE_PARAM_TEMPLATES(unsigned char) 342INSTANTIATE_PARAM_TEMPLATES(signed short) 343INSTANTIATE_PARAM_TEMPLATES(unsigned short) 344INSTANTIATE_PARAM_TEMPLATES(signed int) 345INSTANTIATE_PARAM_TEMPLATES(unsigned int) 346INSTANTIATE_PARAM_TEMPLATES(signed long) 347INSTANTIATE_PARAM_TEMPLATES(unsigned long) 348INSTANTIATE_PARAM_TEMPLATES(signed long long) 349INSTANTIATE_PARAM_TEMPLATES(unsigned long long) 350INSTANTIATE_PARAM_TEMPLATES(bool) 351INSTANTIATE_PARAM_TEMPLATES(float) 352INSTANTIATE_PARAM_TEMPLATES(double) 353INSTANTIATE_PARAM_TEMPLATES(string) 354 355 356///////////////////////////// 357 358/// Container for serializing global variables (not associated with 359/// any serialized object). 360class Globals : public Serializable 361{ 362 public: 363 const string name() const; 364 void serialize(ostream &os); 365 void unserialize(Checkpoint *cp); 366}; 367 368/// The one and only instance of the Globals class. 369Globals globals; 370 371const string 372Globals::name() const 373{ 374 return "Globals"; 375} 376 377void 378Globals::serialize(ostream &os) 379{ 380 nameOut(os); 381 SERIALIZE_SCALAR(curTick); 382 383 nameOut(os, "MainEventQueue"); 384 mainEventQueue.serialize(os); 385} 386 387void 388Globals::unserialize(Checkpoint *cp) 389{ 390 const string §ion = name(); 391 UNSERIALIZE_SCALAR(curTick); 392 393 mainEventQueue.unserialize(cp, "MainEventQueue"); 394} 395 396Serializable::Serializable() 397{ 398} 399 400Serializable::~Serializable() 401{ 402} 403 404void 405Serializable::serialize(ostream &os) 406{ 407} 408 409void 410Serializable::unserialize(Checkpoint *cp, const string §ion) 411{ 412} 413 414void 415Serializable::serializeAll(const string &cpt_dir) 416{ 417 setCheckpointDir(cpt_dir); 418 string dir = Checkpoint::dir(); 419 if (mkdir(dir.c_str(), 0775) == -1 && errno != EEXIST) 420 fatal("couldn't mkdir %s\n", dir); 421 422 string cpt_file = dir + Checkpoint::baseFilename; 423 ofstream outstream(cpt_file.c_str()); 424 time_t t = time(NULL); 425 if (!outstream.is_open()) 426 fatal("Unable to open file %s for writing\n", cpt_file.c_str()); 427 outstream << "// checkpoint generated: " << ctime(&t); 428 429 globals.serialize(outstream); 430 SimObject::serializeAll(outstream); 431} 432 433void 434Serializable::unserializeAll(const string &cpt_dir) 435{ 436 setCheckpointDir(cpt_dir); 437 string dir = Checkpoint::dir(); 438 string cpt_file = dir + Checkpoint::baseFilename; 439 string section = ""; 440 441 DPRINTFR(Config, "Loading checkpoint dir '%s'\n", 442 dir); 443 Checkpoint *cp = new Checkpoint(dir, section); 444 unserializeGlobals(cp); 445 SimObject::unserializeAll(cp); 446} 447 448void 449Serializable::unserializeGlobals(Checkpoint *cp) 450{ 451 globals.unserialize(cp); 452} 453 454const char *Checkpoint::baseFilename = "m5.cpt"; 455 456static string checkpointDirBase; 457 458void 459setCheckpointDir(const string &name) 460{ 461 checkpointDirBase = name; 462 if (checkpointDirBase[checkpointDirBase.size() - 1] != '/') 463 checkpointDirBase += "/"; 464} 465 466string 467Checkpoint::dir() 468{ 469 // use csprintf to insert curTick into directory name if it 470 // appears to have a format placeholder in it. 471 return (checkpointDirBase.find("%") != string::npos) ? 472 csprintf(checkpointDirBase, curTick) : checkpointDirBase; 473} 474 475void 476debug_serialize(const string &cpt_dir) 477{ 478 Serializable::serializeAll(cpt_dir); 479} 480 481 482//////////////////////////////////////////////////////////////////////// 483// 484// SerializableClass member definitions 485// 486//////////////////////////////////////////////////////////////////////// 487 488// Map of class names to SerializableBuilder creation functions. 489// Need to make this a pointer so we can force initialization on the 490// first reference; otherwise, some SerializableClass constructors 491// may be invoked before the classMap constructor. 492map<string, SerializableClass::CreateFunc> *SerializableClass::classMap = 0; 493 494// SerializableClass constructor: add mapping to classMap 495SerializableClass::SerializableClass(const string &className, 496 CreateFunc createFunc) 497{ 498 if (classMap == NULL) 499 classMap = new map<string, SerializableClass::CreateFunc>(); 500 501 if ((*classMap)[className]) 502 fatal("Error: simulation object class %s redefined\n", className); 503 504 // add className --> createFunc to class map 505 (*classMap)[className] = createFunc; 506} 507 508// 509// 510Serializable * 511SerializableClass::createObject(Checkpoint *cp, const string §ion) 512{ 513 string className; 514 515 if (!cp->find(section, "type", className)) { 516 fatal("Serializable::create: no 'type' entry in section '%s'.\n", 517 section); 518 } 519 520 CreateFunc createFunc = (*classMap)[className]; 521 522 if (createFunc == NULL) { 523 fatal("Serializable::create: no create function for class '%s'.\n", 524 className); 525 } 526 527 Serializable *object = createFunc(cp, section); 528 529 assert(object != NULL); 530 531 return object; 532} 533 534 535Serializable * 536Serializable::create(Checkpoint *cp, const string §ion) 537{ 538 Serializable *object = SerializableClass::createObject(cp, section); 539 object->unserialize(cp, section); 540 return object; 541} 542 543 544Checkpoint::Checkpoint(const string &cpt_dir, const string &path) 545 : db(new IniFile), basePath(path), cptDir(cpt_dir) 546{ 547 string filename = cpt_dir + "/" + Checkpoint::baseFilename; 548 if (!db->load(filename)) { 549 fatal("Can't load checkpoint file '%s'\n", filename); 550 } 551} 552 553 554bool 555Checkpoint::find(const string §ion, const string &entry, string &value) 556{ 557 return db->find(section, entry, value); 558} 559 560 561bool 562Checkpoint::findObj(const string §ion, const string &entry, 563 SimObject *&value) 564{ 565 string path; 566 567 if (!db->find(section, entry, path)) 568 return false; 569 570 value = resolveSimObject(path); 571 return true; 572} 573 574 575bool 576Checkpoint::sectionExists(const string §ion) 577{ 578 return db->sectionExists(section); 579} 580