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