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