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