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