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