More progress on checkpointing... we can now write out a checkpoint and read it back in,
[gem5.git] / sim / param.cc
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 <algorithm>
30 #include <list>
31 #include <string>
32 #include <vector>
33 #include <stdio.h> // for sscanf()
34
35 #include <assert.h>
36
37 #include "sim/param.hh"
38 #include "sim/sim_object.hh"
39 #include "base/inifile.hh"
40 #include "sim/configfile.hh"
41 #include "sim/config_node.hh"
42 #include "base/misc.hh"
43 #include "base/str.hh"
44 #include "base/trace.hh"
45
46 using namespace std;
47
48
49 ////////////////////////////////////////////////////////////////////////
50 //
51 // BaseParam member definitions
52 //
53 ////////////////////////////////////////////////////////////////////////
54
55 void
56 BaseParam::die(const string &err) const
57 {
58 context->printErrorProlog(cerr);
59 cerr << " parameter '" << name << "': "
60 << err << endl;
61 abort();
62 }
63
64
65 ////////////////////////////////////////////////////////////////////////
66 //
67 // Param<T> and VectorParam<T> member definitions
68 //
69 // We implement parsing & displaying values for various parameter
70 // types T using a set of overloaded functions:
71 //
72 // - parseParam(string s, T &value) parses s into value
73 // - showParam(ostream &os, T &value) displays value on os
74 //
75 // By making these independent functions, we can reuse the same code
76 // for type T in both Param<T> and VectorParam<T>.
77 //
78 // For enum types, the parseParam function requires additional
79 // arguments, in which case we must specialize the Param<T>::parse and
80 // VectorParam<T>::parse calls as well.
81 //
82 // Type-specific instances come first, followed by more generic
83 // templated versions and their instantiations.
84 //
85 ////////////////////////////////////////////////////////////////////////
86
87 //
88 // The base implementations use to_number for parsing and '<<' for
89 // displaying, suitable for integer types.
90 //
91 template <class T>
92 bool
93 parseParam(const string &s, T &value)
94 {
95 return to_number(s, value);
96 }
97
98 template <class T>
99 void
100 showParam(ostream &os, const T &value)
101 {
102 os << value;
103 }
104
105 //
106 // Template specializations:
107 // - char (8-bit integer)
108 // - floating-point types
109 // - bool
110 // - string
111 //
112
113 // Treat 8-bit ints (chars) as ints on output, not as chars
114 template <>
115 void
116 showParam(ostream &os, const char &value)
117 {
118 os << (int)value;
119 }
120
121
122 template <>
123 void
124 showParam(ostream &os, const unsigned char &value)
125 {
126 os << (unsigned int)value;
127 }
128
129
130 // Use sscanf() for FP types as to_number() only handles integers
131 template <>
132 bool
133 parseParam(const string &s, float &value)
134 {
135 return (sscanf(s.c_str(), "%f", &value) == 1);
136 }
137
138 template <>
139 bool
140 parseParam(const string &s, double &value)
141 {
142 return (sscanf(s.c_str(), "%lf", &value) == 1);
143 }
144
145 // Be flexible about what we take for bool
146 template <>
147 bool
148 parseParam(const string &s, bool &value)
149 {
150 const string &lower = to_lower(s);
151
152 if (lower == "true" || lower == "t" || lower == "yes" || lower == "y") {
153 value = true;
154 return true;
155 }
156
157 if (lower == "false" || lower == "f" || lower == "no" || lower == "n") {
158 value = false;
159 return true;
160 }
161
162 return false;
163 }
164
165 // Display bools as strings
166 template <>
167 void
168 showParam(ostream &os, const bool &value)
169 {
170 os << (value ? "true" : "false");
171 }
172
173
174 // String requires no processing to speak of
175 template <>
176 bool
177 parseParam(const string &s, string &value)
178 {
179 value = s;
180 return true;
181 }
182
183 //
184 // End of parseParam/showParam definitions. Now we move on to
185 // incorporate them into the Param/VectorParam parse() and showValue()
186 // methods.
187 //
188
189 // These definitions for Param<T>::parse and VectorParam<T>::parse
190 // work for any type for which parseParam() takes only two arguments
191 // (i.e., all the fundamental types like int, bool, etc.), thanks to
192 // overloading.
193 template <class T>
194 void
195 Param<T>::parse(const string &s)
196 {
197 if (parseParam(s, value)) {
198 wasSet = true;
199 }
200 else {
201 string err("could not parse \"");
202
203 err += s;
204 err += "\"";
205
206 die(err);
207 }
208 }
209
210 template <class T>
211 void
212 VectorParam<T>::parse(const string &s)
213 {
214 vector<string> tokens;
215
216 tokenize(tokens, s, ' ');
217
218 value.resize(tokens.size());
219
220 for (int i = 0; i < tokens.size(); i++) {
221 // need to parse into local variable to handle vector<bool>,
222 // for which operator[] returns a special reference class
223 // that's not the same as 'bool&', (since it's a packed
224 // vector)
225 T scalar_value;
226 if (!parseParam(tokens[i], scalar_value)) {
227 string err("could not parse \"");
228
229 err += s;
230 err += "\"";
231
232 die(err);
233 }
234
235 // assign parsed value to vector
236 value[i] = scalar_value;
237 }
238
239 wasSet = true;
240 }
241
242 // These definitions for Param<T>::showValue() and
243 // VectorParam<T>::showValue() work for any type where showParam()
244 // takes only two arguments (i.e., everything but the SimpleEnum and
245 // MappedEnum classes).
246 template <class T>
247 void
248 Param<T>::showValue(ostream &os) const
249 {
250 showParam(os, value);
251 }
252
253 template <class T>
254 void
255 VectorParam<T>::showValue(ostream &os) const
256 {
257 for (int i = 0; i < value.size(); i++) {
258 if (i != 0) {
259 os << " ";
260 }
261 showParam(os, value[i]);
262 }
263 }
264
265
266 #ifdef INSURE_BUILD
267 #define INSTANTIATE_PARAM_TEMPLATES(type, typestr) \
268 void Param<type>::showType(ostream &os) const { os << typestr; } \
269 void VectorParam<type>::showType(ostream &os) const { \
270 os << "vector of " << typestr; \
271 } \
272 template Param<type>; \
273 template VectorParam<type>;
274
275 #else
276 // instantiate all four methods (parse/show, scalar/vector) for basic
277 // types that can use the above templates
278 #define INSTANTIATE_PARAM_TEMPLATES(type, typestr) \
279 template bool parseParam<type>(const string &s, type &value); \
280 template void showParam<type>(ostream &os, const type &value); \
281 template void Param<type>::parse(const string &); \
282 template void VectorParam<type>::parse(const string &); \
283 template void Param<type>::showValue(ostream &) const; \
284 template void VectorParam<type>::showValue(ostream &) const; \
285 void Param<type>::showType(ostream &os) const { os << typestr; } \
286 void VectorParam<type>::showType(ostream &os) const { \
287 os << "vector of " << typestr; \
288 }
289 #endif
290
291 INSTANTIATE_PARAM_TEMPLATES(unsigned long long, "ull")
292 INSTANTIATE_PARAM_TEMPLATES(signed long long, "sll")
293 INSTANTIATE_PARAM_TEMPLATES(unsigned long, "uns long")
294 INSTANTIATE_PARAM_TEMPLATES(signed long, "long")
295 INSTANTIATE_PARAM_TEMPLATES(unsigned int, "uns")
296 INSTANTIATE_PARAM_TEMPLATES(signed int, "int")
297 INSTANTIATE_PARAM_TEMPLATES(unsigned short, "uns short")
298 INSTANTIATE_PARAM_TEMPLATES(signed short, "short")
299 INSTANTIATE_PARAM_TEMPLATES(unsigned char, "uns char")
300 INSTANTIATE_PARAM_TEMPLATES(signed char, "char")
301
302 INSTANTIATE_PARAM_TEMPLATES(float, "float")
303 INSTANTIATE_PARAM_TEMPLATES(double, "double")
304
305 INSTANTIATE_PARAM_TEMPLATES(bool, "bool")
306 INSTANTIATE_PARAM_TEMPLATES(string, "string")
307
308 #undef INSTANTIATE_PARAM_TEMPLATES
309
310 //
311 // SimpleEnumParam & MappedEnumParam must specialize their parse(),
312 // showValue(), and showType() methods.
313 //
314
315 //
316 // SimpleEnumParam & SimpleEnumVectorParam
317 //
318 bool
319 parseEnumParam(const char *const *map, const int num_values,
320 const string &s, int &value)
321 {
322 for (int i = 0; i < num_values; ++i) {
323 if (s == map[i]) {
324 value = i;
325 return true;
326 }
327 }
328
329 return false;
330 }
331
332 void
333 showEnumParam(ostream &os,
334 const char *const *map, const int num_values,
335 int value)
336 {
337 assert(0 <= value && value < num_values);
338 os << map[value];
339 }
340
341 void
342 showEnumType(ostream &os,
343 const char *const *map, const int num_values)
344 {
345 os << "{" << map[0];
346 for (int i = 1; i < num_values; ++i)
347 os << "," << map[i];
348
349 os << "}";
350 }
351
352
353 //
354 // MappedEnumParam & MappedEnumVectorParam
355 //
356 bool
357 parseEnumParam(const EnumParamMap *map, const int num_values,
358 const string &s, int &value)
359 {
360 for (int i = 0; i < num_values; ++i) {
361 if (s == map[i].name) {
362 value = map[i].value;
363 return true;
364 }
365 }
366
367 return false;
368 }
369
370 void
371 showEnumParam(ostream &os,
372 const EnumParamMap *map, const int num_values,
373 int value)
374 {
375 for (int i = 0; i < num_values; ++i) {
376 if (value == map[i].value) {
377 os << map[i].name;
378 return;
379 }
380 }
381
382 // if we can't find a reverse mapping just print the int value
383 os << value;
384 }
385
386 void
387 showEnumType(ostream &os,
388 const EnumParamMap *map, const int num_values)
389 {
390 os << "{" << map[0].name;
391 for (int i = 1; i < num_values; ++i)
392 os << "," << map[i].name;
393
394 os << "}";
395 }
396
397
398 template <class Map>
399 void
400 EnumParam<Map>::parse(const string &s)
401 {
402 if (parseEnumParam(map, num_values, s, value)) {
403 wasSet = true;
404 } else {
405 string err("no match for enum string \"");
406
407 err += s;
408 err += "\"";
409
410 die(err);
411 }
412 }
413
414 template <class Map>
415 void
416 EnumVectorParam<Map>::parse(const string &s)
417 {
418 vector<string> tokens;
419
420 tokenize(tokens, s, ' ');
421
422 value.resize(tokens.size());
423
424 for (int i = 0; i < tokens.size(); i++) {
425 if (!parseEnumParam(map, num_values, tokens[i], value[i])) {
426 string err("no match for enum string \"");
427
428 err += s;
429 err += "\"";
430
431 die(err);
432 }
433 }
434
435 wasSet = true;
436 }
437
438 template <class Map>
439 void
440 EnumParam<Map>::showValue(ostream &os) const
441 {
442 showEnumParam(os, map, num_values, value);
443 }
444
445 template <class Map>
446 void
447 EnumVectorParam<Map>::showValue(ostream &os) const
448 {
449 for (int i = 0; i < value.size(); i++) {
450 if (i != 0) {
451 os << " ";
452 }
453 showEnumParam(os, map, num_values, value[i]);
454 }
455 }
456
457 template <class Map>
458 void
459 EnumParam<Map>::showType(ostream &os) const
460 {
461 showEnumType(os, map, num_values);
462 }
463
464 template <class Map>
465 void
466 EnumVectorParam<Map>::showType(ostream &os) const
467 {
468 os << "vector of";
469 showEnumType(os, map, num_values);
470 }
471
472 template EnumParam<const char *>;
473 template EnumVectorParam<const char *>;
474
475 template EnumParam<EnumParamMap>;
476 template EnumVectorParam<EnumParamMap>;
477
478 ////////////////////////////////////////////////////////////////////////
479 //
480 // SimObjectBaseParam methods
481 //
482 ////////////////////////////////////////////////////////////////////////
483
484 bool
485 parseSimObjectParam(ParamContext *context, const string &s, SimObject *&value)
486 {
487 SimObject *obj;
488
489 if (to_lower(s) == "null") {
490 // explicitly set to null by user; assume that's OK
491 obj = NULL;
492 }
493 else {
494 obj = context->resolveSimObject(s);
495
496 if (obj == NULL)
497 return false;
498 }
499
500 value = obj;
501 return true;
502 }
503
504
505 void
506 SimObjectBaseParam::showValue(ostream &os, SimObject *value) const
507 {
508 os << (value ? value->name() : "null");
509 }
510
511 void
512 SimObjectBaseParam::parse(const string &s, SimObject *&value)
513 {
514 if (parseSimObjectParam(context, s, value)) {
515 wasSet = true;
516 }
517 else {
518 string err("could not resolve object name \"");
519
520 err += s;
521 err += "\"";
522
523 die(err);
524 }
525 }
526
527 void
528 SimObjectBaseParam::parse(const string &s, vector<SimObject *>&value)
529 {
530 vector<string> tokens;
531
532 tokenize(tokens, s, ' ');
533
534 value.resize(tokens.size());
535
536 for (int i = 0; i < tokens.size(); i++) {
537 if (!parseSimObjectParam(context, tokens[i], value[i])) {
538 string err("could not resolve object name \"");
539
540 err += s;
541 err += "\"";
542
543 die(err);
544 }
545 }
546
547 wasSet = true;
548 }
549
550 ////////////////////////////////////////////////////////////////////////
551 //
552 // ParamContext member definitions
553 //
554 ////////////////////////////////////////////////////////////////////////
555
556 list<ParamContext *> *ParamContext::ctxList = NULL;
557
558 ParamContext::ParamContext(const string &_iniSection, bool noAutoParse)
559 : iniFilePtr(NULL), // initialized on call to parseParams()
560 iniSection(_iniSection), paramList(NULL)
561 {
562 if (!noAutoParse) {
563 if (ctxList == NULL)
564 ctxList = new list<ParamContext *>();
565
566 (*ctxList).push_back(this);
567 }
568 }
569
570
571 void
572 ParamContext::addParam(BaseParam *param)
573 {
574 getParamList()->push_back(param);
575 }
576
577
578 void
579 ParamContext::parseParams(IniFile &iniFile)
580 {
581 iniFilePtr = &iniFile; // set object member
582
583 ParamList::iterator i;
584
585 for (i = getParamList()->begin(); i != getParamList()->end(); ++i) {
586 string string_value;
587
588 if (iniFile.findDefault(iniSection, (*i)->name, string_value)) {
589 (*i)->parse(string_value);
590 }
591 }
592 }
593
594
595 // Check parameter values for validity & consistency. Default
596 // implementation is no-op; derive subclass & override to add
597 // actual functionality here.
598 void
599 ParamContext::checkParams()
600 {
601 // nada
602 }
603
604
605 // Clean up context-related objects at end of execution. Default
606 // implementation is no-op; derive subclass & override to add actual
607 // functionality here.
608 void
609 ParamContext::cleanup()
610 {
611 // nada
612 }
613
614
615 void
616 ParamContext::describeParams(ostream &os)
617 {
618 ParamList::iterator i;
619
620 for (i = getParamList()->begin(); i != getParamList()->end(); ++i) {
621 BaseParam *p = *i;
622
623 os << p->name << " (";
624 p->showType(os);
625 os << "): " << p->description << "\n";
626 }
627 }
628
629
630
631 void
632 ParamContext::showParams(ostream &os)
633 {
634 ParamList::iterator i;
635
636 for (i = getParamList()->begin(); i != getParamList()->end(); ++i) {
637 BaseParam *p = *i;
638
639 if (p->isValid()) {
640 os << p->name << "=";
641 p->showValue(os);
642 os << endl;
643 }
644 else {
645 os << "// "<< p->name << " not specified" << endl;
646 }
647 }
648 }
649
650
651 void
652 ParamContext::printErrorProlog(ostream &os)
653 {
654 os << "Parameter error in section [" << iniSection << "]: " << endl;
655 }
656
657 //
658 // Resolve an object name to a SimObject pointer. The object will be
659 // created as a side-effect if necessary. If the name contains a
660 // colon (e.g., "iq:IQ"), then the object is local (invisible to
661 // outside this context). If there is no colon, the name needs to be
662 // resolved through the configuration hierarchy (only possible for
663 // SimObjectBuilder objects, which return non-NULL for configNode()).
664 //
665 SimObject *
666 ParamContext::resolveSimObject(const string &_name)
667 {
668 // look for a colon
669 string::size_type i = _name.find(':');
670 string name = _name;
671 if (i != string::npos) {
672 // colon found: local object
673 // add as child to current node and create it
674 name = _name.substr(0, i);
675 string objConfigClassName = _name.substr(i + 1);
676 getConfigNode()->addChild(name, objConfigClassName);
677 }
678 ConfigNode *n = getConfigNode();
679 return n ? n->resolveSimObject(name) : NULL;
680 }
681
682
683 //
684 // static method: call parseParams() on all registered contexts
685 //
686 void
687 ParamContext::parseAllContexts(IniFile &iniFile)
688 {
689 list<ParamContext *>::iterator iter;
690
691 for (iter = ctxList->begin(); iter != ctxList->end(); ++iter) {
692 ParamContext *pc = *iter;
693
694 pc->parseParams(iniFile);
695 }
696 }
697
698
699 //
700 // static method: call checkParams() on all registered contexts
701 //
702 void
703 ParamContext::checkAllContexts()
704 {
705 list<ParamContext *>::iterator iter;
706
707 for (iter = ctxList->begin(); iter != ctxList->end(); ++iter) {
708 ParamContext *pc = *iter;
709
710 pc->checkParams();
711 }
712 }
713
714
715 //
716 // static method: call showParams() on all registered contexts
717 //
718 void
719 ParamContext::showAllContexts(ostream &os)
720 {
721 list<ParamContext *>::iterator iter;
722
723 for (iter = ctxList->begin(); iter != ctxList->end(); ++iter) {
724 ParamContext *pc = *iter;
725
726 os << "[" << pc->iniSection << "]" << endl;
727 pc->showParams(os);
728 os << endl;
729 }
730 }
731
732
733 //
734 // static method: call cleanup() on all registered contexts
735 //
736 void
737 ParamContext::cleanupAllContexts()
738 {
739 list<ParamContext *>::iterator iter;
740
741 for (iter = ctxList->begin(); iter != ctxList->end(); ++iter) {
742 ParamContext *pc = *iter;
743
744 pc->cleanup();
745 }
746 }
747
748
749 //
750 // static method: call describeParams() on all registered contexts
751 //
752 void
753 ParamContext::describeAllContexts(ostream &os)
754 {
755 list<ParamContext *>::iterator iter;
756
757 for (iter = ctxList->begin(); iter != ctxList->end(); ++iter) {
758 ParamContext *pc = *iter;
759
760 os << "[" << pc->iniSection << "]\n";
761 pc->describeParams(os);
762 os << endl;
763 }
764 }