serialize.cc revision 1637
1/* 2 * Copyright (c) 2002-2004 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 29#include <sys/time.h> 30#include <sys/types.h> 31#include <sys/stat.h> 32#include <errno.h> 33 34#include <fstream> 35#include <list> 36#include <string> 37#include <vector> 38 39#include "base/inifile.hh" 40#include "base/misc.hh" 41#include "base/output.hh" 42#include "base/str.hh" 43#include "base/trace.hh" 44#include "sim/config_node.hh" 45#include "sim/eventq.hh" 46#include "sim/param.hh" 47#include "sim/serialize.hh" 48#include "sim/sim_events.hh" 49#include "sim/sim_object.hh" 50 51using namespace std; 52 53int Serializable::maxCount; 54int Serializable::count; 55 56void 57Serializable::nameOut(ostream &os) 58{ 59 os << "\n[" << name() << "]\n"; 60} 61 62void 63Serializable::nameOut(ostream &os, const string &_name) 64{ 65 os << "\n[" << _name << "]\n"; 66} 67 68template <class T> 69void 70paramOut(ostream &os, const std::string &name, const T ¶m) 71{ 72 os << name << "="; 73 showParam(os, param); 74 os << "\n"; 75} 76 77 78template <class T> 79void 80paramIn(Checkpoint *cp, const std::string §ion, 81 const std::string &name, T ¶m) 82{ 83 std::string str; 84 if (!cp->find(section, name, str) || !parseParam(str, param)) { 85 fatal("Can't unserialize '%s:%s'\n", section, name); 86 } 87} 88 89 90template <class T> 91void 92arrayParamOut(ostream &os, const std::string &name, 93 const T *param, int size) 94{ 95 os << name << "="; 96 if (size > 0) 97 showParam(os, param[0]); 98 for (int i = 1; i < size; ++i) { 99 os << " "; 100 showParam(os, param[i]); 101 } 102 os << "\n"; 103} 104 105 106template <class T> 107void 108arrayParamIn(Checkpoint *cp, const std::string §ion, 109 const std::string &name, T *param, int size) 110{ 111 std::string str; 112 if (!cp->find(section, name, str)) { 113 fatal("Can't unserialize '%s:%s'\n", section, name); 114 } 115 116 // code below stolen from VectorParam<T>::parse(). 117 // it would be nice to unify these somehow... 118 119 vector<string> tokens; 120 121 tokenize(tokens, str, ' '); 122 123 // Need this if we were doing a vector 124 // value.resize(tokens.size()); 125 126 if (tokens.size() != size) { 127 fatal("Array size mismatch on %s:%s'\n", section, name); 128 } 129 130 for (int i = 0; i < tokens.size(); i++) { 131 // need to parse into local variable to handle vector<bool>, 132 // for which operator[] returns a special reference class 133 // that's not the same as 'bool&', (since it's a packed 134 // vector) 135 T scalar_value; 136 if (!parseParam(tokens[i], scalar_value)) { 137 string err("could not parse \""); 138 139 err += str; 140 err += "\""; 141 142 fatal(err); 143 } 144 145 // assign parsed value to vector 146 param[i] = scalar_value; 147 } 148} 149 150 151void 152objParamIn(Checkpoint *cp, const std::string §ion, 153 const std::string &name, Serializable * ¶m) 154{ 155 if (!cp->findObj(section, name, param)) { 156 fatal("Can't unserialize '%s:%s'\n", section, name); 157 } 158} 159 160 161#define INSTANTIATE_PARAM_TEMPLATES(type) \ 162template void \ 163paramOut(ostream &os, const std::string &name, type const ¶m); \ 164template void \ 165paramIn(Checkpoint *cp, const std::string §ion, \ 166 const std::string &name, type & param); \ 167template void \ 168arrayParamOut(ostream &os, const std::string &name, \ 169 type const *param, int size); \ 170template void \ 171arrayParamIn(Checkpoint *cp, const std::string §ion, \ 172 const std::string &name, type *param, int size); 173 174 175INSTANTIATE_PARAM_TEMPLATES(int8_t) 176INSTANTIATE_PARAM_TEMPLATES(uint8_t) 177INSTANTIATE_PARAM_TEMPLATES(int16_t) 178INSTANTIATE_PARAM_TEMPLATES(uint16_t) 179INSTANTIATE_PARAM_TEMPLATES(int32_t) 180INSTANTIATE_PARAM_TEMPLATES(uint32_t) 181INSTANTIATE_PARAM_TEMPLATES(int64_t) 182INSTANTIATE_PARAM_TEMPLATES(uint64_t) 183INSTANTIATE_PARAM_TEMPLATES(bool) 184INSTANTIATE_PARAM_TEMPLATES(string) 185 186 187///////////////////////////// 188 189/// Container for serializing global variables (not associated with 190/// any serialized object). 191class Globals : public Serializable 192{ 193 public: 194 const string name() const; 195 void serialize(ostream &os); 196 void unserialize(Checkpoint *cp); 197}; 198 199/// The one and only instance of the Globals class. 200Globals globals; 201 202const string 203Globals::name() const 204{ 205 return "Globals"; 206} 207 208void 209Globals::serialize(ostream &os) 210{ 211 nameOut(os); 212 SERIALIZE_SCALAR(curTick); 213 214 nameOut(os, "MainEventQueue"); 215 mainEventQueue.serialize(os); 216} 217 218void 219Globals::unserialize(Checkpoint *cp) 220{ 221 const string §ion = name(); 222 UNSERIALIZE_SCALAR(curTick); 223 224 mainEventQueue.unserialize(cp, "MainEventQueue"); 225} 226 227void 228Serializable::serializeAll() 229{ 230 if (maxCount && count++ > maxCount) 231 SimExit("Maximum number of checkpoints dropped"); 232 233 string dir = Checkpoint::dir(); 234 if (mkdir(dir.c_str(), 0775) == -1 && errno != EEXIST) 235 fatal("couldn't mkdir %s\n", dir); 236 237 string cpt_file = dir + Checkpoint::baseFilename; 238 ofstream outstream(cpt_file.c_str()); 239 time_t t = time(NULL); 240 outstream << "// checkpoint generated: " << ctime(&t); 241 242 globals.serialize(outstream); 243 SimObject::serializeAll(outstream); 244} 245 246 247void 248Serializable::unserializeGlobals(Checkpoint *cp) 249{ 250 globals.unserialize(cp); 251} 252 253 254class SerializeEvent : public Event 255{ 256 protected: 257 Tick repeat; 258 259 public: 260 SerializeEvent(Tick _when, Tick _repeat); 261 virtual void process(); 262 virtual void serialize(std::ostream &os) 263 { 264 panic("Cannot serialize the SerializeEvent"); 265 } 266 267}; 268 269SerializeEvent::SerializeEvent(Tick _when, Tick _repeat) 270 : Event(&mainEventQueue, Serialize_Pri), repeat(_repeat) 271{ 272 setFlags(AutoDelete); 273 schedule(_when); 274} 275 276void 277SerializeEvent::process() 278{ 279 Serializable::serializeAll(); 280 if (repeat) 281 schedule(curTick + repeat); 282} 283 284const char *Checkpoint::baseFilename = "m5.cpt"; 285 286static string checkpointDirBase; 287 288string 289Checkpoint::dir() 290{ 291 // use csprintf to insert curTick into directory name if it 292 // appears to have a format placeholder in it. 293 return (checkpointDirBase.find("%") != string::npos) ? 294 csprintf(checkpointDirBase, curTick) : checkpointDirBase; 295} 296 297void 298Checkpoint::setup(Tick when, Tick period) 299{ 300 new SerializeEvent(when, period); 301} 302 303class SerializeParamContext : public ParamContext 304{ 305 private: 306 SerializeEvent *event; 307 308 public: 309 SerializeParamContext(const string §ion); 310 ~SerializeParamContext(); 311 void checkParams(); 312}; 313 314SerializeParamContext serialParams("serialize"); 315 316Param<string> serialize_dir(&serialParams, "dir", 317 "dir to stick checkpoint in " 318 "(sprintf format with cycle #)"); 319 320Param<Counter> serialize_cycle(&serialParams, 321 "cycle", 322 "cycle to serialize", 323 0); 324 325Param<Counter> serialize_period(&serialParams, 326 "period", 327 "period to repeat serializations", 328 0); 329 330Param<int> serialize_count(&serialParams, "count", 331 "maximum number of checkpoints to drop"); 332 333SerializeParamContext::SerializeParamContext(const string §ion) 334 : ParamContext(section), event(NULL) 335{ } 336 337SerializeParamContext::~SerializeParamContext() 338{ 339} 340 341void 342SerializeParamContext::checkParams() 343{ 344 checkpointDirBase = simout.resolve(serialize_dir); 345 346 // guarantee that directory ends with a '/' 347 if (checkpointDirBase[checkpointDirBase.size() - 1] != '/') 348 checkpointDirBase += "/"; 349 350 if (serialize_cycle > 0) 351 Checkpoint::setup(serialize_cycle, serialize_period); 352 353 Serializable::maxCount = serialize_count; 354} 355 356void 357debug_serialize() 358{ 359 Serializable::serializeAll(); 360} 361 362void 363debug_serialize(Tick when) 364{ 365 new SerializeEvent(when, 0); 366} 367 368//////////////////////////////////////////////////////////////////////// 369// 370// SerializableClass member definitions 371// 372//////////////////////////////////////////////////////////////////////// 373 374// Map of class names to SerializableBuilder creation functions. 375// Need to make this a pointer so we can force initialization on the 376// first reference; otherwise, some SerializableClass constructors 377// may be invoked before the classMap constructor. 378map<string,SerializableClass::CreateFunc> *SerializableClass::classMap = 0; 379 380// SerializableClass constructor: add mapping to classMap 381SerializableClass::SerializableClass(const string &className, 382 CreateFunc createFunc) 383{ 384 if (classMap == NULL) 385 classMap = new map<string,SerializableClass::CreateFunc>(); 386 387 if ((*classMap)[className]) 388 { 389 cerr << "Error: simulation object class " << className << " redefined" 390 << endl; 391 fatal(""); 392 } 393 394 // add className --> createFunc to class map 395 (*classMap)[className] = createFunc; 396} 397 398 399// 400// 401Serializable * 402SerializableClass::createObject(Checkpoint *cp, 403 const std::string §ion) 404{ 405 string className; 406 407 if (!cp->find(section, "type", className)) { 408 fatal("Serializable::create: no 'type' entry in section '%s'.\n", 409 section); 410 } 411 412 CreateFunc createFunc = (*classMap)[className]; 413 414 if (createFunc == NULL) { 415 fatal("Serializable::create: no create function for class '%s'.\n", 416 className); 417 } 418 419 Serializable *object = createFunc(cp, section); 420 421 assert(object != NULL); 422 423 return object; 424} 425 426 427Serializable * 428Serializable::create(Checkpoint *cp, const std::string §ion) 429{ 430 Serializable *object = SerializableClass::createObject(cp, section); 431 object->unserialize(cp, section); 432 return object; 433} 434 435 436Checkpoint::Checkpoint(const std::string &cpt_dir, const std::string &path, 437 const ConfigNode *_configNode) 438 : db(new IniFile), basePath(path), configNode(_configNode), cptDir(cpt_dir) 439{ 440 string filename = cpt_dir + "/" + Checkpoint::baseFilename; 441 if (!db->load(filename)) { 442 fatal("Can't load checkpoint file '%s'\n", filename); 443 } 444} 445 446 447bool 448Checkpoint::find(const std::string §ion, const std::string &entry, 449 std::string &value) 450{ 451 return db->find(section, entry, value); 452} 453 454 455bool 456Checkpoint::findObj(const std::string §ion, const std::string &entry, 457 Serializable *&value) 458{ 459 string path; 460 461 if (!db->find(section, entry, path)) 462 return false; 463 464 if ((value = configNode->resolveSimObject(path)) != NULL) 465 return true; 466 467 if ((value = objMap[path]) != NULL) 468 return true; 469 470 return false; 471} 472 473 474bool 475Checkpoint::sectionExists(const std::string §ion) 476{ 477 return db->sectionExists(section); 478} 479