scons: Try to handle problems with gcc, lto and partial linking.
[gem5.git] / src / sim / serialize.cc
1 /*
2 * Copyright (c) 2015 ARM Limited
3 * All rights reserved
4 *
5 * The license below extends only to copyright in the software and shall
6 * not be construed as granting a license to any other intellectual
7 * property including but not limited to intellectual property relating
8 * to a hardware implementation of the functionality of the software
9 * licensed hereunder. You may use the software subject to the license
10 * terms below provided that you ensure that this notice is replicated
11 * unmodified and in its entirety in all distributions of the software,
12 * modified or unmodified, in source code or in binary form.
13 *
14 * Copyright (c) 2002-2005 The Regents of The University of Michigan
15 * Copyright (c) 2013 Advanced Micro Devices, Inc.
16 * Copyright (c) 2013 Mark D. Hill and David A. Wood
17 * All rights reserved.
18 *
19 * Redistribution and use in source and binary forms, with or without
20 * modification, are permitted provided that the following conditions are
21 * met: redistributions of source code must retain the above copyright
22 * notice, this list of conditions and the following disclaimer;
23 * redistributions in binary form must reproduce the above copyright
24 * notice, this list of conditions and the following disclaimer in the
25 * documentation and/or other materials provided with the distribution;
26 * neither the name of the copyright holders nor the names of its
27 * contributors may be used to endorse or promote products derived from
28 * this software without specific prior written permission.
29 *
30 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
31 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
32 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
33 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
34 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
35 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
36 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
37 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
38 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
39 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
40 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
41 *
42 * Authors: Nathan Binkert
43 * Erik Hallnor
44 * Steve Reinhardt
45 * Andreas Sandberg
46 */
47
48 #include "sim/serialize.hh"
49
50 #include <sys/stat.h>
51 #include <sys/time.h>
52 #include <sys/types.h>
53
54 #include <cerrno>
55 #include <fstream>
56 #include <list>
57 #include <string>
58 #include <vector>
59
60 #include "base/framebuffer.hh"
61 #include "base/inifile.hh"
62 #include "base/misc.hh"
63 #include "base/output.hh"
64 #include "base/str.hh"
65 #include "base/trace.hh"
66 #include "debug/Checkpoint.hh"
67 #include "sim/eventq.hh"
68 #include "sim/sim_events.hh"
69 #include "sim/sim_exit.hh"
70 #include "sim/sim_object.hh"
71
72 // For stat reset hack
73 #include "sim/stat_control.hh"
74
75 using namespace std;
76
77 //
78 // The base implementations use to_number for parsing and '<<' for
79 // displaying, suitable for integer types.
80 //
81 template <class T>
82 bool
83 parseParam(const string &s, T &value)
84 {
85 return to_number(s, value);
86 }
87
88 template <class T>
89 void
90 showParam(CheckpointOut &os, const T &value)
91 {
92 os << value;
93 }
94
95 //
96 // Template specializations:
97 // - char (8-bit integer)
98 // - floating-point types
99 // - bool
100 // - string
101 //
102
103 // Treat 8-bit ints (chars) as ints on output, not as chars
104 template <>
105 void
106 showParam(CheckpointOut &os, const char &value)
107 {
108 os << (int)value;
109 }
110
111
112 template <>
113 void
114 showParam(CheckpointOut &os, const signed char &value)
115 {
116 os << (int)value;
117 }
118
119
120 template <>
121 void
122 showParam(CheckpointOut &os, const unsigned char &value)
123 {
124 os << (unsigned int)value;
125 }
126
127
128 template <>
129 bool
130 parseParam(const string &s, float &value)
131 {
132 return to_number(s, value);
133 }
134
135 template <>
136 bool
137 parseParam(const string &s, double &value)
138 {
139 return to_number(s, value);
140 }
141
142 template <>
143 bool
144 parseParam(const string &s, bool &value)
145 {
146 return to_bool(s, value);
147 }
148
149 // Display bools as strings
150 template <>
151 void
152 showParam(CheckpointOut &os, const bool &value)
153 {
154 os << (value ? "true" : "false");
155 }
156
157
158 // String requires no processing to speak of
159 template <>
160 bool
161 parseParam(const string &s, string &value)
162 {
163 value = s;
164 return true;
165 }
166
167 int Serializable::ckptMaxCount = 0;
168 int Serializable::ckptCount = 0;
169 int Serializable::ckptPrevCount = -1;
170 std::stack<std::string> Serializable::path;
171
172 template <class T>
173 void
174 paramOut(CheckpointOut &os, const string &name, const T &param)
175 {
176 os << name << "=";
177 showParam(os, param);
178 os << "\n";
179 }
180
181 template <class T>
182 void
183 arrayParamOut(CheckpointOut &os, const string &name, const vector<T> &param)
184 {
185 typename vector<T>::size_type size = param.size();
186 os << name << "=";
187 if (size > 0)
188 showParam(os, param[0]);
189 for (typename vector<T>::size_type i = 1; i < size; ++i) {
190 os << " ";
191 showParam(os, param[i]);
192 }
193 os << "\n";
194 }
195
196 template <class T>
197 void
198 arrayParamOut(CheckpointOut &os, const string &name, const list<T> &param)
199 {
200 typename list<T>::const_iterator it = param.begin();
201
202 os << name << "=";
203 if (param.size() > 0)
204 showParam(os, *it);
205 it++;
206 while (it != param.end()) {
207 os << " ";
208 showParam(os, *it);
209 it++;
210 }
211 os << "\n";
212 }
213
214 template <class T>
215 void
216 arrayParamOut(CheckpointOut &os, const string &name, const set<T> &param)
217 {
218 typename set<T>::const_iterator it = param.begin();
219
220 os << name << "=";
221 if (param.size() > 0)
222 showParam(os, *it);
223 it++;
224 while (it != param.end()) {
225 os << " ";
226 showParam(os, *it);
227 it++;
228 }
229 os << "\n";
230 }
231
232 template <class T>
233 void
234 paramIn(CheckpointIn &cp, const string &name, T &param)
235 {
236 const string &section(Serializable::currentSection());
237 string str;
238 if (!cp.find(section, name, str) || !parseParam(str, param)) {
239 fatal("Can't unserialize '%s:%s'\n", section, name);
240 }
241 }
242
243 template <class T>
244 bool
245 optParamIn(CheckpointIn &cp, const string &name, T &param, bool warn)
246 {
247 const string &section(Serializable::currentSection());
248 string str;
249 if (!cp.find(section, name, str) || !parseParam(str, param)) {
250 if (warn)
251 warn("optional parameter %s:%s not present\n", section, name);
252 return false;
253 } else {
254 return true;
255 }
256 }
257
258 template <class T>
259 void
260 arrayParamOut(CheckpointOut &os, const string &name,
261 const T *param, unsigned size)
262 {
263 os << name << "=";
264 if (size > 0)
265 showParam(os, param[0]);
266 for (unsigned i = 1; i < size; ++i) {
267 os << " ";
268 showParam(os, param[i]);
269 }
270 os << "\n";
271 }
272
273
274 template <class T>
275 void
276 arrayParamIn(CheckpointIn &cp, const string &name, T *param, unsigned size)
277 {
278 const string &section(Serializable::currentSection());
279 string str;
280 if (!cp.find(section, name, str)) {
281 fatal("Can't unserialize '%s:%s'\n", section, name);
282 }
283
284 // code below stolen from VectorParam<T>::parse().
285 // it would be nice to unify these somehow...
286
287 vector<string> tokens;
288
289 tokenize(tokens, str, ' ');
290
291 // Need this if we were doing a vector
292 // value.resize(tokens.size());
293
294 if (tokens.size() != size) {
295 fatal("Array size mismatch on %s:%s'\n", section, name);
296 }
297
298 for (vector<string>::size_type i = 0; i < tokens.size(); i++) {
299 // need to parse into local variable to handle vector<bool>,
300 // for which operator[] returns a special reference class
301 // that's not the same as 'bool&', (since it's a packed
302 // vector)
303 T scalar_value;
304 if (!parseParam(tokens[i], scalar_value)) {
305 string err("could not parse \"");
306
307 err += str;
308 err += "\"";
309
310 fatal(err);
311 }
312
313 // assign parsed value to vector
314 param[i] = scalar_value;
315 }
316 }
317
318 template <class T>
319 void
320 arrayParamIn(CheckpointIn &cp, const string &name, vector<T> &param)
321 {
322 const string &section(Serializable::currentSection());
323 string str;
324 if (!cp.find(section, name, str)) {
325 fatal("Can't unserialize '%s:%s'\n", section, name);
326 }
327
328 // code below stolen from VectorParam<T>::parse().
329 // it would be nice to unify these somehow...
330
331 vector<string> tokens;
332
333 tokenize(tokens, str, ' ');
334
335 // Need this if we were doing a vector
336 // value.resize(tokens.size());
337
338 param.resize(tokens.size());
339
340 for (vector<string>::size_type i = 0; i < tokens.size(); i++) {
341 // need to parse into local variable to handle vector<bool>,
342 // for which operator[] returns a special reference class
343 // that's not the same as 'bool&', (since it's a packed
344 // vector)
345 T scalar_value;
346 if (!parseParam(tokens[i], scalar_value)) {
347 string err("could not parse \"");
348
349 err += str;
350 err += "\"";
351
352 fatal(err);
353 }
354
355 // assign parsed value to vector
356 param[i] = scalar_value;
357 }
358 }
359
360 template <class T>
361 void
362 arrayParamIn(CheckpointIn &cp, const string &name, list<T> &param)
363 {
364 const string &section(Serializable::currentSection());
365 string str;
366 if (!cp.find(section, name, str)) {
367 fatal("Can't unserialize '%s:%s'\n", section, name);
368 }
369 param.clear();
370
371 vector<string> tokens;
372 tokenize(tokens, str, ' ');
373
374 for (vector<string>::size_type i = 0; i < tokens.size(); i++) {
375 T scalar_value;
376 if (!parseParam(tokens[i], scalar_value)) {
377 string err("could not parse \"");
378
379 err += str;
380 err += "\"";
381
382 fatal(err);
383 }
384
385 // assign parsed value to vector
386 param.push_back(scalar_value);
387 }
388 }
389
390 template <class T>
391 void
392 arrayParamIn(CheckpointIn &cp, const string &name, set<T> &param)
393 {
394 const string &section(Serializable::currentSection());
395 string str;
396 if (!cp.find(section, name, str)) {
397 fatal("Can't unserialize '%s:%s'\n", section, name);
398 }
399 param.clear();
400
401 vector<string> tokens;
402 tokenize(tokens, str, ' ');
403
404 for (vector<string>::size_type i = 0; i < tokens.size(); i++) {
405 T scalar_value;
406 if (!parseParam(tokens[i], scalar_value)) {
407 string err("could not parse \"");
408
409 err += str;
410 err += "\"";
411
412 fatal(err);
413 }
414
415 // assign parsed value to vector
416 param.insert(scalar_value);
417 }
418 }
419
420
421 void
422 objParamIn(CheckpointIn &cp, const string &name, SimObject * &param)
423 {
424 const string &section(Serializable::currentSection());
425 if (!cp.findObj(section, name, param)) {
426 fatal("Can't unserialize '%s:%s'\n", section, name);
427 }
428 }
429
430
431 #define INSTANTIATE_PARAM_TEMPLATES(type) \
432 template void \
433 paramOut(CheckpointOut &os, const string &name, type const &param); \
434 template void \
435 paramIn(CheckpointIn &cp, const string &name, type & param); \
436 template bool \
437 optParamIn(CheckpointIn &cp, const string &name, type & param, \
438 bool warn); \
439 template void \
440 arrayParamOut(CheckpointOut &os, const string &name, \
441 type const *param, unsigned size); \
442 template void \
443 arrayParamIn(CheckpointIn &cp, const string &name, \
444 type *param, unsigned size); \
445 template void \
446 arrayParamOut(CheckpointOut &os, const string &name, \
447 const vector<type> &param); \
448 template void \
449 arrayParamIn(CheckpointIn &cp, const string &name, \
450 vector<type> &param); \
451 template void \
452 arrayParamOut(CheckpointOut &os, const string &name, \
453 const list<type> &param); \
454 template void \
455 arrayParamIn(CheckpointIn &cp, const string &name, \
456 list<type> &param);
457
458 INSTANTIATE_PARAM_TEMPLATES(char)
459 INSTANTIATE_PARAM_TEMPLATES(signed char)
460 INSTANTIATE_PARAM_TEMPLATES(unsigned char)
461 INSTANTIATE_PARAM_TEMPLATES(signed short)
462 INSTANTIATE_PARAM_TEMPLATES(unsigned short)
463 INSTANTIATE_PARAM_TEMPLATES(signed int)
464 INSTANTIATE_PARAM_TEMPLATES(unsigned int)
465 INSTANTIATE_PARAM_TEMPLATES(signed long)
466 INSTANTIATE_PARAM_TEMPLATES(unsigned long)
467 INSTANTIATE_PARAM_TEMPLATES(signed long long)
468 INSTANTIATE_PARAM_TEMPLATES(unsigned long long)
469 INSTANTIATE_PARAM_TEMPLATES(bool)
470 INSTANTIATE_PARAM_TEMPLATES(float)
471 INSTANTIATE_PARAM_TEMPLATES(double)
472 INSTANTIATE_PARAM_TEMPLATES(string)
473 INSTANTIATE_PARAM_TEMPLATES(Pixel)
474
475 // set is only used with strings and furthermore doesn't agree with Pixel
476 template void
477 arrayParamOut(CheckpointOut &, const string &, const set<string> &);
478 template void
479 arrayParamIn(CheckpointIn &, const string &, set<string> &);
480
481 /////////////////////////////
482
483 /// Container for serializing global variables (not associated with
484 /// any serialized object).
485 class Globals : public Serializable
486 {
487 public:
488 Globals()
489 : unserializedCurTick(0) {}
490
491 void serialize(CheckpointOut &cp) const override;
492 void unserialize(CheckpointIn &cp) override;
493
494 Tick unserializedCurTick;
495 };
496
497 /// The one and only instance of the Globals class.
498 Globals globals;
499
500 /// The version tags for this build of the simulator, to be stored in the
501 /// Globals section during serialization and compared upon unserialization.
502 extern std::set<std::string> version_tags;
503
504 void
505 Globals::serialize(CheckpointOut &cp) const
506 {
507 paramOut(cp, "curTick", curTick());
508 SERIALIZE_CONTAINER(version_tags);
509 }
510
511 void
512 Globals::unserialize(CheckpointIn &cp)
513 {
514 paramIn(cp, "curTick", unserializedCurTick);
515
516 const std::string &section(Serializable::currentSection());
517 std::string str;
518 if (!cp.find(section, "version_tags", str)) {
519 warn("**********************************************************\n");
520 warn("!!!! Checkpoint uses an old versioning scheme. !!!!\n");
521 warn("Run the checkpoint upgrader (util/cpt_upgrader.py) on your "
522 "checkpoint\n");
523 warn("**********************************************************\n");
524 return;
525 }
526
527 std::set<std::string> cpt_tags;
528 arrayParamIn(cp, "version_tags", cpt_tags); // UNSERIALIZE_CONTAINER
529
530 bool err = false;
531 for (const auto& t : version_tags) {
532 if (cpt_tags.find(t) == cpt_tags.end()) {
533 // checkpoint is missing tag that this binary has
534 if (!err) {
535 warn("*****************************************************\n");
536 warn("!!!! Checkpoint is missing the following version tags:\n");
537 err = true;
538 }
539 warn(" %s\n", t);
540 }
541 }
542 if (err) {
543 warn("You might experience some issues when restoring and should run "
544 "the checkpoint upgrader (util/cpt_upgrader.py) on your "
545 "checkpoint\n");
546 warn("**********************************************************\n");
547 }
548
549 err = false;
550 for (const auto& t : cpt_tags) {
551 if (version_tags.find(t) == version_tags.end()) {
552 // gem5 binary is missing tag that this checkpoint has
553 if (!err) {
554 warn("*****************************************************\n");
555 warn("!!!! gem5 is missing the following version tags:\n");
556 err = true;
557 }
558 warn(" %s\n", t);
559 }
560 }
561 if (err) {
562 warn("Running a checkpoint with incompatible version tags is not "
563 "supported. While it might work, you may experience incorrect "
564 "behavior or crashes.\n");
565 warn("**********************************************************\n");
566 }
567 }
568
569 Serializable::Serializable()
570 {
571 }
572
573 Serializable::~Serializable()
574 {
575 }
576
577 void
578 Serializable::serializeSection(CheckpointOut &cp, const char *name) const
579 {
580 Serializable::ScopedCheckpointSection sec(cp, name);
581 serialize(cp);
582 }
583
584 void
585 Serializable::unserializeSection(CheckpointIn &cp, const char *name)
586 {
587 Serializable::ScopedCheckpointSection sec(cp, name);
588 unserialize(cp);
589 }
590
591 void
592 Serializable::serializeAll(const string &cpt_dir)
593 {
594 string dir = CheckpointIn::setDir(cpt_dir);
595 if (mkdir(dir.c_str(), 0775) == -1 && errno != EEXIST)
596 fatal("couldn't mkdir %s\n", dir);
597
598 string cpt_file = dir + CheckpointIn::baseFilename;
599 ofstream outstream(cpt_file.c_str());
600 time_t t = time(NULL);
601 if (!outstream.is_open())
602 fatal("Unable to open file %s for writing\n", cpt_file.c_str());
603 outstream << "## checkpoint generated: " << ctime(&t);
604
605 globals.serializeSection(outstream, "Globals");
606
607 SimObject::serializeAll(outstream);
608 }
609
610 void
611 Serializable::unserializeGlobals(CheckpointIn &cp)
612 {
613 globals.unserializeSection(cp, "Globals");
614
615 for (uint32_t i = 0; i < numMainEventQueues; ++i)
616 mainEventQueue[i]->setCurTick(globals.unserializedCurTick);
617 }
618
619 Serializable::ScopedCheckpointSection::~ScopedCheckpointSection()
620 {
621 assert(!path.empty());
622 DPRINTF(Checkpoint, "Popping: %s\n", path.top());
623 path.pop();
624 }
625
626 void
627 Serializable::ScopedCheckpointSection::pushName(const char *obj_name)
628 {
629 if (path.empty()) {
630 path.push(obj_name);
631 } else {
632 path.push(csprintf("%s.%s", path.top(), obj_name));
633 }
634 DPRINTF(Checkpoint, "ScopedCheckpointSection::pushName: %s\n", obj_name);
635 }
636
637 void
638 Serializable::ScopedCheckpointSection::nameOut(CheckpointOut &cp)
639 {
640 DPRINTF(Checkpoint, "ScopedCheckpointSection::nameOut: %s\n",
641 Serializable::currentSection());
642 cp << "\n[" << Serializable::currentSection() << "]\n";
643 }
644
645 void
646 debug_serialize(const string &cpt_dir)
647 {
648 Serializable::serializeAll(cpt_dir);
649 }
650
651 const std::string &
652 Serializable::currentSection()
653 {
654 assert(!path.empty());
655
656 return path.top();
657 }
658
659 const char *CheckpointIn::baseFilename = "m5.cpt";
660
661 string CheckpointIn::currentDirectory;
662
663 string
664 CheckpointIn::setDir(const string &name)
665 {
666 // use csprintf to insert curTick() into directory name if it
667 // appears to have a format placeholder in it.
668 currentDirectory = (name.find("%") != string::npos) ?
669 csprintf(name, curTick()) : name;
670 if (currentDirectory[currentDirectory.size() - 1] != '/')
671 currentDirectory += "/";
672 return currentDirectory;
673 }
674
675 string
676 CheckpointIn::dir()
677 {
678 return currentDirectory;
679 }
680
681
682 CheckpointIn::CheckpointIn(const string &cpt_dir, SimObjectResolver &resolver)
683 : db(new IniFile), objNameResolver(resolver), cptDir(setDir(cpt_dir))
684 {
685 string filename = cptDir + "/" + CheckpointIn::baseFilename;
686 if (!db->load(filename)) {
687 fatal("Can't load checkpoint file '%s'\n", filename);
688 }
689 }
690
691 CheckpointIn::~CheckpointIn()
692 {
693 delete db;
694 }
695
696 bool
697 CheckpointIn::entryExists(const string &section, const string &entry)
698 {
699 return db->entryExists(section, entry);
700 }
701
702 bool
703 CheckpointIn::find(const string &section, const string &entry, string &value)
704 {
705 return db->find(section, entry, value);
706 }
707
708
709 bool
710 CheckpointIn::findObj(const string &section, const string &entry,
711 SimObject *&value)
712 {
713 string path;
714
715 if (!db->find(section, entry, path))
716 return false;
717
718 value = objNameResolver.resolveSimObject(path);
719 return true;
720 }
721
722
723 bool
724 CheckpointIn::sectionExists(const string &section)
725 {
726 return db->sectionExists(section);
727 }