diff options
Diffstat (limited to 'src/base')
-rw-r--r-- | src/base/SConscript | 83 | ||||
-rw-r--r-- | src/base/annotate.cc | 2 | ||||
-rw-r--r-- | src/base/bigint.cc | 47 | ||||
-rw-r--r-- | src/base/bigint.hh | 97 | ||||
-rw-r--r-- | src/base/bitfield.hh | 294 | ||||
-rw-r--r-- | src/base/cprintf.cc | 427 | ||||
-rw-r--r-- | src/base/cprintf.hh | 205 | ||||
-rw-r--r-- | src/base/cprintf_formats.hh | 4 | ||||
-rw-r--r-- | src/base/loader/elf_object.cc | 15 | ||||
-rw-r--r-- | src/base/loader/object_file.hh | 6 | ||||
-rw-r--r-- | src/base/misc.cc | 90 | ||||
-rw-r--r-- | src/base/misc.hh | 71 | ||||
-rw-r--r-- | src/base/pollevent.cc | 2 | ||||
-rw-r--r-- | src/base/pollevent.hh | 2 | ||||
-rw-r--r-- | src/base/random.cc | 48 | ||||
-rw-r--r-- | src/base/random.hh | 18 | ||||
-rw-r--r-- | src/base/statistics.hh | 19 | ||||
-rw-r--r-- | src/base/stats/events.cc | 131 | ||||
-rw-r--r-- | src/base/stats/events.hh | 10 | ||||
-rw-r--r-- | src/base/stats/mysql.cc | 253 | ||||
-rw-r--r-- | src/base/stats/mysql.hh | 60 | ||||
-rw-r--r-- | src/base/stats/output.cc | 70 | ||||
-rw-r--r-- | src/base/stats/output.hh | 1 | ||||
-rw-r--r-- | src/base/stats/text.cc | 22 | ||||
-rw-r--r-- | src/base/stats/text.hh | 6 | ||||
-rw-r--r-- | src/base/trace.cc | 283 | ||||
-rw-r--r-- | src/base/trace.hh | 175 | ||||
-rw-r--r-- | src/base/traceflags.py | 304 | ||||
-rw-r--r-- | src/base/varargs.hh | 292 |
29 files changed, 1903 insertions, 1134 deletions
diff --git a/src/base/SConscript b/src/base/SConscript new file mode 100644 index 000000000..788aa3e6f --- /dev/null +++ b/src/base/SConscript @@ -0,0 +1,83 @@ +# -*- mode:python -*- + +# Copyright (c) 2006 The Regents of The University of Michigan +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer; +# redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution; +# neither the name of the copyright holders nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# Authors: Nathan Binkert + +Import('*') + +# base/traceflags.{cc,hh} are generated from base/traceflags.py. +# $TARGET.base will expand to "<build-dir>/base/traceflags". +env.Command(['traceflags.hh', 'traceflags.cc'], 'traceflags.py', + 'python $SOURCE $TARGET.base') + +Source('annotate.cc') +Source('bigint.cc') +Source('circlebuf.cc') +Source('cprintf.cc') +Source('crc.cc') +Source('fast_alloc.cc') +Source('fifo_buffer.cc') +Source('hostinfo.cc') +Source('hybrid_pred.cc') +Source('inet.cc') +Source('inifile.cc') +Source('intmath.cc') +Source('match.cc') +Source('misc.cc') +Source('output.cc') +Source('pollevent.cc') +Source('random.cc') +Source('range.cc') +Source('remote_gdb.cc') +Source('sat_counter.cc') +Source('socket.cc') +Source('statistics.cc') +Source('str.cc') +Source('time.cc') +Source('trace.cc') +Source('traceflags.cc') +Source('userinfo.cc') + +Source('compression/lzss_compression.cc') + +Source('loader/aout_object.cc') +Source('loader/ecoff_object.cc') +Source('loader/elf_object.cc') +Source('loader/object_file.cc') +Source('loader/raw_object.cc') +Source('loader/symtab.cc') + +Source('stats/events.cc') +Source('stats/output.cc') +Source('stats/statdb.cc') +Source('stats/text.cc') +Source('stats/visit.cc') + +if env['USE_MYSQL']: + Source('mysql.cc') + Source('stats/mysql.cc') diff --git a/src/base/annotate.cc b/src/base/annotate.cc index ba2fb1788..de7eeed51 100644 --- a/src/base/annotate.cc +++ b/src/base/annotate.cc @@ -32,7 +32,7 @@ #include "base/callback.hh" #include "base/output.hh" #include "base/trace.hh" -#include "sim/root.hh" +#include "sim/core.hh" #include "sim/sim_exit.hh" #include "sim/system.hh" diff --git a/src/base/bigint.cc b/src/base/bigint.cc new file mode 100644 index 000000000..ce9942c9c --- /dev/null +++ b/src/base/bigint.cc @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2006 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Gabe Black + */ + +#include "base/bigint.hh" + +#include <iostream> + +using namespace std; + +ostream & operator << (ostream & os, const Twin64_t & t) +{ + os << t.a << ", " << t.b; + return os; +} + +ostream & operator << (ostream & os, const Twin32_t & t) +{ + os << t.a << ", " << t.b; + return os; +} diff --git a/src/base/bigint.hh b/src/base/bigint.hh new file mode 100644 index 000000000..d60684231 --- /dev/null +++ b/src/base/bigint.hh @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2006 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Ali Saidi + */ + +#include "base/misc.hh" + +#include <iostream> + +#ifndef __BASE_BIGINT_HH__ +#define __BASE_BIGINT_HH__ +// Create a couple of large int types for atomic reads +struct m5_twin64_t { + uint64_t a; + uint64_t b; + m5_twin64_t() + {} + m5_twin64_t(const uint64_t x) + { + a = x; + b = x; + } + inline m5_twin64_t& operator=(const uint64_t x) + { + a = x; + b = x; + return *this; + } + + operator uint64_t() + { + panic("Tried to cram a twin64_t into an integer!\n"); + return a; + } +}; + +struct m5_twin32_t { + uint32_t a; + uint32_t b; + m5_twin32_t() + {} + m5_twin32_t(const uint32_t x) + { + a = x; + b = x; + } + inline m5_twin32_t& operator=(const uint32_t x) + { + a = x; + b = x; + return *this; + } + + operator uint32_t() + { + panic("Tried to cram a twin32_t into an integer!\n"); + return a; + } +}; + + +// This is for twin loads (two 64 bit values), not 1 128 bit value (as far as +// endian conversion is concerned! +typedef m5_twin64_t Twin64_t; +typedef m5_twin32_t Twin32_t; + +// Output operator overloads +std::ostream & operator << (std::ostream & os, const Twin64_t & t); +std::ostream & operator << (std::ostream & os, const Twin32_t & t); + +#endif // __BASE_BIGINT_HH__ + diff --git a/src/base/bitfield.hh b/src/base/bitfield.hh index 1fc0bad5d..69cce2245 100644 --- a/src/base/bitfield.hh +++ b/src/base/bitfield.hh @@ -44,6 +44,7 @@ mask(int nbits) } + /** * Extract the bitfield from position 'first' to 'last' (inclusive) * from 'val' and right justify it. MSB is numbered 63, LSB is 0. @@ -69,6 +70,12 @@ mbits(T val, int first, int last) return val & (mask(first+1) & ~mask(last)); } +inline uint64_t +mask(int first, int last) +{ + return mbits((uint64_t)-1LL, first, last); +} + /** * Sign-extend an N-bit value to 64 bits. */ @@ -105,4 +112,291 @@ replaceBits(T& val, int first, int last, B bit_val) val = insertBits(val, first, last, bit_val); } +/** + * Returns the bit position of the MSB that is set in the input + */ +inline +int +findMsbSet(uint64_t val) { + int msb = 0; + if (!val) + return 0; + if (bits(val, 63,32)) { msb += 32; val >>= 32; } + if (bits(val, 31,16)) { msb += 16; val >>= 16; } + if (bits(val, 15,8)) { msb += 8; val >>= 8; } + if (bits(val, 7,4)) { msb += 4; val >>= 4; } + if (bits(val, 3,2)) { msb += 2; val >>= 2; } + if (bits(val, 1,1)) { msb += 1; } + return msb; +} + +// The following implements the BitUnion system of defining bitfields +//on top of an underlying class. This is done through the pervasive use of +//both named and unnamed unions which all contain the same actual storage. +//Since they're unioned with each other, all of these storage locations +//overlap. This allows all of the bitfields to manipulate the same data +//without having to have access to each other. More details are provided with the +//individual components. + +//This namespace is for classes which implement the backend of the BitUnion +//stuff. Don't use any of these directly, except for the Bitfield classes in +//the *BitfieldTypes class(es). +namespace BitfieldBackend +{ + //A base class for all bitfields. It instantiates the actual storage, + //and provides getBits and setBits functions for manipulating it. The + //Data template parameter is type of the underlying storage. + template<class Data> + class BitfieldBase + { + protected: + Data __data; + + //This function returns a range of bits from the underlying storage. + //It relies on the "bits" function above. It's the user's + //responsibility to make sure that there is a properly overloaded + //version of this function for whatever type they want to overlay. + inline uint64_t + getBits(int first, int last) const + { + return bits(__data, first, last); + } + + //Similar to the above, but for settings bits with replaceBits. + inline void + setBits(int first, int last, uint64_t val) + { + replaceBits(__data, first, last, val); + } + }; + + //This class contains all the "regular" bitfield classes. It is inherited + //by all BitUnions which give them access to those types. + template<class Type> + class RegularBitfieldTypes + { + protected: + //This class implements ordinary bitfields, that is a span of bits + //who's msb is "first", and who's lsb is "last". + template<int first, int last=first> + class Bitfield : public BitfieldBase<Type> + { + public: + operator uint64_t () const + { + return this->getBits(first, last); + } + + uint64_t + operator=(const uint64_t _data) + { + this->setBits(first, last, _data); + return _data; + } + }; + + //A class which specializes the above so that it can only be read + //from. This is accomplished explicitly making sure the assignment + //operator is blocked. The conversion operator is carried through + //inheritance. This will unfortunately need to be copied into each + //bitfield type due to limitations with how templates work + template<int first, int last=first> + class BitfieldRO : public Bitfield<first, last> + { + private: + uint64_t + operator=(const uint64_t _data); + }; + + //Similar to the above, but only allows writing. + template<int first, int last=first> + class BitfieldWO : public Bitfield<first, last> + { + private: + operator uint64_t () const; + + public: + using Bitfield<first, last>::operator=; + }; + }; + + //This class contains all the "regular" bitfield classes. It is inherited + //by all BitUnions which give them access to those types. + template<class Type> + class SignedBitfieldTypes + { + protected: + //This class implements ordinary bitfields, that is a span of bits + //who's msb is "first", and who's lsb is "last". + template<int first, int last=first> + class SignedBitfield : public BitfieldBase<Type> + { + public: + operator int64_t () const + { + return sext<first - last + 1>(this->getBits(first, last)); + } + + int64_t + operator=(const int64_t _data) + { + this->setBits(first, last, _data); + return _data; + } + }; + + //A class which specializes the above so that it can only be read + //from. This is accomplished explicitly making sure the assignment + //operator is blocked. The conversion operator is carried through + //inheritance. This will unfortunately need to be copied into each + //bitfield type due to limitations with how templates work + template<int first, int last=first> + class SignedBitfieldRO : public SignedBitfield<first, last> + { + private: + int64_t + operator=(const int64_t _data); + }; + + //Similar to the above, but only allows writing. + template<int first, int last=first> + class SignedBitfieldWO : public SignedBitfield<first, last> + { + private: + operator int64_t () const; + + public: + int64_t operator=(const int64_t _data) + { + *((SignedBitfield<first, last> *)this) = _data; + return _data; + } + }; + }; + + template<class Type> + class BitfieldTypes : public RegularBitfieldTypes<Type>, + public SignedBitfieldTypes<Type> + {}; + + //When a BitUnion is set up, an underlying class is created which holds + //the actual union. This class then inherits from it, and provids the + //implementations for various operators. Setting things up this way + //prevents having to redefine these functions in every different BitUnion + //type. More operators could be implemented in the future, as the need + //arises. + template <class Type, class Base> + class BitUnionOperators : public Base + { + public: + operator Type () const + { + return Base::__data; + } + + Type + operator=(const Type & _data) + { + Base::__data = _data; + return _data; + } + + bool + operator<(const Base & base) const + { + return Base::__data < base.__data; + } + + bool + operator==(const Base & base) const + { + return Base::__data == base.__data; + } + }; +} + +//This macro is a backend for other macros that specialize it slightly. +//First, it creates/extends a namespace "BitfieldUnderlyingClasses" and +//sticks the class which has the actual union in it, which +//BitfieldOperators above inherits from. Putting these classes in a special +//namespace ensures that there will be no collisions with other names as long +//as the BitUnion names themselves are all distinct and nothing else uses +//the BitfieldUnderlyingClasses namespace, which is unlikely. The class itself +//creates a typedef of the "type" parameter called __DataType. This allows +//the type to propagate outside of the macro itself in a controlled way. +//Finally, the base storage is defined which BitfieldOperators will refer to +//in the operators it defines. This macro is intended to be followed by +//bitfield definitions which will end up inside it's union. As explained +//above, these is overlayed the __data member in its entirety by each of the +//bitfields which are defined in the union, creating shared storage with no +//overhead. +#define __BitUnion(type, name) \ + namespace BitfieldUnderlyingClasses \ + { \ + class name; \ + } \ + class BitfieldUnderlyingClasses::name : \ + public BitfieldBackend::BitfieldTypes<type> \ + { \ + public: \ + typedef type __DataType; \ + union { \ + type __data;\ + +//This closes off the class and union started by the above macro. It is +//followed by a typedef which makes "name" refer to a BitfieldOperator +//class inheriting from the class and union just defined, which completes +//building up the type for the user. +#define EndBitUnion(name) \ + }; \ + }; \ + typedef BitfieldBackend::BitUnionOperators< \ + BitfieldUnderlyingClasses::name::__DataType, \ + BitfieldUnderlyingClasses::name> name; + +//This sets up a bitfield which has other bitfields nested inside of it. The +//__data member functions like the "underlying storage" of the top level +//BitUnion. Like everything else, it overlays with the top level storage, so +//making it a regular bitfield type makes the entire thing function as a +//regular bitfield when referred to by itself. +#define __SubBitUnion(fieldType, first, last, name) \ + class : public BitfieldBackend::BitfieldTypes<__DataType> \ + { \ + public: \ + union { \ + fieldType<first, last> __data; + +//This closes off the union created above and gives it a name. Unlike the top +//level BitUnion, we're interested in creating an object instead of a type. +//The operators are defined in the macro itself instead of a class for +//technical reasons. If someone determines a way to move them to one, please +//do so. +#define EndSubBitUnion(name) \ + }; \ + inline operator const __DataType () \ + { return __data; } \ + \ + inline const __DataType operator = (const __DataType & _data) \ + { __data = _data; } \ + } name; + +//Regular bitfields +//These define macros for read/write regular bitfield based subbitfields. +#define SubBitUnion(name, first, last) \ + __SubBitUnion(Bitfield, first, last, name) + +//Regular bitfields +//These define macros for read/write regular bitfield based subbitfields. +#define SignedSubBitUnion(name, first, last) \ + __SubBitUnion(SignedBitfield, first, last, name) + +//Use this to define an arbitrary type overlayed with bitfields. +#define BitUnion(type, name) __BitUnion(type, name) + +//Use this to define conveniently sized values overlayed with bitfields. +#define BitUnion64(name) __BitUnion(uint64_t, name) +#define BitUnion32(name) __BitUnion(uint32_t, name) +#define BitUnion16(name) __BitUnion(uint16_t, name) +#define BitUnion8(name) __BitUnion(uint8_t, name) + #endif // __BASE_BITFIELD_HH__ diff --git a/src/base/cprintf.cc b/src/base/cprintf.cc index dd8ce858b..d4ba9ca21 100644 --- a/src/base/cprintf.cc +++ b/src/base/cprintf.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002-2005 The Regents of The University of Michigan + * Copyright (c) 2002-2006 The Regents of The University of Michigan * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -39,232 +39,247 @@ using namespace std; namespace cp { -ArgList::~ArgList() +Print::Print(std::ostream &stream, const std::string &format) + : stream(stream), format(format.c_str()), ptr(format.c_str()) +{ + saved_flags = stream.flags(); + saved_fill = stream.fill(); + saved_precision = stream.precision(); +} + +Print::Print(std::ostream &stream, const char *format) + : stream(stream), format(format), ptr(format) +{ + saved_flags = stream.flags(); + saved_fill = stream.fill(); + saved_precision = stream.precision(); +} + +Print::~Print() { - while (!objects.empty()) { - delete objects.front(); - objects.pop_front(); - } } void -ArgList::dump(const string &format) +Print::process(Format &fmt) { - list_t::iterator iter = objects.begin(); - list_t::iterator end = objects.end(); - - const char *p = format.c_str(); - - stream->fill(' '); - stream->flags((ios::fmtflags)0); - - while (*p) { - switch (*p) { - case '%': { - if (p[1] == '%') { - *stream << '%'; - p += 2; - continue; - } - - Format fmt; - bool done = false; - bool end_number = false; - bool have_precision = false; - int number = 0; - - while (!done) { - ++p; - if (*p >= '0' && *p <= '9') { - if (end_number) - continue; - } else if (number > 0) - end_number = true; - - switch (*p) { - case 's': - fmt.format = Format::string; - done = true; - break; - - case 'c': - fmt.format = Format::character; - done = true; - break; - - case 'l': - continue; - - case 'p': - fmt.format = Format::integer; - fmt.base = Format::hex; - fmt.alternate_form = true; - done = true; - break; - - case 'X': - fmt.uppercase = true; - case 'x': - fmt.base = Format::hex; - fmt.format = Format::integer; - done = true; - break; - - case 'o': - fmt.base = Format::oct; - fmt.format = Format::integer; - done = true; - break; - - case 'd': - case 'i': - case 'u': - fmt.format = Format::integer; - done = true; - break; - - case 'G': - fmt.uppercase = true; - case 'g': - fmt.format = Format::floating; - fmt.float_format = Format::best; - done = true; - break; - - case 'E': - fmt.uppercase = true; - case 'e': - fmt.format = Format::floating; - fmt.float_format = Format::scientific; - done = true; - break; - - case 'f': - fmt.format = Format::floating; - fmt.float_format = Format::fixed; - done = true; - break; - - case 'n': - *stream << "we don't do %n!!!\n"; - done = true; - break; - - case '#': - fmt.alternate_form = true; - break; - - case '-': - fmt.flush_left = true; - break; - - case '+': - fmt.print_sign = true; - break; - - case ' ': - fmt.blank_space = true; - break; - - case '.': - fmt.width = number; - fmt.precision = 0; - have_precision = true; - number = 0; - end_number = false; - break; - - case '0': - if (number == 0) { - fmt.fill_zero = true; - break; - } - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - number = number * 10 + (*p - '0'); - break; - - case '%': - assert("we shouldn't get here"); - break; - - default: - done = true; - break; - } - - if (end_number) { - if (have_precision) - fmt.precision = number; - else - fmt.width = number; - - end_number = false; - number = 0; - } - } - - if (iter != end) - { - ios::fmtflags saved_flags = stream->flags(); - char old_fill = stream->fill(); - int old_precision = stream->precision(); - - (*iter)->process(*stream, fmt); - - stream->flags(saved_flags); - stream->fill(old_fill); - stream->precision(old_precision); - - ++iter; - } else { - *stream << "<missing arg for format>"; - } - - ++p; - } + size_t len; + + while (*ptr) { + switch (*ptr) { + case '%': + if (ptr[1] != '%') + goto processing; + + stream.put('%'); + ptr += 2; break; case '\n': - *stream << endl; - ++p; + stream << endl; + ++ptr; break; case '\r': - ++p; - if (*p != '\n') - *stream << endl; + ++ptr; + if (*ptr != '\n') + stream << endl; break; - default: { - size_t len = strcspn(p, "%\n\r\0"); - stream->write(p, len); - p += len; - } + default: + len = strcspn(ptr, "%\n\r\0"); + stream.write(ptr, len); + ptr += len; break; } } - while (iter != end) { - *stream << "<extra arg>"; - ++iter; + return; + + processing: + bool done = false; + bool end_number = false; + bool have_precision = false; + int number = 0; + + stream.fill(' '); + stream.flags((ios::fmtflags)0); + + while (!done) { + ++ptr; + if (*ptr >= '0' && *ptr <= '9') { + if (end_number) + continue; + } else if (number > 0) + end_number = true; + + switch (*ptr) { + case 's': + fmt.format = Format::string; + done = true; + break; + + case 'c': + fmt.format = Format::character; + done = true; + break; + + case 'l': + continue; + + case 'p': + fmt.format = Format::integer; + fmt.base = Format::hex; + fmt.alternate_form = true; + done = true; + break; + + case 'X': + fmt.uppercase = true; + case 'x': + fmt.base = Format::hex; + fmt.format = Format::integer; + done = true; + break; + + case 'o': + fmt.base = Format::oct; + fmt.format = Format::integer; + done = true; + break; + + case 'd': + case 'i': + case 'u': + fmt.format = Format::integer; + done = true; + break; + + case 'G': + fmt.uppercase = true; + case 'g': + fmt.format = Format::floating; + fmt.float_format = Format::best; + done = true; + break; + + case 'E': + fmt.uppercase = true; + case 'e': + fmt.format = Format::floating; + fmt.float_format = Format::scientific; + done = true; + break; + + case 'f': + fmt.format = Format::floating; + fmt.float_format = Format::fixed; + done = true; + break; + + case 'n': + stream << "we don't do %n!!!\n"; + done = true; + break; + + case '#': + fmt.alternate_form = true; + break; + + case '-': + fmt.flush_left = true; + break; + + case '+': + fmt.print_sign = true; + break; + + case ' ': + fmt.blank_space = true; + break; + + case '.': + fmt.width = number; + fmt.precision = 0; + have_precision = true; + number = 0; + end_number = false; + break; + + case '0': + if (number == 0) { + fmt.fill_zero = true; + break; + } + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + number = number * 10 + (*ptr - '0'); + break; + + case '%': + assert("we shouldn't get here"); + break; + + default: + done = true; + break; + } + + if (end_number) { + if (have_precision) + fmt.precision = number; + else + fmt.width = number; + + end_number = false; + number = 0; + } } + + ++ptr; } -string -ArgList::dumpToString(const string &format) +void +Print::end_args() { - stringstream ss; + size_t len; - dump(ss, format); + while (*ptr) { + switch (*ptr) { + case '%': + if (ptr[1] != '%') + stream << "<extra arg>"; - return ss.str(); -} + stream.put('%'); + ptr += 2; + break; + case '\n': + stream << endl; + ++ptr; + break; + case '\r': + ++ptr; + if (*ptr != '\n') + stream << endl; + break; + + default: + len = strcspn(ptr, "%\n\r\0"); + stream.write(ptr, len); + ptr += len; + break; + } + } + + stream.flags(saved_flags); + stream.fill(saved_fill); + stream.precision(saved_precision); } + +/* end namespace cp */ } diff --git a/src/base/cprintf.hh b/src/base/cprintf.hh index dd2256e69..cff73a228 100644 --- a/src/base/cprintf.hh +++ b/src/base/cprintf.hh @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002-2005 The Regents of The University of Michigan + * Copyright (c) 2002-2006 The Regents of The University of Michigan * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -29,142 +29,135 @@ * Steve Reinhardt */ -#ifndef __CPRINTF_HH__ -#define __CPRINTF_HH__ +#ifndef __BASE_CPRINTF_HH__ +#define __BASE_CPRINTF_HH__ +#include <ios> #include <iostream> #include <list> #include <string> +#include "base/varargs.hh" #include "base/cprintf_formats.hh" namespace cp { -class ArgList +#define CPRINTF_DECLARATION VARARGS_DECLARATION(cp::Print) +#define CPRINTF_DEFINITION VARARGS_DEFINITION(cp::Print) + +struct Print { - private: - class Base - { - public: - virtual ~Base() {} - virtual void process(std::ostream &out, Format &fmt) = 0; - }; + protected: + std::ostream &stream; + const char *format; + const char *ptr; + + std::ios::fmtflags saved_flags; + char saved_fill; + int saved_precision; + + void process(Format &fmt); + + public: + Print(std::ostream &stream, const std::string &format); + Print(std::ostream &stream, const char *format); + ~Print(); template <typename T> - class Node : public Base + void + add_arg(const T &data) { - public: - const T &data; - - public: - Node(const T &d) : data(d) {} - virtual void process(std::ostream &out, Format &fmt) { - switch (fmt.format) { - case Format::character: - format_char(out, data, fmt); - break; - - case Format::integer: - format_integer(out, data, fmt); - break; - - case Format::floating: - format_float(out, data, fmt); - break; - - case Format::string: - format_string(out, data, fmt); - break; - - default: - out << "<bad format>"; - break; - } - } - }; + Format fmt; + process(fmt); - typedef std::list<Base *> list_t; + switch (fmt.format) { + case Format::character: + format_char(stream, data, fmt); + break; - protected: - list_t objects; - std::ostream *stream; + case Format::integer: + format_integer(stream, data, fmt); + break; - public: - ArgList() : stream(&std::cout) {} - ~ArgList(); + case Format::floating: + format_float(stream, data, fmt); + break; - template<class T> - void append(const T &data) { - Base *obj = new ArgList::Node<T>(data); - objects.push_back(obj); - } + case Format::string: + format_string(stream, data, fmt); + break; - template<class T> - void prepend(const T &data) { - Base *obj = new ArgList::Node<T>(data); - objects.push_front(obj); + default: + stream << "<bad format>"; + break; + } } - void dump(const std::string &format); - void dump(std::ostream &strm, const std::string &fmt) - { stream = &strm; dump(fmt); } + void end_args(); +}; - std::string dumpToString(const std::string &format); +/* end namespace cp */ } - friend ArgList &operator<<(std::ostream &str, ArgList &list); -}; +typedef VarArgs::List<cp::Print> CPrintfArgsList; + +inline void +ccprintf(std::ostream &stream, const char *format, const CPrintfArgsList &args) +{ + cp::Print print(stream, format); + args.add_args(print); +} -template<class T> -inline ArgList & -operator,(ArgList &alist, const T &data) +inline void +ccprintf(std::ostream &stream, const char *format, CPRINTF_DECLARATION) { - alist.append(data); - return alist; + cp::Print print(stream, format); + VARARGS_ADDARGS(print); } -class ArgListNull { -}; +inline void +cprintf(const char *format, CPRINTF_DECLARATION) +{ + ccprintf(std::cout, format, VARARGS_ALLARGS); +} + +inline std::string +csprintf(const char *format, CPRINTF_DECLARATION) +{ + std::stringstream stream; + ccprintf(stream, format, VARARGS_ALLARGS); + return stream.str(); +} -inline ArgList & -operator,(ArgList &alist, ArgListNull) -{ return alist; } +/* + * functions again with std::string. We have both so we don't waste + * time converting const char * to std::string since we don't take + * advantage of it. + */ +inline void +ccprintf(std::ostream &stream, const std::string &format, + const CPrintfArgsList &args) +{ + ccprintf(stream, format.c_str(), args); +} -// -// cprintf(format, args, ...) prints to cout -// (analogous to printf()) -// inline void -__cprintf(const std::string &format, ArgList &args) -{ args.dump(format); delete &args; } -#define __cprintf__(format, ...) \ - cp::__cprintf(format, (*(new cp::ArgList), __VA_ARGS__)) -#define cprintf(...) \ - __cprintf__(__VA_ARGS__, cp::ArgListNull()) - -// -// ccprintf(stream, format, args, ...) prints to the specified stream -// (analogous to fprintf()) -// +ccprintf(std::ostream &stream, const std::string &format, CPRINTF_DECLARATION) +{ + ccprintf(stream, format.c_str(), VARARGS_ALLARGS); +} + inline void -__ccprintf(std::ostream &stream, const std::string &format, ArgList &args) -{ args.dump(stream, format); delete &args; } -#define __ccprintf__(stream, format, ...) \ - cp::__ccprintf(stream, format, (*(new cp::ArgList), __VA_ARGS__)) -#define ccprintf(stream, ...) \ - __ccprintf__(stream, __VA_ARGS__, cp::ArgListNull()) - -// -// csprintf(format, args, ...) returns a string -// (roughly analogous to sprintf()) -// -inline std::string -__csprintf(const std::string &format, ArgList &args) -{ std::string s = args.dumpToString(format); delete &args; return s; } -#define __csprintf__(format, ...) \ - cp::__csprintf(format, (*(new cp::ArgList), __VA_ARGS__)) -#define csprintf(...) \ - __csprintf__(__VA_ARGS__, cp::ArgListNull()) +cprintf(const std::string &format, CPRINTF_DECLARATION) +{ + ccprintf(std::cout, format.c_str(), VARARGS_ALLARGS); +} +inline std::string +csprintf(const std::string &format, CPRINTF_DECLARATION) +{ + std::stringstream stream; + ccprintf(stream, format.c_str(), VARARGS_ALLARGS); + return stream.str(); } #endif // __CPRINTF_HH__ diff --git a/src/base/cprintf_formats.hh b/src/base/cprintf_formats.hh index 0af493217..4e8b2b09e 100644 --- a/src/base/cprintf_formats.hh +++ b/src/base/cprintf_formats.hh @@ -28,8 +28,8 @@ * Authors: Nathan Binkert */ -#ifndef __CPRINTF_FORMATS_HH__ -#define __CPRINTF_FORMATS_HH__ +#ifndef __BASE_CPRINTF_FORMATS_HH__ +#define __BASE_CPRINTF_FORMATS_HH__ #include <sstream> #include <ostream> diff --git a/src/base/loader/elf_object.cc b/src/base/loader/elf_object.cc index d59affe85..8f157da28 100644 --- a/src/base/loader/elf_object.cc +++ b/src/base/loader/elf_object.cc @@ -78,12 +78,23 @@ ElfObject::tryFile(const string &fname, int fd, size_t len, uint8_t *data) //just assume if it wasn't something else and it's 64 bit, that's //what it must be. if (ehdr.e_machine == EM_SPARC64 || - ehdr.e_machine == EM_SPARC || + (ehdr.e_machine == EM_SPARC && + ehdr.e_ident[EI_CLASS] == ELFCLASS64)|| ehdr.e_machine == EM_SPARCV9) { - arch = ObjectFile::SPARC; + arch = ObjectFile::SPARC64; + } else if (ehdr.e_machine == EM_SPARC32PLUS || + (ehdr.e_machine == EM_SPARC && + ehdr.e_ident[EI_CLASS] == ELFCLASS32)) { + arch = ObjectFile::SPARC32; } else if (ehdr.e_machine == EM_MIPS && ehdr.e_ident[EI_CLASS] == ELFCLASS32) { arch = ObjectFile::Mips; + } else if (ehdr.e_machine == EM_X86_64 && + ehdr.e_ident[EI_CLASS] == ELFCLASS64) { + //In the future, we might want to differentiate between 32 bit + //and 64 bit x86 processes in case there are differences in their + //initial stack frame. + arch = ObjectFile::X86; } else if (ehdr.e_ident[EI_CLASS] == ELFCLASS64) { arch = ObjectFile::Alpha; } else { diff --git a/src/base/loader/object_file.hh b/src/base/loader/object_file.hh index 18e6482be..4b44a6e22 100644 --- a/src/base/loader/object_file.hh +++ b/src/base/loader/object_file.hh @@ -47,8 +47,10 @@ class ObjectFile enum Arch { UnknownArch, Alpha, - SPARC, - Mips + SPARC64, + SPARC32, + Mips, + X86 }; enum OpSys { diff --git a/src/base/misc.cc b/src/base/misc.cc index 991a33736..afb48ca80 100644 --- a/src/base/misc.cc +++ b/src/base/misc.cc @@ -36,91 +36,99 @@ #include "base/misc.hh" #include "base/output.hh" #include "base/trace.hh" +#include "base/varargs.hh" #include "sim/host.hh" -#include "sim/root.hh" +#include "sim/core.hh" using namespace std; void -__panic(const string &format, cp::ArgList &args, const char *func, - const char *file, int line) +__panic(const char *func, const char *file, int line, const char *fmt, + CPRINTF_DEFINITION) { - string fmt = "panic: " + format; - switch (fmt[fmt.size() - 1]) { + string format = "panic: "; + format += fmt; + switch (format[format.size() - 1]) { case '\n': case '\r': break; default: - fmt += "\n"; + format += "\n"; } - fmt += " @ cycle %d\n[%s:%s, line %d]\n"; + format += " @ cycle %d\n[%s:%s, line %d]\n"; - args.append(curTick); - args.append(func); - args.append(file); - args.append(line); - args.dump(cerr, fmt); + CPrintfArgsList args(VARARGS_ALLARGS); - delete &args; + args.push_back(curTick); + args.push_back(func); + args.push_back(file); + args.push_back(line); + + ccprintf(cerr, format.c_str(), args); abort(); } void -__fatal(const string &format, cp::ArgList &args, const char *func, - const char *file, int line) +__fatal(const char *func, const char *file, int line, const char *fmt, + CPRINTF_DEFINITION) { - string fmt = "fatal: " + format; + CPrintfArgsList args(VARARGS_ALLARGS); + string format = "fatal: "; + format += fmt; - switch (fmt[fmt.size() - 1]) { + switch (format[format.size() - 1]) { case '\n': case '\r': break; default: - fmt += "\n"; + format += "\n"; } - fmt += " @ cycle %d\n[%s:%s, line %d]\n"; - fmt += "Memory Usage: %ld KBytes\n"; + format += " @ cycle %d\n[%s:%s, line %d]\n"; + format += "Memory Usage: %ld KBytes\n"; - args.append(curTick); - args.append(func); - args.append(file); - args.append(line); - args.append(memUsage()); - args.dump(cerr, fmt); + args.push_back(curTick); + args.push_back(func); + args.push_back(file); + args.push_back(line); + args.push_back(memUsage()); - delete &args; + ccprintf(cerr, format.c_str(), args); exit(1); } void -__warn(const string &format, cp::ArgList &args, const char *func, - const char *file, int line) +__warn(const char *func, const char *file, int line, const char *fmt, + CPRINTF_DEFINITION) { - string fmt = "warn: " + format; + string format = "warn: "; + format += fmt; - switch (fmt[fmt.size() - 1]) { + switch (format[format.size() - 1]) { case '\n': case '\r': break; default: - fmt += "\n"; + format += "\n"; } #ifdef VERBOSE_WARN - fmt += " @ cycle %d\n[%s:%s, line %d]\n"; - args.append(curTick); - args.append(func); - args.append(file); - args.append(line); + format += " @ cycle %d\n[%s:%s, line %d]\n"; #endif - args.dump(cerr, fmt); - if (simout.isFile(*outputStream)) - args.dump(*outputStream, fmt); + CPrintfArgsList args(VARARGS_ALLARGS); + +#ifdef VERBOSE_WARN + args.push_back(curTick); + args.push_back(func); + args.push_back(file); + args.push_back(line); +#endif - delete &args; + ccprintf(cerr, format.c_str(), args); + if (simout.isFile(*outputStream)) + ccprintf(*outputStream, format.c_str(), args); } diff --git a/src/base/misc.hh b/src/base/misc.hh index c12c2fe20..1509ea2d2 100644 --- a/src/base/misc.hh +++ b/src/base/misc.hh @@ -32,9 +32,11 @@ #ifndef __MISC_HH__ #define __MISC_HH__ -#include <assert.h> +#include <cassert> + #include "base/compiler.hh" #include "base/cprintf.hh" +#include "base/varargs.hh" #if defined(__SUNPRO_CC) #define __FUNCTION__ "how to fix me?" @@ -47,14 +49,20 @@ // calls abort which can dump core or enter the debugger. // // -void __panic(const std::string&, cp::ArgList &, const char*, const char*, int) - M5_ATTR_NORETURN; -#define __panic__(format, ...) \ - __panic(format, (*(new cp::ArgList), __VA_ARGS__), \ - __FUNCTION__ , __FILE__, __LINE__) -#define panic(...) \ - __panic__(__VA_ARGS__, cp::ArgListNull()) +void __panic(const char *func, const char *file, int line, const char *format, + CPRINTF_DECLARATION) M5_ATTR_NORETURN; +void __panic(const char *func, const char *file, int line, + const std::string &format, CPRINTF_DECLARATION) +M5_ATTR_NORETURN; + +inline void +__panic(const char *func, const char *file, int line, + const std::string &format, CPRINTF_DEFINITION) +{ + __panic(func, file, line, format.c_str(), VARARGS_ALLARGS); +} M5_PRAGMA_NORETURN(__panic) +#define panic(...) __panic(__FUNCTION__, __FILE__, __LINE__, __VA_ARGS__) // // This implements a cprintf based fatal() function. fatal() should @@ -64,34 +72,43 @@ M5_PRAGMA_NORETURN(__panic) // "normal" exit with an error code, as opposed to abort() like // panic() does. // -void __fatal(const std::string&, cp::ArgList &, const char*, const char*, int) +void __fatal(const char *func, const char *file, int line, const char *format, + CPRINTF_DECLARATION) M5_ATTR_NORETURN; +void __fatal(const char *func, const char *file, int line, + const std::string &format, CPRINTF_DECLARATION) M5_ATTR_NORETURN; -#define __fatal__(format, ...) \ - __fatal(format, (*(new cp::ArgList), __VA_ARGS__), \ - __FUNCTION__ , __FILE__, __LINE__) -#define fatal(...) \ - __fatal__(__VA_ARGS__, cp::ArgListNull()) + +inline void +__fatal(const char *func, const char *file, int line, + const std::string &format, CPRINTF_DEFINITION) +{ + __fatal(func, file, line, format.c_str(), VARARGS_ALLARGS); +} M5_PRAGMA_NORETURN(__fatal) +#define fatal(...) __fatal(__FUNCTION__, __FILE__, __LINE__, __VA_ARGS__) // // This implements a cprintf based warn // -void __warn(const std::string&, cp::ArgList &, const char*, const char*, int); -#define __warn__(format, ...) \ - __warn(format, (*(new cp::ArgList), __VA_ARGS__), \ - __FUNCTION__ , __FILE__, __LINE__) -#define warn(...) \ - __warn__(__VA_ARGS__, cp::ArgListNull()) +void __warn(const char *func, const char *file, int line, const char *format, + CPRINTF_DECLARATION); +inline void +__warn(const char *func, const char *file, int line, const std::string &format, + CPRINTF_DECLARATION) +{ + __warn(func, file, line, format, VARARGS_ALLARGS); +} +#define warn(...) __warn(__FUNCTION__, __FILE__, __LINE__, __VA_ARGS__) // Only print the warning message the first time it is seen. This // doesn't check the warning string itself, it just only lets one // warning come from the statement. So, even if the arguments change // and that would have resulted in a different warning message, // subsequent messages would still be supressed. -#define warn_once(...) do { \ +#define warn_once(...) do { \ static bool once = false; \ if (!once) { \ - __warn__(__VA_ARGS__, cp::ArgListNull()); \ + warn(__VA_ARGS__); \ once = true; \ } \ } while (0) @@ -99,10 +116,10 @@ void __warn(const std::string&, cp::ArgList &, const char*, const char*, int); // // assert() that prints out the current cycle // -#define m5_assert(TEST) \ - if (!(TEST)) { \ - std::cerr << "Assertion failure, curTick = " << curTick << std::endl; \ - } \ - assert(TEST); +#define m5_assert(TEST) do { \ + if (!(TEST)) \ + ccprintf(std::cerr, "Assertion failure, curTick = %d\n", curTick); \ + assert(TEST); \ +} while (0) #endif // __MISC_HH__ diff --git a/src/base/pollevent.cc b/src/base/pollevent.cc index 32724b74d..331b5eac6 100644 --- a/src/base/pollevent.cc +++ b/src/base/pollevent.cc @@ -42,7 +42,7 @@ #include "sim/host.hh" #include "base/misc.hh" #include "base/pollevent.hh" -#include "sim/root.hh" +#include "sim/core.hh" #include "sim/serialize.hh" using namespace std; diff --git a/src/base/pollevent.hh b/src/base/pollevent.hh index 5b84650cb..ecaeb94ce 100644 --- a/src/base/pollevent.hh +++ b/src/base/pollevent.hh @@ -33,7 +33,7 @@ #include <vector> #include <poll.h> -#include "sim/root.hh" +#include "sim/core.hh" class Checkpoint; class PollQueue; diff --git a/src/base/random.cc b/src/base/random.cc index 0ccedcb00..ceab337d9 100644 --- a/src/base/random.cc +++ b/src/base/random.cc @@ -40,38 +40,20 @@ #include <cstdlib> #include <cmath> - -#include "sim/param.hh" #include "base/random.hh" -#include "base/trace.hh" using namespace std; -class RandomContext : public ParamContext -{ - public: - RandomContext(const string &_iniSection) - : ::ParamContext(_iniSection) {} - ~RandomContext() {} - - void checkParams(); -}; - -RandomContext paramContext("random"); - -Param<unsigned> -seed(¶mContext, "seed", "seed to random number generator", 1); - -void -RandomContext::checkParams() +uint32_t +getInt32() { - ::srand48(seed); + return mrand48() & 0xffffffff; } -long -getLong() +double +getDouble() { - return mrand48(); + return drand48(); } double @@ -105,21 +87,3 @@ getUniformPos(uint64_t min, uint64_t max) return (uint64_t)m5round(r); } - - -// idea for generating a double from erand48 -double -getDouble() -{ - union { - uint32_t _long[2]; - uint16_t _short[4]; - }; - - _long[0] = mrand48(); - _long[1] = mrand48(); - - return ldexp((double) _short[0], -48) + - ldexp((double) _short[1], -32) + - ldexp((double) _short[2], -16); -} diff --git a/src/base/random.hh b/src/base/random.hh index 40d62da7f..0cd88728d 100644 --- a/src/base/random.hh +++ b/src/base/random.hh @@ -34,7 +34,7 @@ #include "sim/host.hh" -long getLong(); +uint32_t getUInt32(); double getDouble(); double m5random(double r); uint64_t getUniformPos(uint64_t min, uint64_t max); @@ -46,7 +46,7 @@ struct Random; template<> struct Random<int8_t> { static int8_t get() - { return getLong() & (int8_t)-1; } + { return getUInt32() & (int8_t)-1; } static int8_t uniform(int8_t min, int8_t max) { return getUniform(min, max); } @@ -55,7 +55,7 @@ template<> struct Random<int8_t> template<> struct Random<uint8_t> { static uint8_t get() - { return getLong() & (uint8_t)-1; } + { return getUInt32() & (uint8_t)-1; } static uint8_t uniform(uint8_t min, uint8_t max) { return getUniformPos(min, max); } @@ -64,7 +64,7 @@ template<> struct Random<uint8_t> template<> struct Random<int16_t> { static int16_t get() - { return getLong() & (int16_t)-1; } + { return getUInt32() & (int16_t)-1; } static int16_t uniform(int16_t min, int16_t max) { return getUniform(min, max); } @@ -73,7 +73,7 @@ template<> struct Random<int16_t> template<> struct Random<uint16_t> { static uint16_t get() - { return getLong() & (uint16_t)-1; } + { return getUInt32() & (uint16_t)-1; } static uint16_t uniform(uint16_t min, uint16_t max) { return getUniformPos(min, max); } @@ -82,7 +82,7 @@ template<> struct Random<uint16_t> template<> struct Random<int32_t> { static int32_t get() - { return (int32_t)getLong(); } + { return (int32_t)getUInt32(); } static int32_t uniform(int32_t min, int32_t max) { return getUniform(min, max); } @@ -91,7 +91,7 @@ template<> struct Random<int32_t> template<> struct Random<uint32_t> { static uint32_t get() - { return (uint32_t)getLong(); } + { return (uint32_t)getUInt32(); } static uint32_t uniform(uint32_t min, uint32_t max) { return getUniformPos(min, max); } @@ -100,7 +100,7 @@ template<> struct Random<uint32_t> template<> struct Random<int64_t> { static int64_t get() - { return (int64_t)getLong() << 32 || (uint64_t)getLong(); } + { return (int64_t)getUInt32() << 32 || (uint64_t)getUInt32(); } static int64_t uniform(int64_t min, int64_t max) { return getUniform(min, max); } @@ -109,7 +109,7 @@ template<> struct Random<int64_t> template<> struct Random<uint64_t> { static uint64_t get() - { return (uint64_t)getLong() << 32 || (uint64_t)getLong(); } + { return (uint64_t)getUInt32() << 32 || (uint64_t)getUInt32(); } static uint64_t uniform(uint64_t min, uint64_t max) { return getUniformPos(min, max); } diff --git a/src/base/statistics.hh b/src/base/statistics.hh index 2b1b327e5..761b30c2b 100644 --- a/src/base/statistics.hh +++ b/src/base/statistics.hh @@ -70,7 +70,7 @@ class Callback; -/** The current simulated cycle. */ +/** The current simulated tick. */ extern Tick curTick; /* A namespace for all of the Statistics */ @@ -598,9 +598,9 @@ struct StatStor }; /** - * Templatized storage and interface to a per-cycle average stat. This keeps - * a current count and updates a total (count * cycles) when this count - * changes. This allows the quick calculation of a per cycle count of the item + * Templatized storage and interface to a per-tick average stat. This keeps + * a current count and updates a total (count * ticks) when this count + * changes. This allows the quick calculation of a per tick count of the item * being watched. This is good for keeping track of residencies in structures * among other things. */ @@ -613,9 +613,9 @@ struct AvgStor private: /** The current count. */ Counter current; - /** The total count for all cycles. */ + /** The total count for all tick. */ mutable Result total; - /** The cycle that current last changed. */ + /** The tick that current last changed. */ mutable Tick last; public: @@ -1563,7 +1563,7 @@ struct FancyStor }; /** - * Templatized storage for distribution that calculates per cycle mean and + * Templatized storage for distribution that calculates per tick mean and * variance. */ struct AvgFancy @@ -2280,7 +2280,7 @@ class Value : public Wrap<Value, ValueBase, ScalarStatData> }; /** - * A stat that calculates the per cycle average of a value. + * A stat that calculates the per tick average of a value. * @sa Stat, ScalarBase, AvgStor */ template<int N = 0> @@ -2417,7 +2417,7 @@ class StandardDeviation }; /** - * Calculates the per cycle mean and variance of the samples. + * Calculates the per tick mean and variance of the samples. * @sa Stat, DistBase, AvgFancy */ template<int N = 0> @@ -2839,6 +2839,7 @@ class Temp */ void check(); +void dump(); void reset(); void registerResetCallback(Callback *cb); diff --git a/src/base/stats/events.cc b/src/base/stats/events.cc index 6ecc5434c..dc56fe75f 100644 --- a/src/base/stats/events.cc +++ b/src/base/stats/events.cc @@ -31,20 +31,8 @@ #include <vector> #include "base/stats/events.hh" - -#if USE_MYSQL -#include "base/cprintf.hh" -#include "base/misc.hh" -#include "base/mysql.hh" -#include "base/stats/mysql.hh" -#include "base/stats/mysql_run.hh" -#include "base/str.hh" -#endif - -#include "base/match.hh" +#include "base/stats/output.hh" #include "sim/host.hh" -#include "sim/sim_object.hh" -#include "sim/root.hh" using namespace std; @@ -52,118 +40,21 @@ namespace Stats { Tick EventStart = ULL(0x7fffffffffffffff); -ObjectMatch event_ignore; +extern list<Output *> OutputList; #if USE_MYSQL -class InsertEvent -{ - private: - char *query; - int size; - bool first; - static const int maxsize = 1024*1024; - - typedef map<string, uint32_t> event_map_t; - event_map_t events; - - MySQL::Connection &mysql; - uint16_t run; - - public: - InsertEvent() - : mysql(MySqlDB.conn()), run(MySqlDB.run()) - { - query = new char[maxsize + 1]; - size = 0; - first = true; - flush(); - } - ~InsertEvent() - { - flush(); - } - - void flush(); - void insert(const string &stat); -}; - void -InsertEvent::insert(const string &stat) +__event(const string &event) { - assert(mysql.connected()); - - event_map_t::iterator i = events.find(stat); - uint32_t event; - if (i == events.end()) { - mysql.query( - csprintf("SELECT en_id " - "from event_names " - "where en_name=\"%s\"", - stat)); - - MySQL::Result result = mysql.store_result(); - if (!result) - panic("could not get a run\n%s\n", mysql.error); - - assert(result.num_fields() == 1); - MySQL::Row row = result.fetch_row(); - if (row) { - if (!to_number(row[0], event)) - panic("invalid event id: %s\n", row[0]); - } else { - mysql.query( - csprintf("INSERT INTO " - "event_names(en_name)" - "values(\"%s\")", - stat)); - - if (mysql.error) - panic("could not get a run\n%s\n", mysql.error); - - event = mysql.insert_id(); - } - } else { - event = (*i).second; + list<Output *>::iterator i = OutputList.begin(); + list<Output *>::iterator end = OutputList.end(); + for (; i != end; ++i) { + Output *output = *i; + if (!output->valid()) + continue; + + output->event(event); } - - if (size + 1024 > maxsize) - flush(); - - if (!first) { - query[size++] = ','; - query[size] = '\0'; - } - - first = false; - - size += sprintf(query + size, "(%u,%u,%llu)", - event, run, (unsigned long long)curTick); -} - -void -InsertEvent::flush() -{ - static const char query_header[] = "INSERT INTO " - "events(ev_event, ev_run, ev_tick)" - "values"; - - if (size) { - MySQL::Connection &mysql = MySqlDB.conn(); - assert(mysql.connected()); - mysql.query(query); - } - - query[0] = '\0'; - size = sizeof(query_header); - first = true; - memcpy(query, query_header, size); -} - -void -__event(const string &stat) -{ - static InsertEvent event; - event.insert(stat); } #endif diff --git a/src/base/stats/events.hh b/src/base/stats/events.hh index b09b91c7c..8ba9cece5 100644 --- a/src/base/stats/events.hh +++ b/src/base/stats/events.hh @@ -42,11 +42,10 @@ extern Tick EventStart; #if USE_MYSQL void __event(const std::string &stat); -bool MySqlConnected(); +#else +inline void __event(const std::string &stat) {} #endif -bool ignoreEvent(const std::string &name); - inline void recordEvent(const std::string &stat) { @@ -55,12 +54,7 @@ recordEvent(const std::string &stat) DPRINTF(StatEvents, "Statistics Event: %s\n", stat); -#if USE_MYSQL - if (!MySqlConnected()) - return; - __event(stat); -#endif } /* namespace Stats */ } diff --git a/src/base/stats/mysql.cc b/src/base/stats/mysql.cc index 0fb31f4ce..39a687fff 100644 --- a/src/base/stats/mysql.cc +++ b/src/base/stats/mysql.cc @@ -43,20 +43,13 @@ #include "base/stats/statdb.hh" #include "base/stats/types.hh" #include "base/str.hh" +#include "base/userinfo.hh" #include "sim/host.hh" using namespace std; namespace Stats { -MySqlRun MySqlDB; - -bool -MySqlConnected() -{ - return MySqlDB.connected(); -} - void MySqlRun::connect(const string &host, const string &user, const string &passwd, const string &db, const string &name, const string &sample, @@ -196,9 +189,9 @@ SetupStat::init() } unsigned -SetupStat::setup() +SetupStat::setup(MySqlRun *run) { - MySQL::Connection &mysql = MySqlDB.conn(); + MySQL::Connection &mysql = run->conn(); stringstream insert; ccprintf(insert, @@ -301,7 +294,8 @@ SetupStat::setup() return statid; } -InsertData::InsertData() +InsertData::InsertData(MySqlRun *_run) + : run(_run) { query = new char[maxsize + 1]; size = 0; @@ -317,7 +311,7 @@ void InsertData::flush() { if (size) { - MySQL::Connection &mysql = MySqlDB.conn(); + MySQL::Connection &mysql = run->conn(); assert(mysql.connected()); mysql.query(query); if (mysql.error) @@ -349,10 +343,97 @@ InsertData::insert() first = false; size += sprintf(query + size, "(%u,%d,%d,%u,%llu,\"%f\")", - stat, x, y, MySqlDB.run(), (unsigned long long)tick, + stat, x, y, run->run(), (unsigned long long)tick, data); } +InsertEvent::InsertEvent(MySqlRun *_run) + : run(_run) +{ + query = new char[maxsize + 1]; + size = 0; + first = true; + flush(); +} + +InsertEvent::~InsertEvent() +{ + flush(); +} + +void +InsertEvent::insert(const string &stat) +{ + MySQL::Connection &mysql = run->conn(); + assert(mysql.connected()); + + event_map_t::iterator i = events.find(stat); + uint32_t event; + if (i == events.end()) { + mysql.query( + csprintf("SELECT en_id " + "from event_names " + "where en_name=\"%s\"", + stat)); + + MySQL::Result result = mysql.store_result(); + if (!result) + panic("could not get a run\n%s\n", mysql.error); + + assert(result.num_fields() == 1); + MySQL::Row row = result.fetch_row(); + if (row) { + if (!to_number(row[0], event)) + panic("invalid event id: %s\n", row[0]); + } else { + mysql.query( + csprintf("INSERT INTO " + "event_names(en_name)" + "values(\"%s\")", + stat)); + + if (mysql.error) + panic("could not get a run\n%s\n", mysql.error); + + event = mysql.insert_id(); + } + } else { + event = (*i).second; + } + + if (size + 1024 > maxsize) + flush(); + + if (!first) { + query[size++] = ','; + query[size] = '\0'; + } + + first = false; + + size += sprintf(query + size, "(%u,%u,%llu)", + event, run->run(), (unsigned long long)curTick); +} + +void +InsertEvent::flush() +{ + static const char query_header[] = "INSERT INTO " + "events(ev_event, ev_run, ev_tick)" + "values"; + + MySQL::Connection &mysql = run->conn(); + assert(mysql.connected()); + + if (size) + mysql.query(query); + + query[0] = '\0'; + size = sizeof(query_header); + first = true; + memcpy(query, query_header, size); +} + struct InsertSubData { uint16_t stat; @@ -361,13 +442,13 @@ struct InsertSubData string name; string descr; - void setup(); + void setup(MySqlRun *run); }; void -InsertSubData::setup() +InsertSubData::setup(MySqlRun *run) { - MySQL::Connection &mysql = MySqlDB.conn(); + MySQL::Connection &mysql = run->conn(); assert(mysql.connected()); stringstream insert; ccprintf(insert, @@ -383,47 +464,27 @@ InsertSubData::setup() panic("could not commit transaction\n%s\n", mysql.error); } -void -InsertFormula(uint16_t stat, const string &formula) -{ - MySQL::Connection &mysql = MySqlDB.conn(); - assert(mysql.connected()); - stringstream insert_formula; - ccprintf(insert_formula, - "INSERT INTO formulas(fm_stat,fm_formula) values(%d, \"%s\")", - stat, formula); +MySql::MySql() + : run(new MySqlRun), newdata(run), newevent(run) +{} - mysql.query(insert_formula); -// if (mysql.error) -// panic("could not insert formula\n%s\n", mysql.error); - - stringstream insert_ref; - ccprintf(insert_ref, - "INSERT INTO formula_ref(fr_stat,fr_run) values(%d, %d)", - stat, MySqlDB.run()); - - mysql.query(insert_ref); -// if (mysql.error) -// panic("could not insert formula reference\n%s\n", mysql.error); - - if (mysql.commit()) - panic("could not commit transaction\n%s\n", mysql.error); +MySql::~MySql() +{ + delete run; } void -UpdatePrereq(uint16_t stat, uint16_t prereq) +MySql::connect(const string &host, const string &user, const string &passwd, + const string &db, const string &name, const string &sample, + const string &project) { - MySQL::Connection &mysql = MySqlDB.conn(); - assert(mysql.connected()); - stringstream update; - ccprintf(update, "UPDATE stats SET st_prereq=%d WHERE st_id=%d", - prereq, stat); - mysql.query(update); - if (mysql.error) - panic("could not update prereq\n%s\n", mysql.error); + run->connect(host, user, passwd, db, name, sample, project); +} - if (mysql.commit()) - panic("could not commit transaction\n%s\n", mysql.error); +bool +MySql::connected() const +{ + return run->connected(); } void @@ -434,7 +495,7 @@ MySql::configure() */ using namespace Database; - MySQL::Connection &mysql = MySqlDB.conn(); + MySQL::Connection &mysql = run->conn(); stat_list_t::const_iterator i, end = stats().end(); for (i = stats().begin(); i != end; ++i) { @@ -444,11 +505,20 @@ MySql::configure() for (i = stats().begin(); i != end; ++i) { StatData *data = *i; if (data->prereq) { + // update the prerequisite uint16_t stat_id = find(data->id); uint16_t prereq_id = find(data->prereq->id); assert(stat_id && prereq_id); - UpdatePrereq(stat_id, prereq_id); + stringstream update; + ccprintf(update, "UPDATE stats SET st_prereq=%d WHERE st_id=%d", + prereq_id, stat_id); + mysql.query(update); + if (mysql.error) + panic("could not update prereq\n%s\n", mysql.error); + + if (mysql.commit()) + panic("could not commit transaction\n%s\n", mysql.error); } } @@ -483,7 +553,7 @@ MySql::configure(const ScalarData &data) if (!configure(data, "SCALAR")) return; - insert(data.id, stat.setup()); + insert(data.id, stat.setup(run)); } void @@ -492,7 +562,7 @@ MySql::configure(const VectorData &data) if (!configure(data, "VECTOR")) return; - uint16_t statid = stat.setup(); + uint16_t statid = stat.setup(run); if (!data.subnames.empty()) { InsertSubData subdata; @@ -504,7 +574,7 @@ MySql::configure(const VectorData &data) subdata.descr = data.subdescs.empty() ? "" : data.subdescs[i]; if (!subdata.name.empty() || !subdata.descr.empty()) - subdata.setup(); + subdata.setup(run); } } @@ -523,7 +593,7 @@ MySql::configure(const DistData &data) stat.max = data.data.max; stat.bktsize = data.data.bucket_size; } - insert(data.id, stat.setup()); + insert(data.id, stat.setup(run)); } void @@ -539,7 +609,7 @@ MySql::configure(const VectorDistData &data) stat.bktsize = data.data[0].bucket_size; } - uint16_t statid = stat.setup(); + uint16_t statid = stat.setup(run); if (!data.subnames.empty()) { InsertSubData subdata; @@ -550,7 +620,7 @@ MySql::configure(const VectorDistData &data) subdata.name = data.subnames[i]; subdata.descr = data.subdescs.empty() ? "" : data.subdescs[i]; if (!subdata.name.empty() || !subdata.descr.empty()) - subdata.setup(); + subdata.setup(run); } } @@ -563,7 +633,7 @@ MySql::configure(const Vector2dData &data) if (!configure(data, "VECTOR2D")) return; - uint16_t statid = stat.setup(); + uint16_t statid = stat.setup(run); if (!data.subnames.empty()) { InsertSubData subdata; @@ -574,7 +644,7 @@ MySql::configure(const Vector2dData &data) subdata.name = data.subnames[i]; subdata.descr = data.subdescs.empty() ? "" : data.subdescs[i]; if (!subdata.name.empty() || !subdata.descr.empty()) - subdata.setup(); + subdata.setup(run); } } @@ -587,7 +657,7 @@ MySql::configure(const Vector2dData &data) subdata.y = i; subdata.name = data.y_subnames[i]; if (!subdata.name.empty()) - subdata.setup(); + subdata.setup(run); } } @@ -597,15 +667,41 @@ MySql::configure(const Vector2dData &data) void MySql::configure(const FormulaData &data) { + MySQL::Connection &mysql = run->conn(); + assert(mysql.connected()); + configure(data, "FORMULA"); - insert(data.id, stat.setup()); - InsertFormula(find(data.id), data.str()); + insert(data.id, stat.setup(run)); + + uint16_t stat = find(data.id); + string formula = data.str(); + + stringstream insert_formula; + ccprintf(insert_formula, + "INSERT INTO formulas(fm_stat,fm_formula) values(%d, \"%s\")", + stat, formula); + + mysql.query(insert_formula); +// if (mysql.error) +// panic("could not insert formula\n%s\n", mysql.error); + + stringstream insert_ref; + ccprintf(insert_ref, + "INSERT INTO formula_ref(fr_stat,fr_run) values(%d, %d)", + stat, run->run()); + + mysql.query(insert_ref); +// if (mysql.error) +// panic("could not insert formula reference\n%s\n", mysql.error); + + if (mysql.commit()) + panic("could not commit transaction\n%s\n", mysql.error); } bool MySql::valid() const { - return MySqlDB.connected(); + return run->connected(); } void @@ -620,7 +716,7 @@ MySql::output() // store sample # newdata.tick = curTick; - MySQL::Connection &mysql = MySqlDB.conn(); + MySQL::Connection &mysql = run->conn(); Database::stat_list_t::const_iterator i, end = Database::stats().end(); for (i = Database::stats().begin(); i != end; ++i) { @@ -634,6 +730,13 @@ MySql::output() } void +MySql::event(const std::string &event) +{ + newevent.insert(event); +} + + +void MySql::output(const ScalarData &data) { if (!(data.flags & print)) @@ -825,4 +928,20 @@ MySql::visit(const FormulaData &data) output(data); } -/* namespace Stats */ } +bool +initMySQL(string host, string user, string password, string database, + string project, string name, string sample) +{ + extern list<Output *> OutputList; + static MySql mysql; + + if (mysql.connected()) + return false; + + mysql.connect(host, user, password, database, name, sample, project); + OutputList.push_back(&mysql); + + return true; +} + +/* end namespace Stats */ } diff --git a/src/base/stats/mysql.hh b/src/base/stats/mysql.hh index 50f7d9e97..0ce381c2f 100644 --- a/src/base/stats/mysql.hh +++ b/src/base/stats/mysql.hh @@ -35,14 +35,13 @@ #include <string> #include "base/stats/output.hh" +#include "config/use_mysql.hh" namespace MySQL { class Connection; } namespace Stats { class DistDataData; class MySqlRun; -bool MySqlConnected(); -extern MySqlRun MySqlDB; struct SetupStat { @@ -63,7 +62,7 @@ struct SetupStat uint16_t size; void init(); - unsigned setup(); + unsigned setup(MySqlRun *run); }; class InsertData @@ -85,18 +84,43 @@ class InsertData int16_t y; public: - InsertData(); + InsertData(MySqlRun *_run); ~InsertData(); void flush(); void insert(); }; +class InsertEvent +{ + private: + char *query; + int size; + bool first; + static const int maxsize = 1024*1024; + + typedef std::map<std::string, uint32_t> event_map_t; + event_map_t events; + + MySqlRun *run; + + public: + InsertEvent(MySqlRun *_run); + ~InsertEvent(); + + void flush(); + void insert(const std::string &stat); +}; + class MySql : public Output { protected: + MySqlRun *run; /* Hide the implementation so we don't have a + #include mess */ + SetupStat stat; InsertData newdata; + InsertEvent newevent; std::list<FormulaData *> formulas; bool configured; @@ -116,6 +140,17 @@ class MySql : public Output assert(i != idmap.end()); return (*i).second; } + + public: + MySql(); + ~MySql(); + + void connect(const std::string &host, const std::string &user, + const std::string &passwd, const std::string &db, + const std::string &name, const std::string &sample, + const std::string &project); + bool connected() const; + public: // Implement Visit virtual void visit(const ScalarData &data); @@ -129,6 +164,9 @@ class MySql : public Output virtual bool valid() const; virtual void output(); + // Implement Event Output + virtual void event(const std::string &event); + protected: // Output helper void output(const DistDataData &data); @@ -149,6 +187,20 @@ class MySql : public Output void configure(const FormulaData &data); }; +bool initMySQL(std::string host, std::string database, std::string user, + std::string passwd, std::string project, std::string name, + std::string sample); + +#if !USE_MYSQL +inline bool +initMySQL(std::string host, std::string user, std::string password, + std::string database, std::string project, std::string name, + std::string sample) +{ + return false; +} +#endif + /* namespace Stats */ } #endif // __BASE_STATS_MYSQL_HH__ diff --git a/src/base/stats/output.cc b/src/base/stats/output.cc new file mode 100644 index 000000000..9f2b91c77 --- /dev/null +++ b/src/base/stats/output.cc @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2004-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Nathan Binkert + */ + +#include <list> + +#include "base/stats/output.hh" +#include "sim/eventq.hh" +#include "sim/host.hh" + +using namespace std; + +namespace Stats { + +Tick lastDump(0); +list<Output *> OutputList; + +void +dump() +{ + assert(lastDump <= curTick); + if (lastDump == curTick) + return; + lastDump = curTick; + + list<Output *>::iterator i = OutputList.begin(); + list<Output *>::iterator end = OutputList.end(); + for (; i != end; ++i) { + Output *output = *i; + if (!output->valid()) + continue; + + output->output(); + } +} + +/* namespace Stats */ } + +void +debugDumpStats() +{ + Stats::dump(); +} + diff --git a/src/base/stats/output.hh b/src/base/stats/output.hh index 4fe93791f..c7ffcaade 100644 --- a/src/base/stats/output.hh +++ b/src/base/stats/output.hh @@ -42,6 +42,7 @@ struct Output : public Visit inline void operator()() { output(); } virtual void output() = 0; virtual bool valid() const = 0; + virtual void event(const std::string &event) = 0; }; /* namespace Stats */ } diff --git a/src/base/stats/text.cc b/src/base/stats/text.cc index ae0d65537..a018c4837 100644 --- a/src/base/stats/text.cc +++ b/src/base/stats/text.cc @@ -251,6 +251,7 @@ VectorPrint::operator()(std::ostream &stream) const ScalarPrint print; print.name = name; print.desc = desc; + print.compat = compat; print.precision = precision; print.descriptions = descriptions; print.flags = flags; @@ -725,4 +726,25 @@ Text::visit(const FormulaData &data) visit((const VectorData &)data); } +bool +initText(const string &filename, bool desc, bool compat) +{ + static Text text; + static bool connected = false; + + if (connected) + return false; + + extern list<Output *> OutputList; + + text.open(*simout.find(filename)); + text.descriptions = desc; + text.compat = compat; + OutputList.push_back(&text); + connected = true; + + return true; +} + + /* namespace Stats */ } diff --git a/src/base/stats/text.hh b/src/base/stats/text.hh index b3faf5ad5..781d1083d 100644 --- a/src/base/stats/text.hh +++ b/src/base/stats/text.hh @@ -34,6 +34,7 @@ #include <iosfwd> #include <string> +#include "base/output.hh" #include "base/stats/output.hh" namespace Stats { @@ -71,8 +72,13 @@ class Text : public Output // Implement Output virtual bool valid() const; virtual void output(); + + // Implement Event Output + virtual void event(const std::string &event) {} }; +bool initText(const std::string &filename, bool desc=true, bool compat=true); + /* namespace Stats */ } #endif // __BASE_STATS_TEXT_HH__ diff --git a/src/base/trace.cc b/src/base/trace.cc index 9fa615f4d..0a7e6e833 100644 --- a/src/base/trace.cc +++ b/src/base/trace.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001-2005 The Regents of The University of Michigan + * Copyright (c) 2001-2006 The Regents of The University of Michigan * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -37,14 +37,17 @@ #include <vector> #include "base/misc.hh" -#include "base/trace.hh" +#include "base/output.hh" #include "base/str.hh" +#include "base/trace.hh" +#include "base/varargs.hh" using namespace std; namespace Trace { const string DefaultName("global"); FlagVec flags(NumFlags, false); +bool enabled = false; // // This variable holds the output stream for debug information. Other @@ -53,151 +56,74 @@ FlagVec flags(NumFlags, false); // output. // ostream *dprintf_stream = &cerr; - -ObjectMatch ignore; - -Log theLog; - -Log::Log() +ostream & +output() { - size = 0; - buffer = NULL; + return *dprintf_stream; } - void -Log::init(int _size) +setOutput(const string &filename) { - if (buffer != NULL) { - fatal("Trace::Log::init called twice!"); - } - - size = _size; - - buffer = new Record *[size]; - - for (int i = 0; i < size; ++i) { - buffer[i] = NULL; - } - - nextRecPtr = &buffer[0]; - wrapRecPtr = &buffer[size]; + dprintf_stream = simout.find(filename); } +ObjectMatch ignore; -Log::~Log() +void +dprintf(Tick when, const std::string &name, const char *format, + CPRINTF_DEFINITION) { - for (int i = 0; i < size; ++i) { - delete buffer[i]; - } - - delete [] buffer; -} + if (!name.empty() && ignore.match(name)) + return; + std::ostream &os = *dprintf_stream; -void -Log::append(Record *rec) -{ - // dump record to output stream if there's one open - if (dprintf_stream != NULL) { - rec->dump(*dprintf_stream); - } else { - rec->dump(cout); - } + string fmt = ""; + CPrintfArgsList args(VARARGS_ALLARGS); - // no buffering: justget rid of it now - if (buffer == NULL) { - delete rec; - return; + if (!name.empty()) { + fmt = "%s: " + fmt; + args.push_front(name); } - Record *oldRec = *nextRecPtr; - - if (oldRec != NULL) { - // log has wrapped: overwrite - delete oldRec; + if (when != (Tick)-1) { + fmt = "%7d: " + fmt; + args.push_front(when); } - *nextRecPtr = rec; + fmt += format; - if (++nextRecPtr == wrapRecPtr) { - nextRecPtr = &buffer[0]; - } + ccprintf(os, fmt.c_str(), args); + os.flush(); } - void -Log::dump(ostream &os) +dump(Tick when, const std::string &name, const void *d, int len) { - if (buffer == NULL) { + if (!name.empty() && ignore.match(name)) return; - } - - Record **bufPtr = nextRecPtr; - - if (*bufPtr == NULL) { - // next record slot is empty: log must not be full yet. - // start dumping from beginning of buffer - bufPtr = buffer; - } - do { - Record *rec = *bufPtr; - - rec->dump(os); - - if (++bufPtr == wrapRecPtr) { - bufPtr = &buffer[0]; - } - } while (bufPtr != nextRecPtr); -} - -PrintfRecord::~PrintfRecord() -{ - delete &args; -} + std::ostream &os = *dprintf_stream; -void -PrintfRecord::dump(ostream &os) -{ string fmt = ""; + CPrintfArgsList args; if (!name.empty()) { fmt = "%s: " + fmt; - args.prepend(name); + args.push_front(name); } - if (cycle != (Tick)-1) { + if (when != (Tick)-1) { fmt = "%7d: " + fmt; - args.prepend(cycle); + args.push_front(when); } - fmt += format; - - args.dump(os, fmt); - os.flush(); -} - -DataRecord::DataRecord(Tick _cycle, const string &_name, - const void *_data, int _len) - : Record(_cycle), name(_name), len(_len) -{ - data = new uint8_t[len]; - memcpy(data, _data, len); -} - -DataRecord::~DataRecord() -{ - delete [] data; -} - -void -DataRecord::dump(ostream &os) -{ + const char *data = static_cast<const char *>(d); int c, i, j; - for (i = 0; i < len; i += 16) { - ccprintf(os, "%d: %s: %08x ", cycle, name, i); + ccprintf(os, fmt, args); + ccprintf(os, "%08x ", i); c = len - i; if (c > 16) c = 16; @@ -213,8 +139,7 @@ DataRecord::dump(ostream &os) for (j = 0; j < c; j++) { int ch = data[i + j] & 0x7f; - ccprintf(os, - "%c", (char)(isprint(ch) ? ch : ' ')); + ccprintf(os, "%c", (char)(isprint(ch) ? ch : ' ')); } ccprintf(os, "\n"); @@ -223,126 +148,64 @@ DataRecord::dump(ostream &os) break; } } -} // namespace Trace -// -// Returns the current output stream for debug information. As a -// wrapper around Trace::dprintf_stream, this handles cases where debug -// information is generated in the process of parsing .ini options, -// before we process the option that sets up the debug output stream -// itself. -// -std::ostream & -DebugOut() -{ - return *Trace::dprintf_stream; -} - -///////////////////////////////////////////// -// -// C-linkage functions for invoking from gdb -// -///////////////////////////////////////////// - -// -// Dump trace buffer to specified file (cout if NULL) -// -void -dumpTrace(const char *filename) -{ - if (filename != NULL) { - ofstream out(filename); - Trace::theLog.dump(out); - out.close(); - } - else { - Trace::theLog.dump(cout); - } -} - - -// -// Turn on/off trace output to cerr. Typically used when trace output -// is only going to circular buffer, but you want to see what's being -// sent there as you step through some code in gdb. This uses the -// same facility as the "trace to file" feature, and will print error -// messages rather than clobbering an existing ostream pointer. -// -void -echoTrace(bool on) -{ - if (on) { - if (Trace::dprintf_stream != NULL) { - cerr << "Already echoing trace to a file... go do a 'tail -f'" - << " on that file instead." << endl; - } else { - Trace::dprintf_stream = &cerr; - } - } else { - if (Trace::dprintf_stream != &cerr) { - cerr << "Not echoing trace to cerr." << endl; - } else { - Trace::dprintf_stream = NULL; - } - } -} - -void -printTraceFlags() -{ - using namespace Trace; - for (int i = 0; i < numFlagStrings; ++i) - if (flags[i]) - cprintf("%s\n", flagStrings[i]); -} - -void -tweakTraceFlag(const char *string, bool value) +bool +changeFlag(const char *s, bool value) { using namespace Trace; - std::string str(string); + std::string str(s); for (int i = 0; i < numFlagStrings; ++i) { if (str != flagStrings[i]) continue; - int idx = i; - - if (idx < NumFlags) { - flags[idx] = value; + if (i < NumFlags) { + flags[i] = value; } else { - idx -= NumFlags; - if (idx >= NumCompoundFlags) { - ccprintf(cerr, "Invalid compound flag"); - return; - } - - const Flags *flagVec = compoundFlags[idx]; + i -= NumFlags; + const Flags *flagVec = compoundFlags[i]; for (int j = 0; flagVec[j] != -1; ++j) { - if (flagVec[j] >= NumFlags) { - ccprintf(cerr, "Invalid compound flag"); - return; - } - flags[flagVec[j]] = value; + if (flagVec[j] < NumFlags) + flags[flagVec[j]] = value; } } - cprintf("flag %s was %s\n", string, value ? "set" : "cleared"); - return; + return true; } - cprintf("could not find flag %s\n", string); + // the flag was not found. + return false; +} + +void +dumpStatus() +{ + using namespace Trace; + for (int i = 0; i < numFlagStrings; ++i) { + if (flags[i]) + cprintf("%s\n", flagStrings[i]); + } } +/* namespace Trace */ } + + +// add a set of functions that can easily be invoked from gdb void setTraceFlag(const char *string) { - tweakTraceFlag(string, true); + Trace::changeFlag(string, true); } void clearTraceFlag(const char *string) { - tweakTraceFlag(string, false); + Trace::changeFlag(string, false); +} + +void +dumpTraceStatus() +{ + Trace::dumpStatus(); } diff --git a/src/base/trace.hh b/src/base/trace.hh index a46643159..c1b506187 100644 --- a/src/base/trace.hh +++ b/src/base/trace.hh @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001-2005 The Regents of The University of Michigan + * Copyright (c) 2001-2006 The Regents of The University of Michigan * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -32,125 +32,35 @@ #ifndef __BASE_TRACE_HH__ #define __BASE_TRACE_HH__ +#include <string> #include <vector> #include "base/cprintf.hh" #include "base/match.hh" -#include "sim/host.hh" -#include "sim/root.hh" - #include "base/traceflags.hh" +#include "sim/host.hh" +#include "sim/core.hh" namespace Trace { - typedef std::vector<bool> FlagVec; +std::ostream &output(); +void setOutput(const std::string &filename); - extern FlagVec flags; +extern bool enabled; +typedef std::vector<bool> FlagVec; +extern FlagVec flags; +inline bool IsOn(int t) { return flags[t]; } +bool changeFlag(const char *str, bool value); +void dumpStatus(); -#if TRACING_ON - const bool On = true; -#else - const bool On = false; -#endif - - inline bool - IsOn(int t) - { - return flags[t]; - - } - - void dump(const uint8_t *data, int count); - - class Record - { - protected: - Tick cycle; - - Record(Tick _cycle) - : cycle(_cycle) - { - } - - public: - virtual ~Record() {} - - virtual void dump(std::ostream &) = 0; - }; - - class PrintfRecord : public Record - { - private: - const char *format; - const std::string &name; - cp::ArgList &args; - - public: - PrintfRecord(const char *_format, cp::ArgList &_args, - Tick cycle, const std::string &_name) - : Record(cycle), format(_format), name(_name), args(_args) - { - } - - virtual ~PrintfRecord(); - - virtual void dump(std::ostream &); - }; - - class DataRecord : public Record - { - private: - const std::string &name; - uint8_t *data; - int len; - - public: - DataRecord(Tick cycle, const std::string &name, - const void *_data, int _len); - virtual ~DataRecord(); - - virtual void dump(std::ostream &); - }; - - class Log - { - private: - int size; // number of records in log - Record **buffer; // array of 'size' Record ptrs (circular buf) - Record **nextRecPtr; // next slot to use in buffer - Record **wrapRecPtr; // &buffer[size], for quick wrap check - - public: - - Log(); - ~Log(); - - void init(int _size); - - void append(Record *); // append trace record to log - void dump(std::ostream &); // dump contents to stream - }; - - extern Log theLog; - - extern ObjectMatch ignore; - - inline void - dprintf(const char *format, cp::ArgList &args, Tick cycle, - const std::string &name) - { - if (name.empty() || !ignore.match(name)) - theLog.append(new Trace::PrintfRecord(format, args, cycle, name)); - } - - inline void - dataDump(Tick cycle, const std::string &name, const void *data, int len) - { - theLog.append(new Trace::DataRecord(cycle, name, data, len)); - } - - extern const std::string DefaultName; -}; +extern ObjectMatch ignore; +extern const std::string DefaultName; + +void dprintf(Tick when, const std::string &name, const char *format, + CPRINTF_DECLARATION); +void dump(Tick when, const std::string &name, const void *data, int len); + +/* namespace Trace */ } // This silly little class allows us to wrap a string in a functor // object so that we can give a name() that DPRINTF will like @@ -162,7 +72,6 @@ struct StringWrap }; inline const std::string &name() { return Trace::DefaultName; } -std::ostream &DebugOut(); // // DPRINTF is a debugging trace facility that allows one to @@ -176,50 +85,44 @@ std::ostream &DebugOut(); #if TRACING_ON -#define DTRACE(x) (Trace::IsOn(Trace::x)) - -#define DCOUT(x) if (Trace::IsOn(Trace::x)) DebugOut() +#define DTRACE(x) (Trace::IsOn(Trace::x) && Trace::enabled) -#define DDUMP(x, data, count) \ -do { \ - if (Trace::IsOn(Trace::x)) \ - Trace::dataDump(curTick, name(), data, count); \ +#define DDUMP(x, data, count) do { \ + if (DTRACE(x)) \ + Trace::dump(curTick, name(), data, count); \ } while (0) -#define __dprintf(cycle, name, format, ...) \ - Trace::dprintf(format, (*(new cp::ArgList), __VA_ARGS__), cycle, name) +#define DPRINTF(x, ...) do { \ + if (DTRACE(x)) \ + Trace::dprintf(curTick, name(), __VA_ARGS__); \ +} while (0) -#define DPRINTF(x, ...) \ -do { \ - if (Trace::IsOn(Trace::x)) \ - __dprintf(curTick, name(), __VA_ARGS__, cp::ArgListNull()); \ +#define DPRINTFR(x, ...) do { \ + if (DTRACE(x)) \ + Trace::dprintf((Tick)-1, std::string(), __VA_ARGS__); \ } while (0) -#define DPRINTFR(x, ...) \ -do { \ - if (Trace::IsOn(Trace::x)) \ - __dprintf((Tick)-1, std::string(), __VA_ARGS__, cp::ArgListNull()); \ +#define DDUMPN(data, count) do { \ + Trace::dump(curTick, name(), data, count); \ } while (0) -#define DPRINTFN(...) \ -do { \ - __dprintf(curTick, name(), __VA_ARGS__, cp::ArgListNull()); \ +#define DPRINTFN(...) do { \ + Trace::dprintf(curTick, name(), __VA_ARGS__); \ } while (0) -#define DPRINTFNR(...) \ -do { \ - __dprintf((Tick)-1, string(), __VA_ARGS__, cp::ArgListNull()); \ +#define DPRINTFNR(...) do { \ + Trace::dprintf((Tick)-1, string(), __VA_ARGS__); \ } while (0) #else // !TRACING_ON #define DTRACE(x) (false) -#define DCOUT(x) if (0) DebugOut() +#define DDUMP(x, data, count) do {} while (0) #define DPRINTF(x, ...) do {} while (0) #define DPRINTFR(...) do {} while (0) +#define DDUMPN(data, count) do {} while (0) #define DPRINTFN(...) do {} while (0) #define DPRINTFNR(...) do {} while (0) -#define DDUMP(x, data, count) do {} while (0) #endif // TRACING_ON diff --git a/src/base/traceflags.py b/src/base/traceflags.py index c06399f81..e57bfa350 100644 --- a/src/base/traceflags.py +++ b/src/base/traceflags.py @@ -29,19 +29,7 @@ # Authors: Nathan Binkert # Steve Reinhardt -# -# This file generates the header and source files for the flags -# that control the tracing facility. -# - -import sys - -if len(sys.argv) != 2: - print "%s: Need argument (basename of cc/hh files)" % sys.argv[0] - sys.exit(1) - -hhfilename = sys.argv[1] + '.hh' -ccfilename = sys.argv[1] + '.cc' +__all__ = [ 'allFlags', 'baseFlags', 'compoundFlagsMap', 'compoundFlags' ] # # The list of trace flags that can be used to condition DPRINTFs etc. @@ -89,6 +77,20 @@ baseFlags = [ 'EthernetPIO', 'EthernetSM', 'Event', + 'ExecEnable', + 'ExecCPSeq', + 'ExecEffAddr', + 'ExecFetchSeq', + 'ExecIntRegs', + 'ExecIntel', + 'ExecLegion', + 'ExecOpClass', + 'ExecRegDelta', + 'ExecResult', + 'ExecSpeculative', + 'ExecSymbol', + 'ExecThread', + 'ExecTicks', 'FE', 'Fault', 'Fetch', @@ -114,7 +116,7 @@ baseFlags = [ 'ISP', 'IdeCtrl', 'IdeDisk', - 'InstExec', + 'Iob', 'Interrupt', 'LLSC', 'LSQ', @@ -135,6 +137,7 @@ baseFlags = [ 'PciConfigAll', 'Pipeline', 'Printf', + 'Predecoder', 'Quiesce', 'ROB', 'Regs', @@ -167,6 +170,7 @@ baseFlags = [ 'VtoPhys', 'WriteBarrier', 'Writeback', + 'X86', ] # @@ -178,111 +182,119 @@ baseFlags = [ # following the existing examples. # compoundFlagMap = { - 'GDBAll' : [ 'GDBMisc', 'GDBAcc', 'GDBRead', 'GDBWrite', 'GDBSend', 'GDBRecv', 'GDBExtra' ], - 'ScsiAll' : [ 'ScsiDisk', 'ScsiCtrl', 'ScsiNone' ], - 'DiskImageAll' : [ 'DiskImage', 'DiskImageRead', 'DiskImageWrite' ], - 'EthernetAll' : [ 'Ethernet', 'EthernetPIO', 'EthernetDMA', 'EthernetData' , 'EthernetDesc', 'EthernetIntr', 'EthernetSM', 'EthernetCksum' ], - 'EthernetNoData' : [ 'Ethernet', 'EthernetPIO', 'EthernetDesc', 'EthernetIntr', 'EthernetSM', 'EthernetCksum' ], - 'IdeAll' : [ 'IdeCtrl', 'IdeDisk' ], - 'O3CPUAll' : [ 'Fetch', 'Decode', 'Rename', 'IEW', 'Commit', 'IQ', 'ROB', 'FreeList', 'RenameMap', 'LSQ', 'LSQUnit', 'StoreSet', 'MemDepUnit', 'DynInst', 'FullCPU', 'O3CPU', 'Activity','Scoreboard','Writeback'], - 'OzoneCPUAll' : [ 'BE', 'FE', 'IBE', 'OzoneLSQ', 'OzoneCPU'], - 'All' : baseFlags + 'All' : baseFlags, + 'DiskImageAll' : [ 'DiskImage', 'DiskImageRead', 'DiskImageWrite' ], + 'EthernetAll' : [ 'Ethernet', 'EthernetPIO', 'EthernetDMA', + 'EthernetData' , 'EthernetDesc', 'EthernetIntr', + 'EthernetSM', 'EthernetCksum' ], + 'EthernetNoData' : [ 'Ethernet', 'EthernetPIO', 'EthernetDesc', + 'EthernetIntr', 'EthernetSM', 'EthernetCksum' ], + 'Exec' : [ 'ExecEnable', 'ExecTicks', 'ExecOpClass', + 'ExecThread', 'ExecEffAddr', 'ExecResult', + 'ExecSymbol' ], + 'GDBAll' : [ 'GDBMisc', 'GDBAcc', 'GDBRead', 'GDBWrite', 'GDBSend', + 'GDBRecv', 'GDBExtra' ], + 'IdeAll' : [ 'IdeCtrl', 'IdeDisk' ], + 'O3CPUAll' : [ 'Fetch', 'Decode', 'Rename', 'IEW', 'Commit', 'IQ', + 'ROB', 'FreeList', 'RenameMap', 'LSQ', 'LSQUnit', + 'StoreSet', 'MemDepUnit', 'DynInst', 'FullCPU', + 'O3CPU', 'Activity','Scoreboard','Writeback' ], + 'OzoneCPUAll' : [ 'BE', 'FE', 'IBE', 'OzoneLSQ', 'OzoneCPU' ], + 'ScsiAll' : [ 'ScsiDisk', 'ScsiCtrl', 'ScsiNone' ] } -############################################################# -# -# Everything below this point generates the appropriate C++ -# declarations and definitions for the trace flags. If you are simply -# adding or modifying flag definitions, you should not have to change -# anything below. -# - -import sys - # extract just the compound flag names into a list compoundFlags = [] compoundFlags.extend(compoundFlagMap.keys()) compoundFlags.sort() -# -# First generate the header file. This defines the Flag enum -# and some extern declarations for the .cc file. -# -try: - hhfile = file(hhfilename, 'w') -except IOError, e: - sys.exit("can't open %s: %s" % (hhfilename, e)) - -# file header boilerplate -print >>hhfile, ''' -/* - * DO NOT EDIT THIS FILE! - * - * Automatically generated from traceflags.py - */ +allFlags = frozenset(baseFlags + compoundFlags) -#ifndef __BASE_TRACE_FLAGS_HH__ -#define __BASE_TRACE_FLAGS_HH__ - -namespace Trace { - -enum Flags { -''', - -# Generate the enum. Base flags come first, then compound flags. -idx = 0 -for flag in baseFlags: - print >>hhfile, ' %s = %d,' % (flag, idx) - idx += 1 - -numBaseFlags = idx -print >>hhfile, ' NumFlags = %d,' % idx - -# put a comment in here to separate base from compound flags -print >>hhfile, ''' - // The remaining enum values are *not* valid indices for Trace::flags. - // They are "compound" flags, which correspond to sets of base - // flags, and are used only by TraceParamContext::setFlags(). -''', - -for flag in compoundFlags: - print >>hhfile, ' %s = %d,' % (flag, idx) - idx += 1 - -numCompoundFlags = idx - numBaseFlags -print >>hhfile, ' NumCompoundFlags = %d' % numCompoundFlags - -# trailer boilerplate -print >>hhfile, '''\ -}; // enum Flags - -// Array of strings for SimpleEnumParam -extern const char *flagStrings[]; -extern const int numFlagStrings; - -// Array of arraay pointers: for each compound flag, gives the list of -// base flags to set. Inidividual flag arrays are terminated by -1. -extern const Flags *compoundFlags[]; - -/* namespace Trace */ } - -#endif // __BASE_TRACE_FLAGS_HH__ -''', - -hhfile.close() - -# -# -# Print out .cc file with array definitions. +############################################################# # +# Everything below this point generates the appropriate C++ +# declarations and definitions for the trace flags. If you are simply +# adding or modifying flag definitions, you should not have to change +# anything below. # -try: - ccfile = file(ccfilename, 'w') -except OSError, e: - sys.exit("can't open %s: %s" % (ccfilename, e)) - -# file header -print >>ccfile, ''' +def gen_hh(filename): + # + # First generate the header file. This defines the Flag enum + # and some extern declarations for the .cc file. + # + try: + hhfile = file(filename, 'w') + except IOError, e: + sys.exit("can't open %s: %s" % (hhfilename, e)) + + # file header boilerplate + print >>hhfile, ''' + /* + * DO NOT EDIT THIS FILE! + * + * Automatically generated from traceflags.py + */ + + #ifndef __BASE_TRACE_FLAGS_HH__ + #define __BASE_TRACE_FLAGS_HH__ + + namespace Trace { + + enum Flags { + ''', + + # Generate the enum. Base flags come first, then compound flags. + idx = 0 + for flag in baseFlags: + print >>hhfile, ' %s = %d,' % (flag, idx) + idx += 1 + + numBaseFlags = idx + print >>hhfile, ' NumFlags = %d,' % idx + + # put a comment in here to separate base from compound flags + print >>hhfile, ''' + // The remaining enum values are *not* valid indices for Trace::flags. + // They are "compound" flags, which correspond to sets of base + // flags, and are used by changeFlag. + ''', + + for flag in compoundFlags: + print >>hhfile, ' %s = %d,' % (flag, idx) + idx += 1 + + numCompoundFlags = idx - numBaseFlags + print >>hhfile, ' NumCompoundFlags = %d' % numCompoundFlags + + # trailer boilerplate + print >>hhfile, '''\ + }; // enum Flags + + // Array of strings for SimpleEnumParam + extern const char *flagStrings[]; + extern const int numFlagStrings; + + // Array of arraay pointers: for each compound flag, gives the list of + // base flags to set. Inidividual flag arrays are terminated by -1. + extern const Flags *compoundFlags[]; + + /* namespace Trace */ } + + #endif // __BASE_TRACE_FLAGS_HH__ + \n''', + + hhfile.close() + +def gen_cc(filename): + '''Print out .cc file with array definitions.''' + + try: + ccfile = file(filename, 'w') + except OSError, e: + sys.exit("can't open %s: %s" % (ccfilename, e)) + + # file header + print >>ccfile, ''' /* * DO NOT EDIT THIS FILE! * @@ -297,45 +309,57 @@ const char *Trace::flagStrings[] = { ''', -# The string array is used by SimpleEnumParam to map the strings -# provided by the user to enum values. -for flag in baseFlags: - print >>ccfile, ' "%s",' % flag + # The string array is used by SimpleEnumParam to map the strings + # provided by the user to enum values. + for flag in baseFlags: + print >>ccfile, ' "%s",' % flag -for flag in compoundFlags: - print >>ccfile, ' "%s",' % flag + for flag in compoundFlags: + print >>ccfile, ' "%s",' % flag -print >>ccfile, '};\n' + print >>ccfile, '};\n' -numFlagStrings = len(baseFlags) + len(compoundFlags); + numFlagStrings = len(baseFlags) + len(compoundFlags); -print >>ccfile, 'const int Trace::numFlagStrings = %d;' % numFlagStrings -print >>ccfile + print >>ccfile, 'const int Trace::numFlagStrings = %d;' % numFlagStrings + print >>ccfile -# -# Now define the individual compound flag arrays. There is an array -# for each compound flag listing the component base flags. -# + # + # Now define the individual compound flag arrays. There is an array + # for each compound flag listing the component base flags. + # -for flag in compoundFlags: - flags = compoundFlagMap[flag] - flags.append('(Flags)-1') - print >>ccfile, 'static const Flags %sMap[] =' % flag - print >>ccfile, '{ %s };' % (', '.join(flags)) - print >>ccfile + for flag in compoundFlags: + flags = compoundFlagMap[flag] + flags.append('(Flags)-1') + print >>ccfile, 'static const Flags %sMap[] =' % flag + print >>ccfile, '{ %s };' % (', '.join(flags)) + print >>ccfile -# -# Finally the compoundFlags[] array maps the compound flags -# to their individual arrays/ -# -print >>ccfile, 'const Flags *Trace::compoundFlags[] =' -print >>ccfile, '{' + # + # Finally the compoundFlags[] array maps the compound flags + # to their individual arrays/ + # + print >>ccfile, 'const Flags *Trace::compoundFlags[] =' + print >>ccfile, '{' + + for flag in compoundFlags: + print >>ccfile, ' %sMap,' % flag + + # file trailer + print >>ccfile, '};' + + ccfile.close() -for flag in compoundFlags: - print >>ccfile, ' %sMap,' % flag +if __name__ == '__main__': + # This file generates the header and source files for the flags + # that control the tracing facility. -# file trailer -print >>ccfile, '};' + import sys -ccfile.close() + if len(sys.argv) != 2: + print "%s: Need argument (basename of cc/hh files)" % sys.argv[0] + sys.exit(1) + gen_hh(sys.argv[1] + '.hh') + gen_cc(sys.argv[1] + '.cc') diff --git a/src/base/varargs.hh b/src/base/varargs.hh new file mode 100644 index 000000000..2ba8c240a --- /dev/null +++ b/src/base/varargs.hh @@ -0,0 +1,292 @@ +/* + * Copyright (c) 2006 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Nathan Binkert + */ + +#ifndef __BASE_VARARGS_HH__ +#define __BASE_VARARGS_HH__ + +#include "base/refcnt.hh" + +#define VARARGS_DECLARATION(receiver) \ + VarArgs::Argument<receiver> a01 = VarArgs::Null(), \ + VarArgs::Argument<receiver> a02 = VarArgs::Null(), \ + VarArgs::Argument<receiver> a03 = VarArgs::Null(), \ + VarArgs::Argument<receiver> a04 = VarArgs::Null(), \ + VarArgs::Argument<receiver> a05 = VarArgs::Null(), \ + VarArgs::Argument<receiver> a06 = VarArgs::Null(), \ + VarArgs::Argument<receiver> a07 = VarArgs::Null(), \ + VarArgs::Argument<receiver> a08 = VarArgs::Null(), \ + VarArgs::Argument<receiver> a09 = VarArgs::Null(), \ + VarArgs::Argument<receiver> a10 = VarArgs::Null(), \ + VarArgs::Argument<receiver> a11 = VarArgs::Null(), \ + VarArgs::Argument<receiver> a12 = VarArgs::Null(), \ + VarArgs::Argument<receiver> a13 = VarArgs::Null(), \ + VarArgs::Argument<receiver> a14 = VarArgs::Null(), \ + VarArgs::Argument<receiver> a15 = VarArgs::Null(), \ + VarArgs::Argument<receiver> a16 = VarArgs::Null() + +#define VARARGS_DEFINITION(receiver) \ + VarArgs::Argument<receiver> a01, \ + VarArgs::Argument<receiver> a02, \ + VarArgs::Argument<receiver> a03, \ + VarArgs::Argument<receiver> a04, \ + VarArgs::Argument<receiver> a05, \ + VarArgs::Argument<receiver> a06, \ + VarArgs::Argument<receiver> a07, \ + VarArgs::Argument<receiver> a08, \ + VarArgs::Argument<receiver> a09, \ + VarArgs::Argument<receiver> a10, \ + VarArgs::Argument<receiver> a11, \ + VarArgs::Argument<receiver> a12, \ + VarArgs::Argument<receiver> a13, \ + VarArgs::Argument<receiver> a14, \ + VarArgs::Argument<receiver> a15, \ + VarArgs::Argument<receiver> a16 + +#define VARARGS_ALLARGS \ + a01, a02, a03, a04, a05, a06, a07, a08, \ + a09, a10, a11, a12, a13, a14, a15, a16 + +#define VARARGS_ADDARGS(receiver) do { \ + do { \ + if (!a01) break; \ + a01.add_arg(receiver); \ + if (!a02) break; \ + a02.add_arg(receiver); \ + if (!a03) break; \ + a03.add_arg(receiver); \ + if (!a04) break; \ + a04.add_arg(receiver); \ + if (!a05) break; \ + a05.add_arg(receiver); \ + if (!a06) break; \ + a06.add_arg(receiver); \ + if (!a07) break; \ + a07.add_arg(receiver); \ + if (!a08) break; \ + a08.add_arg(receiver); \ + if (!a09) break; \ + a09.add_arg(receiver); \ + if (!a10) break; \ + a10.add_arg(receiver); \ + if (!a11) break; \ + a11.add_arg(receiver); \ + if (!a12) break; \ + a12.add_arg(receiver); \ + if (!a13) break; \ + a13.add_arg(receiver); \ + if (!a14) break; \ + a14.add_arg(receiver); \ + if (!a15) break; \ + a15.add_arg(receiver); \ + if (!a16) break; \ + a16.add_arg(receiver); \ + } while (0); \ + receiver.end_args(); \ +} while (0) + +namespace VarArgs { + +struct Null {}; + +template <typename T> +struct Traits +{ + enum { enabled = true }; +}; + +template <> +struct Traits<Null> +{ + enum { enabled = false }; +}; + +template <class RECV> +struct Base : public RefCounted +{ + virtual void add_arg(RECV &receiver) const = 0; +}; + +template <typename T, class RECV> +struct Any : public Base<RECV> +{ + const T &argument; + + Any(const T &arg) : argument(arg) {} + + virtual void + add_arg(RECV &receiver) const + { + receiver.add_arg(argument); + } +}; + +template <class RECV> +struct Argument : public RefCountingPtr<Base<RECV> > +{ + typedef RefCountingPtr<Base<RECV> > Base; + + Argument() { } + Argument(const Null &null) { } + template <typename T> + Argument(const T& arg) : Base(new Any<T, RECV>(arg)) { } + + void + add_arg(RECV &receiver) const + { + if (this->data) + this->data->add_arg(receiver); + } +}; + +template<class RECV> +class List +{ + public: + typedef Argument<RECV> Argument; + typedef std::list<Argument> list; + typedef typename list::iterator iterator; + typedef typename list::const_iterator const_iterator; + typedef typename list::size_type size_type; + + protected: + list l; + + public: + List() {} + List(Argument a01, Argument a02, Argument a03, Argument a04, + Argument a05, Argument a06, Argument a07, Argument a08, + Argument a09, Argument a10, Argument a11, Argument a12, + Argument a13, Argument a14, Argument a15, Argument a16) + { + if (!a01) return; + l.push_back(a01); + if (!a02) return; + l.push_back(a02); + if (!a03) return; + l.push_back(a03); + if (!a04) return; + l.push_back(a04); + if (!a05) return; + l.push_back(a05); + if (!a06) return; + l.push_back(a06); + if (!a07) return; + l.push_back(a07); + if (!a08) return; + l.push_back(a08); + if (!a09) return; + l.push_back(a09); + if (!a10) return; + l.push_back(a10); + if (!a11) return; + l.push_back(a11); + if (!a12) return; + l.push_back(a12); + if (!a13) return; + l.push_back(a13); + if (!a14) return; + l.push_back(a14); + if (!a15) return; + l.push_back(a15); + if (!a16) return; + l.push_back(a16); + } + + size_type size() const { return l.size(); } + bool empty() const { return l.empty(); } + + iterator begin() { return l.begin(); } + const_iterator begin() const { return l.begin(); } + + iterator end() { return l.end(); } + const_iterator end() const { return l.end(); } + + void + push_back(const Argument &arg) + { + if (arg) + l.push_back(arg); + } + + void + push_front(const Argument &arg) + { + if (arg) + l.push_front(arg); + } + + template <typename T> + void + push_back(const T &arg) + { + if (Traits<T>::enabled) + l.push_back(arg); + } + + template <typename T> + void + push_front(const T &arg) + { + if (Traits<T>::enabled) + l.push_front(arg); + } + + Argument& front() { return l.front(); } + const Argument& front() const { return l.front(); } + Argument& back() { return l.back(); } + const Argument& back() const { return l.back(); } + + void erase(iterator position) { return l.erase(position); } + void erase(iterator first, iterator last) { return l.erase(first, last); } + void clear() { return l.clear(); } + void pop_front() { return l.pop_front(); } + void pop_back() { return l.pop_back(); } + void reverse() { l.reverse(); } + + /* + * Functions specific to variable arguments + */ + void + add_args(RECV &recv) const + { + const_iterator i = l.begin(); + const_iterator end = l.end(); + while (i != end) { + i->add_arg(recv); + ++i; + } + + recv.end_args(); + } +}; + +/* end namespace VarArgs */ } + +#endif /* __BASE_VARARGS_HH__ */ |