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