serialize.cc revision 237
13560SN/A/* 23560SN/A * Copyright (c) 2003 The Regents of The University of Michigan 33560SN/A * All rights reserved. 43560SN/A * 53560SN/A * Redistribution and use in source and binary forms, with or without 63560SN/A * modification, are permitted provided that the following conditions are 73560SN/A * met: redistributions of source code must retain the above copyright 83560SN/A * notice, this list of conditions and the following disclaimer; 93560SN/A * redistributions in binary form must reproduce the above copyright 103560SN/A * notice, this list of conditions and the following disclaimer in the 113560SN/A * documentation and/or other materials provided with the distribution; 123560SN/A * neither the name of the copyright holders nor the names of its 133560SN/A * contributors may be used to endorse or promote products derived from 143560SN/A * this software without specific prior written permission. 153560SN/A * 163560SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 173560SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 183560SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 193560SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 203560SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 213560SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 223560SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 233560SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 243560SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 253560SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 263560SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 273560SN/A */ 283560SN/A 293560SN/A#include <sys/time.h> 303560SN/A 313560SN/A#include <fstream> 3211793Sbrandon.potter@amd.com#include <list> 3311793Sbrandon.potter@amd.com#include <string> 343560SN/A#include <vector> 353560SN/A 363560SN/A#include "base/misc.hh" 373560SN/A#include "base/str.hh" 3811793Sbrandon.potter@amd.com 399329Sdam.sunwoo@arm.com#include "sim/eventq.hh" 403560SN/A#include "sim/param.hh" 413560SN/A#include "sim/serialize.hh" 428232Snate@binkert.org#include "base/inifile.hh" 433560SN/A#include "sim/sim_events.hh" 443560SN/A#include "sim/sim_object.hh" 453560SN/A#include "base/trace.hh" 463560SN/A#include "sim/config_node.hh" 473560SN/A 483560SN/Ausing namespace std; 493560SN/A 503560SN/ASerializer *Serializeable::serializer = NULL; 513560SN/A 523560SN/ASerializeable::Serializeable(const string &n) 5312181Sgabeblack@google.com : objName(n), serialized(false) 5412181Sgabeblack@google.com{ } 5512182Sgabeblack@google.com 5612182Sgabeblack@google.comSerializeable::~Serializeable() 573560SN/A{ } 583560SN/A 593560SN/Avoid 603560SN/ASerializeable::mark() 613560SN/A{ 623560SN/A if (!serialized) 633560SN/A serializer->add_object(this); 643560SN/A 653560SN/A serialized = true; 663560SN/A} 673560SN/A 683560SN/Avoid 693560SN/ASerializeable::nameOut(ostream &os) 703560SN/A{ 713560SN/A os << "\n[" << name() << "]\n"; 723560SN/A} 733560SN/A 743560SN/Avoid 753560SN/ASerializeable::nameOut(ostream &os, const string &_name) 763560SN/A{ 773560SN/A os << "\n[" << _name << "]\n"; 783560SN/A} 793560SN/A 803560SN/Atemplate <class T> 813560SN/Avoid 823560SN/AparamOut(ostream &os, const std::string &name, const T& param) 833560SN/A{ 843560SN/A os << name << "="; 853560SN/A showParam(os, param); 863560SN/A os << "\n"; 873560SN/A} 883560SN/A 893560SN/A 903560SN/Atemplate <class T> 913560SN/Avoid 923560SN/AparamIn(Checkpoint *cp, const std::string §ion, 933560SN/A const std::string &name, T& param) 943560SN/A{ 953560SN/A std::string str; 963560SN/A if (!cp->find(section, name, str) || !parseParam(str, param)) { 973560SN/A fatal("Can't unserialize '%s:%s'\n", section, name); 983560SN/A } 993560SN/A} 1003560SN/A 1013560SN/A 1023560SN/Atemplate <class T> 1033560SN/Avoid 1043560SN/AarrayParamOut(ostream &os, const std::string &name, 1053560SN/A const T *param, int size) 1063560SN/A{ 1073560SN/A os << name << "="; 1083560SN/A if (size > 0) 1093560SN/A showParam(os, param[0]); 1103560SN/A for (int i = 1; i < size; ++i) { 1113560SN/A os << " "; 1123560SN/A showParam(os, param[i]); 1133560SN/A } 1143560SN/A os << "\n"; 1153560SN/A} 1163560SN/A 1173560SN/A 1183560SN/Atemplate <class T> 1193560SN/Avoid 1203560SN/AarrayParamIn(Checkpoint *cp, const std::string §ion, 1213560SN/A const std::string &name, T *param, int size) 1223560SN/A{ 1233560SN/A std::string str; 12412182Sgabeblack@google.com if (!cp->find(section, name, str)) { 12512182Sgabeblack@google.com fatal("Can't unserialize '%s:%s'\n", section, name); 12612182Sgabeblack@google.com } 12712182Sgabeblack@google.com 12812182Sgabeblack@google.com // code below stolen from VectorParam<T>::parse(). 12912182Sgabeblack@google.com // it would be nice to unify these somehow... 13012182Sgabeblack@google.com 13112182Sgabeblack@google.com vector<string> tokens; 13212182Sgabeblack@google.com 13312182Sgabeblack@google.com tokenize(tokens, str, ' '); 13412182Sgabeblack@google.com 13512182Sgabeblack@google.com // Need this if we were doing a vector 13612182Sgabeblack@google.com // value.resize(tokens.size()); 13712182Sgabeblack@google.com 13812182Sgabeblack@google.com if (tokens.size() != size) { 13912182Sgabeblack@google.com fatal("Array size mismatch on %s:%s'\n", section, name); 14012182Sgabeblack@google.com } 14112182Sgabeblack@google.com 14212182Sgabeblack@google.com for (int i = 0; i < tokens.size(); i++) { 14312182Sgabeblack@google.com // need to parse into local variable to handle vector<bool>, 14412182Sgabeblack@google.com // for which operator[] returns a special reference class 14512182Sgabeblack@google.com // that's not the same as 'bool&', (since it's a packed 14612182Sgabeblack@google.com // vector) 14712182Sgabeblack@google.com T scalar_value; 14812182Sgabeblack@google.com if (!parseParam(tokens[i], scalar_value)) { 14912182Sgabeblack@google.com string err("could not parse \""); 15012182Sgabeblack@google.com 15112182Sgabeblack@google.com err += str; 15212182Sgabeblack@google.com err += "\""; 1533560SN/A 1543560SN/A fatal(err); 1553560SN/A } 1563560SN/A 1573560SN/A // assign parsed value to vector 1583560SN/A param[i] = scalar_value; 1593560SN/A } 1603560SN/A} 1613560SN/A 1623560SN/A 1633560SN/Avoid 1643560SN/AobjParamIn(Checkpoint *cp, const std::string §ion, 1653560SN/A const std::string &name, Serializeable * ¶m) 1663560SN/A{ 1673560SN/A if (!cp->findObj(section, name, param)) { 1683560SN/A fatal("Can't unserialize '%s:%s'\n", section, name); 1693560SN/A } 1703560SN/A} 1713560SN/A 1725191Ssaidi@eecs.umich.edu 1735191Ssaidi@eecs.umich.edu#define INSTANTIATE_PARAM_TEMPLATES(type) \ 1745191Ssaidi@eecs.umich.edutemplate void \ 1753560SN/AparamOut(ostream &os, const std::string &name, type const ¶m); \ 1763560SN/Atemplate void \ 1777823Ssteve.reinhardt@amd.comparamIn(Checkpoint *cp, const std::string §ion, \ 1783560SN/A const std::string &name, type & param); \ 1797823Ssteve.reinhardt@amd.comtemplate void \ 1803560SN/AarrayParamOut(ostream &os, const std::string &name, \ 1813560SN/A type const *param, int size); \ 1823560SN/Atemplate void \ 1833560SN/AarrayParamIn(Checkpoint *cp, const std::string §ion, \ 1843560SN/A const std::string &name, type *param, int size); 1853560SN/A 1865568Snate@binkert.org 1873560SN/AINSTANTIATE_PARAM_TEMPLATES(int8_t) 1883560SN/AINSTANTIATE_PARAM_TEMPLATES(uint8_t) 1893560SN/AINSTANTIATE_PARAM_TEMPLATES(int16_t) 1903560SN/AINSTANTIATE_PARAM_TEMPLATES(uint16_t) 1913560SN/AINSTANTIATE_PARAM_TEMPLATES(int32_t) 1923560SN/AINSTANTIATE_PARAM_TEMPLATES(uint32_t) 1933560SN/AINSTANTIATE_PARAM_TEMPLATES(int64_t) 1943560SN/AINSTANTIATE_PARAM_TEMPLATES(uint64_t) 1953560SN/AINSTANTIATE_PARAM_TEMPLATES(bool) 1963560SN/AINSTANTIATE_PARAM_TEMPLATES(string) 1973560SN/A 1983560SN/A 1993560SN/A#if 0 2003560SN/A// unneeded? 2015191Ssaidi@eecs.umich.eduvoid 2025191Ssaidi@eecs.umich.eduSerializeable::childOut(const string &name, Serializeable *child) 2035191Ssaidi@eecs.umich.edu{ 2045191Ssaidi@eecs.umich.edu child->mark(); 2053560SN/A if (child->name() == "") 2063560SN/A panic("child is unnamed"); 2073560SN/A 2083560SN/A out() << name << "=" << child->name() << "\n"; 2093560SN/A} 2103560SN/A#endif 2113560SN/A 2123560SN/Avoid 2133560SN/ASerializeable::setName(const string &name) 2143560SN/A{ 2153560SN/A if (objName != "") { 2163560SN/A cprintf("Renaming object '%s' to '%s'.\n", objName, name); 21712182Sgabeblack@google.com } 21812182Sgabeblack@google.com 21912182Sgabeblack@google.com objName = name; 22012182Sgabeblack@google.com} 22112182Sgabeblack@google.com 22212182Sgabeblack@google.comSerializer::Serializer() 22312182Sgabeblack@google.com{ } 22412182Sgabeblack@google.com 22512182Sgabeblack@google.comSerializer::~Serializer() 22612182Sgabeblack@google.com{ } 22712182Sgabeblack@google.com 22812182Sgabeblack@google.comostream & 22912182Sgabeblack@google.comSerializer::out() const 23012182Sgabeblack@google.com{ 23112182Sgabeblack@google.com if (!output) 23212182Sgabeblack@google.com panic("must set output before serializing"); 23310905Sandreas.sandberg@arm.com 2343560SN/A return *output; 23510905Sandreas.sandberg@arm.com} 2363560SN/A 2373560SN/Avoid 2383560SN/ASerializer::add_object(Serializeable *obj) 2393560SN/A{ 24012182Sgabeblack@google.com objects.push_back(obj); 24112182Sgabeblack@google.com} 2423560SN/A 2433560SN/Avoid 2443560SN/ASerializer::add_objects() 24510905Sandreas.sandberg@arm.com{ 2463560SN/A mainEventQueue.mark(); 24710905Sandreas.sandberg@arm.com 2483560SN/A SimObject::SimObjectList::iterator i = SimObject::simObjectList.begin(); 2493560SN/A SimObject::SimObjectList::iterator end = SimObject::simObjectList.end(); 2503560SN/A 2513560SN/A while (i != end) { 2523560SN/A (*i)->mark(); 25312182Sgabeblack@google.com ++i; 25412182Sgabeblack@google.com } 2553560SN/A} 2563560SN/A 2575568Snate@binkert.orgvoid 2585568Snate@binkert.orgSerializer::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