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