diff options
67 files changed, 5619 insertions, 2713 deletions
@@ -1,4 +1,4 @@ -# Doxyfile 1.3.3 +# Doxyfile 1.3.6 # This file describes the settings to be used by the documentation system # doxygen (www.doxygen.org) for a project @@ -11,7 +11,7 @@ # Values that contain spaces should be placed between quotes (" ") #--------------------------------------------------------------------------- -# General configuration options +# Project related configuration options #--------------------------------------------------------------------------- # The PROJECT_NAME tag is a single word (or a sequence of words surrounded @@ -38,7 +38,7 @@ OUTPUT_DIRECTORY = docs/doxygen # The default language is English, other supported languages are: # Brazilian, Catalan, Chinese, Chinese-Traditional, Croatian, Czech, Danish, Dutch, # Finnish, French, German, Greek, Hungarian, Italian, Japanese, Japanese-en -# (Japanese with English messages), Korean, Norwegian, Polish, Portuguese, +# (Japanese with English messages), Korean, Korean-en, Norwegian, Polish, Portuguese, # Romanian, Russian, Serbian, Slovak, Slovene, Spanish, Swedish, and Ukrainian. OUTPUT_LANGUAGE = English @@ -53,6 +53,141 @@ OUTPUT_LANGUAGE = English USE_WINDOWS_ENCODING = NO +# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will +# include brief member descriptions after the members that are listed in +# the file and class documentation (similar to JavaDoc). +# Set to NO to disable this. + +BRIEF_MEMBER_DESC = YES + +# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend +# the brief description of a member or function before the detailed description. +# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the +# brief descriptions will be completely suppressed. + +REPEAT_BRIEF = YES + +# This tag implements a quasi-intelligent brief description abbreviator +# that is used to form the text in various listings. Each string +# in this list, if found as the leading text of the brief description, will be +# stripped from the text and the result after processing the whole list, is used +# as the annotated text. Otherwise, the brief description is used as-is. If left +# blank, the following values are used ("$name" is automatically replaced with the +# name of the entity): "The $name class" "The $name widget" "The $name file" +# "is" "provides" "specifies" "contains" "represents" "a" "an" "the" + +ABBREVIATE_BRIEF = + +# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then +# Doxygen will generate a detailed section even if there is only a brief +# description. + +ALWAYS_DETAILED_SEC = YES + +# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all inherited +# members of a class in the documentation of that class as if those members were +# ordinary class members. Constructors, destructors and assignment operators of +# the base classes will not be shown. + +INLINE_INHERITED_MEMB = NO + +# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full +# path before files name in the file list and in the header files. If set +# to NO the shortest path that makes the file name unique will be used. + +FULL_PATH_NAMES = YES + +# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag +# can be used to strip a user-defined part of the path. Stripping is +# only done if one of the specified strings matches the left-hand part of +# the path. It is allowed to use relative paths in the argument list. +# If left blank the directory from which doxygen is run is used as the +# path to strip. + +STRIP_FROM_PATH = . + +# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter +# (but less readable) file names. This can be useful is your file systems +# doesn't support long names like on DOS, Mac, or CD-ROM. + +SHORT_NAMES = NO + +# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen +# will interpret the first line (until the first dot) of a JavaDoc-style +# comment as the brief description. If set to NO, the JavaDoc +# comments will behave just like the Qt-style comments (thus requiring an +# explicit @brief command for a brief description. + +JAVADOC_AUTOBRIEF = YES + +# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen +# treat a multi-line C++ special comment block (i.e. a block of //! or /// +# comments) as a brief description. This used to be the default behaviour. +# The new default is to treat a multi-line C++ comment block as a detailed +# description. Set this tag to YES if you prefer the old behaviour instead. + +MULTILINE_CPP_IS_BRIEF = NO + +# If the DETAILS_AT_TOP tag is set to YES then Doxygen +# will output the detailed description near the top, like JavaDoc. +# If set to NO, the detailed description appears after the member +# documentation. + +DETAILS_AT_TOP = NO + +# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented +# member inherits the documentation from any documented member that it +# re-implements. + +INHERIT_DOCS = YES + +# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC +# tag is set to YES, then doxygen will reuse the documentation of the first +# member in the group (if any) for the other members of the group. By default +# all members of a group must be documented explicitly. + +DISTRIBUTE_GROUP_DOC = NO + +# The TAB_SIZE tag can be used to set the number of spaces in a tab. +# Doxygen uses this value to replace tabs by spaces in code fragments. + +TAB_SIZE = 8 + +# This tag can be used to specify a number of aliases that acts +# as commands in the documentation. An alias has the form "name=value". +# For example adding "sideeffect=\par Side Effects:\n" will allow you to +# put the command \sideeffect (or @sideeffect) in the documentation, which +# will result in a user-defined paragraph with heading "Side Effects:". +# You can put \n's in the value part of an alias to insert newlines. + +ALIASES = + +# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources +# only. Doxygen will then generate output that is more tailored for C. +# For instance, some of the names that are used will be different. The list +# of all members will be omitted, etc. + +OPTIMIZE_OUTPUT_FOR_C = NO + +# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java sources +# only. Doxygen will then generate output that is more tailored for Java. +# For instance, namespaces will be presented as packages, qualified scopes +# will look different, etc. + +OPTIMIZE_OUTPUT_JAVA = NO + +# Set the SUBGROUPING tag to YES (the default) to allow class member groups of +# the same type (for instance a group of public functions) to be put as a +# subgroup of that type (e.g. under the Public Functions section). Set it to +# NO to prevent subgrouping. Alternatively, this can be done per class using +# the \nosubgrouping command. + +SUBGROUPING = YES + +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- + # If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in # documentation are documented, even if no documentation was available. # Private class members and static file members will be hidden unless @@ -105,46 +240,6 @@ HIDE_FRIEND_COMPOUNDS = NO HIDE_IN_BODY_DOCS = NO -# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will -# include brief member descriptions after the members that are listed in -# the file and class documentation (similar to JavaDoc). -# Set to NO to disable this. - -BRIEF_MEMBER_DESC = YES - -# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend -# the brief description of a member or function before the detailed description. -# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the -# brief descriptions will be completely suppressed. - -REPEAT_BRIEF = YES - -# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then -# Doxygen will generate a detailed section even if there is only a brief -# description. - -ALWAYS_DETAILED_SEC = YES - -# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all inherited -# members of a class in the documentation of that class as if those members were -# ordinary class members. Constructors, destructors and assignment operators of -# the base classes will not be shown. - -INLINE_INHERITED_MEMB = NO - -# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full -# path before files name in the file list and in the header files. If set -# to NO the shortest path that makes the file name unique will be used. - -FULL_PATH_NAMES = YES - -# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag -# can be used to strip a user-defined part of the path. Stripping is -# only done if one of the specified strings matches the left-hand part of -# the path. It is allowed to use relative paths in the argument list. - -STRIP_FROM_PATH = . - # The INTERNAL_DOCS tag determines if documentation # that is typed after a \internal command is included. If the tag is set # to NO (the default) then the documentation will be excluded. @@ -160,12 +255,6 @@ INTERNAL_DOCS = NO CASE_SENSE_NAMES = YES -# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter -# (but less readable) file names. This can be useful is your file systems -# doesn't support long names like on DOS, Mac, or CD-ROM. - -SHORT_NAMES = NO - # If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen # will show members with their full class and namespace scopes in the # documentation. If set to YES the scope will be hidden. @@ -178,35 +267,6 @@ HIDE_SCOPE_NAMES = NO SHOW_INCLUDE_FILES = YES -# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen -# will interpret the first line (until the first dot) of a JavaDoc-style -# comment as the brief description. If set to NO, the JavaDoc -# comments will behave just like the Qt-style comments (thus requiring an -# explict @brief command for a brief description. - -JAVADOC_AUTOBRIEF = YES - -# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen -# treat a multi-line C++ special comment block (i.e. a block of //! or /// -# comments) as a brief description. This used to be the default behaviour. -# The new default is to treat a multi-line C++ comment block as a detailed -# description. Set this tag to YES if you prefer the old behaviour instead. - -MULTILINE_CPP_IS_BRIEF = NO - -# If the DETAILS_AT_TOP tag is set to YES then Doxygen -# will output the detailed description near the top, like JavaDoc. -# If set to NO, the detailed description appears after the member -# documentation. - -DETAILS_AT_TOP = NO - -# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented -# member inherits the documentation from any documented member that it -# reimplements. - -INHERIT_DOCS = YES - # If the INLINE_INFO tag is set to YES (the default) then a tag [inline] # is inserted in the documentation for inline members. @@ -219,17 +279,22 @@ INLINE_INFO = YES SORT_MEMBER_DOCS = YES -# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC -# tag is set to YES, then doxygen will reuse the documentation of the first -# member in the group (if any) for the other members of the group. By default -# all members of a group must be documented explicitly. +# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the +# brief documentation of file, namespace and class members alphabetically +# by member name. If set to NO (the default) the members will appear in +# declaration order. -DISTRIBUTE_GROUP_DOC = NO +SORT_BRIEF_DOCS = NO -# The TAB_SIZE tag can be used to set the number of spaces in a tab. -# Doxygen uses this value to replace tabs by spaces in code fragments. +# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be +# sorted by fully-qualified names, including namespaces. If set to +# NO (the default), the class list will be sorted only by class name, +# not including the namespace part. +# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. +# Note: This option applies only to the class list, not to the +# alphabetical list. -TAB_SIZE = 8 +SORT_BY_SCOPE_NAME = NO # The GENERATE_TODOLIST tag can be used to enable (YES) or # disable (NO) the todo list. This list is created by putting \todo @@ -255,15 +320,6 @@ GENERATE_BUGLIST = YES GENERATE_DEPRECATEDLIST= YES -# This tag can be used to specify a number of aliases that acts -# as commands in the documentation. An alias has the form "name=value". -# For example adding "sideeffect=\par Side Effects:\n" will allow you to -# put the command \sideeffect (or @sideeffect) in the documentation, which -# will result in a user-defined paragraph with heading "Side Effects:". -# You can put \n's in the value part of an alias to insert newlines. - -ALIASES = - # The ENABLED_SECTIONS tag can be used to enable conditional # documentation sections, marked by \if sectionname ... \endif. @@ -279,34 +335,12 @@ ENABLED_SECTIONS = MAX_INITIALIZER_LINES = 30 -# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources -# only. Doxygen will then generate output that is more tailored for C. -# For instance, some of the names that are used will be different. The list -# of all members will be omitted, etc. - -OPTIMIZE_OUTPUT_FOR_C = NO - -# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java sources -# only. Doxygen will then generate output that is more tailored for Java. -# For instance, namespaces will be presented as packages, qualified scopes -# will look different, etc. - -OPTIMIZE_OUTPUT_JAVA = NO - # Set the SHOW_USED_FILES tag to NO to disable the list of files generated # at the bottom of the documentation of classes and structs. If set to YES the # list will mention the files that were used to generate the documentation. SHOW_USED_FILES = YES -# Set the SUBGROUPING tag to YES (the default) to allow class member groups of -# the same type (for instance a group of public functions) to be put as a -# subgroup of that type (e.g. under the Public Functions section). Set it to -# NO to prevent subgrouping. Alternatively, this can be done per class using -# the \nosubgrouping command. - -SUBGROUPING = YES - #--------------------------------------------------------------------------- # configuration options related to warning and progress messages #--------------------------------------------------------------------------- @@ -346,7 +380,7 @@ WARN_FORMAT = "$file:$line: $text" # and error messages should be written. If left blank the output is written # to stderr. -WARN_LOGFILE = +WARN_LOGFILE = #--------------------------------------------------------------------------- # configuration options related to the input files @@ -364,9 +398,13 @@ INPUT = . # and *.h) to filter out the source-files in the directories. If left # blank the following patterns are tested: # *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx *.hpp -# *.h++ *.idl *.odl *.cs +# *.h++ *.idl *.odl *.cs *.php *.php3 *.inc -FILE_PATTERNS = *.c *.cc *.h *.hh *.doxygen +FILE_PATTERNS = *.c \ + *.cc \ + *.h \ + *.hh \ + *.doxygen # The RECURSIVE tag can be used to turn specify whether or not subdirectories # should be searched for input files as well. Possible values are YES and NO. @@ -378,7 +416,11 @@ RECURSIVE = YES # excluded from the INPUT source files. This way you can easily exclude a # subdirectory from a directory tree whose root is specified with the INPUT tag. -EXCLUDE = build configs setup PENDING RESYNC +EXCLUDE = build \ + configs \ + setup \ + PENDING \ + RESYNC # The EXCLUDE_SYMLINKS tag can be used select whether or not files or directories # that are symbolic links (a Unix filesystem feature) are excluded from the input. @@ -389,7 +431,9 @@ EXCLUDE_SYMLINKS = YES # EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude # certain files from those directories. -EXCLUDE_PATTERNS = */BitKeeper/* */Attic/* */SCCS/* +EXCLUDE_PATTERNS = */BitKeeper/* \ + */Attic/* \ + */SCCS/* # The EXAMPLE_PATH tag can be used to specify one or more files or # directories that contain example code fragments that are included (see @@ -437,7 +481,9 @@ FILTER_SOURCE_FILES = NO #--------------------------------------------------------------------------- # If the SOURCE_BROWSER tag is set to YES then a list of source files will -# be generated. Documented entities will be cross-referenced with these sources. +# be generated. Documented entities will be cross-referenced with these sources. +# Note: To get rid of all source code in the generated output, make sure also +# VERBATIM_HEADERS is set to NO. SOURCE_BROWSER = YES @@ -529,7 +575,9 @@ HTML_FOOTER = docs/footer.html # The HTML_STYLESHEET tag can be used to specify a user-defined cascading # style sheet that is used by each HTML page. It can be used to # fine-tune the look of the HTML output. If the tag is left blank doxygen -# will generate a default style sheet +# will generate a default style sheet. Note that doxygen will try to copy +# the style sheet file to the HTML output directory, so don't put your own +# stylesheet in the HTML output directory as well, or it will be erased! HTML_STYLESHEET = @@ -549,7 +597,7 @@ GENERATE_HTMLHELP = NO # If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can # be used to specify the file name of the resulting .chm file. You # can add a path in front of the file if the result should not be -# written to the html output dir. +# written to the html output directory. CHM_FILE = @@ -684,7 +732,7 @@ LATEX_HIDE_INDICES = NO #--------------------------------------------------------------------------- # If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output -# The RTF output is optimised for Word 97 and may not look very pretty with +# The RTF output is optimized for Word 97 and may not look very pretty with # other RTF readers or editors. GENERATE_RTF = NO @@ -711,7 +759,7 @@ COMPACT_RTF = NO RTF_HYPERLINKS = NO # Load stylesheet definitions from file. Syntax is similar to doxygen's -# config file, i.e. a series of assigments. You only have to provide +# config file, i.e. a series of assignments. You only have to provide # replacements, missing definitions are set to their default value. RTF_STYLESHEET_FILE = @@ -755,9 +803,7 @@ MAN_LINKS = NO # If the GENERATE_XML tag is set to YES Doxygen will # generate an XML file that captures the structure of -# the code including all documentation. Note that this -# feature is still experimental and incomplete at the -# moment. +# the code including all documentation. GENERATE_XML = NO @@ -779,6 +825,13 @@ XML_SCHEMA = XML_DTD = +# If the XML_PROGRAMLISTING tag is set to YES Doxygen will +# dump the program listings (including syntax highlighting +# and cross-referencing information) to the XML output. Note that +# enabling this will significantly increase the size of the XML output. + +XML_PROGRAMLISTING = YES + #--------------------------------------------------------------------------- # configuration options for the AutoGen Definitions output #--------------------------------------------------------------------------- @@ -889,7 +942,7 @@ EXPAND_AS_DEFINED = SKIP_FUNCTION_MACROS = YES #--------------------------------------------------------------------------- -# Configuration::addtions related to external references +# Configuration::additions related to external references #--------------------------------------------------------------------------- # The TAGFILES option can be used to specify one or more tagfiles. @@ -938,7 +991,7 @@ PERL_PATH = /usr/bin/perl # If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will # generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base or # super classes. Setting the tag to NO turns the diagrams off. Note that this -# option is superceded by the HAVE_DOT option below. This is only a fallback. It is +# option is superseded by the HAVE_DOT option below. This is only a fallback. It is # recommended to install and use dot, since it yields more powerful graphs. CLASS_DIAGRAMS = YES @@ -971,7 +1024,7 @@ CLASS_GRAPH = YES COLLABORATION_GRAPH = YES # If the UML_LOOK tag is set to YES doxygen will generate inheritance and -# collaboration diagrams in a style similiar to the OMG's Unified Modeling +# collaboration diagrams in a style similar to the OMG's Unified Modeling # Language. UML_LOOK = NO @@ -1065,45 +1118,10 @@ GENERATE_LEGEND = YES DOT_CLEANUP = YES #--------------------------------------------------------------------------- -# Configuration::addtions related to the search engine +# Configuration::additions related to the search engine #--------------------------------------------------------------------------- # The SEARCHENGINE tag specifies whether or not a search engine should be # used. If set to NO the values of all tags below this one will be ignored. SEARCHENGINE = NO - -# The CGI_NAME tag should be the name of the CGI script that -# starts the search engine (doxysearch) with the correct parameters. -# A script with this name will be generated by doxygen. - -CGI_NAME = search.cgi - -# The CGI_URL tag should be the absolute URL to the directory where the -# cgi binaries are located. See the documentation of your http daemon for -# details. - -CGI_URL = - -# The DOC_URL tag should be the absolute URL to the directory where the -# documentation is located. If left blank the absolute path to the -# documentation, with file:// prepended to it, will be used. - -DOC_URL = - -# The DOC_ABSPATH tag should be the absolute path to the directory where the -# documentation is located. If left blank the directory on the local machine -# will be used. - -DOC_ABSPATH = - -# The BIN_ABSPATH tag must point to the directory where the doxysearch binary -# is installed. - -BIN_ABSPATH = /usr/local/bin/ - -# The EXT_DOC_PATHS tag can be used to specify one or more paths to -# documentation generated for other projects. This allows doxysearch to search -# the documentation for these projects as well. - -EXT_DOC_PATHS = diff --git a/arch/alpha/alpha_memory.cc b/arch/alpha/alpha_memory.cc index 4cd122431..63fb3ebcb 100644 --- a/arch/alpha/alpha_memory.cc +++ b/arch/alpha/alpha_memory.cc @@ -44,20 +44,14 @@ using namespace std; // // Alpha TLB // - -#ifdef DEBUG - bool uncacheBit39 = false; - bool uncacheBit40 = false; -#endif - -AlphaTlb::AlphaTlb(const string &name, int s) +AlphaTLB::AlphaTLB(const string &name, int s) : SimObject(name), size(s), nlu(0) { table = new AlphaISA::PTE[size]; memset(table, 0, sizeof(AlphaISA::PTE[size])); } -AlphaTlb::~AlphaTlb() +AlphaTLB::~AlphaTLB() { if (table) delete [] table; @@ -65,7 +59,7 @@ AlphaTlb::~AlphaTlb() // look up an entry in the TLB AlphaISA::PTE * -AlphaTlb::lookup(Addr vpn, uint8_t asn) const +AlphaTLB::lookup(Addr vpn, uint8_t asn) const { DPRINTF(TLB, "lookup %#x\n", vpn); @@ -89,7 +83,7 @@ AlphaTlb::lookup(Addr vpn, uint8_t asn) const void -AlphaTlb::checkCacheability(MemReqPtr &req) +AlphaTLB::checkCacheability(MemReqPtr &req) { // in Alpha, cacheability is controlled by upper-level bits of the // physical address @@ -135,7 +129,7 @@ AlphaTlb::checkCacheability(MemReqPtr &req) // insert a new TLB entry void -AlphaTlb::insert(Addr vaddr, AlphaISA::PTE &pte) +AlphaTLB::insert(Addr vaddr, AlphaISA::PTE &pte) { if (table[nlu].valid) { Addr oldvpn = table[nlu].tag; @@ -169,7 +163,7 @@ AlphaTlb::insert(Addr vaddr, AlphaISA::PTE &pte) } void -AlphaTlb::flushAll() +AlphaTLB::flushAll() { memset(table, 0, sizeof(AlphaISA::PTE[size])); lookupTable.clear(); @@ -177,7 +171,7 @@ AlphaTlb::flushAll() } void -AlphaTlb::flushProcesses() +AlphaTLB::flushProcesses() { PageTable::iterator i = lookupTable.begin(); PageTable::iterator end = lookupTable.end(); @@ -197,7 +191,7 @@ AlphaTlb::flushProcesses() } void -AlphaTlb::flushAddr(Addr vaddr, uint8_t asn) +AlphaTLB::flushAddr(Addr vaddr, uint8_t asn) { Addr vpn = VA_VPN(vaddr); @@ -225,7 +219,7 @@ AlphaTlb::flushAddr(Addr vaddr, uint8_t asn) void -AlphaTlb::serialize(ostream &os) +AlphaTLB::serialize(ostream &os) { SERIALIZE_SCALAR(size); SERIALIZE_SCALAR(nlu); @@ -237,7 +231,7 @@ AlphaTlb::serialize(ostream &os) } void -AlphaTlb::unserialize(Checkpoint *cp, const string §ion) +AlphaTLB::unserialize(Checkpoint *cp, const string §ion) { UNSERIALIZE_SCALAR(size); UNSERIALIZE_SCALAR(nlu); @@ -255,13 +249,13 @@ AlphaTlb::unserialize(Checkpoint *cp, const string §ion) // // Alpha ITB // -AlphaItb::AlphaItb(const std::string &name, int size) - : AlphaTlb(name, size) +AlphaITB::AlphaITB(const std::string &name, int size) + : AlphaTLB(name, size) {} void -AlphaItb::regStats() +AlphaITB::regStats() { hits .name(name() + ".hits") @@ -280,7 +274,7 @@ AlphaItb::regStats() } void -AlphaItb::fault(Addr pc, ExecContext *xc) const +AlphaITB::fault(Addr pc, ExecContext *xc) const { uint64_t *ipr = xc->regs.ipr; @@ -293,7 +287,7 @@ AlphaItb::fault(Addr pc, ExecContext *xc) const Fault -AlphaItb::translate(MemReqPtr &req) const +AlphaITB::translate(MemReqPtr &req) const { InternalProcReg *ipr = req->xc->regs.ipr; @@ -311,7 +305,7 @@ AlphaItb::translate(MemReqPtr &req) const if (!validVirtualAddress(req->vaddr)) { fault(req->vaddr, req->xc); acv++; - return Itb_Acv_Fault; + return ITB_Acv_Fault; } // Check for "superpage" mapping: when SP<1> is set, and @@ -373,12 +367,12 @@ AlphaItb::translate(MemReqPtr &req) const // // Alpha DTB // -AlphaDtb::AlphaDtb(const std::string &name, int size) - : AlphaTlb(name, size) +AlphaDTB::AlphaDTB(const std::string &name, int size) + : AlphaTLB(name, size) {} void -AlphaDtb::regStats() +AlphaDTB::regStats() { read_hits .name(name() + ".read_hits") @@ -447,7 +441,7 @@ AlphaDtb::regStats() } void -AlphaDtb::fault(Addr vaddr, uint64_t flags, ExecContext *xc) const +AlphaDTB::fault(Addr vaddr, uint64_t flags, ExecContext *xc) const { uint64_t *ipr = xc->regs.ipr; @@ -471,7 +465,7 @@ AlphaDtb::fault(Addr vaddr, uint64_t flags, ExecContext *xc) const } Fault -AlphaDtb::translate(MemReqPtr &req, bool write) const +AlphaDTB::translate(MemReqPtr &req, bool write) const { RegFile *regs = &req->xc->regs; Addr pc = regs->pc; @@ -497,7 +491,7 @@ AlphaDtb::translate(MemReqPtr &req, bool write) const req->xc); if (write) { write_acv++; } else { read_acv++; } - return Dtb_Fault_Fault; + return DTB_Fault_Fault; } // Check for "superpage" mapping: when SP<1> is set, and @@ -593,7 +587,7 @@ AlphaDtb::translate(MemReqPtr &req, bool write) const } AlphaISA::PTE & -AlphaTlb::index(bool advance) +AlphaTLB::index(bool advance) { AlphaISA::PTE *pte = &table[nlu]; @@ -603,43 +597,45 @@ AlphaTlb::index(bool advance) return *pte; } -BEGIN_DECLARE_SIM_OBJECT_PARAMS(AlphaItb) +DEFINE_SIM_OBJECT_CLASS_NAME("AlphaTLB", AlphaTLB) + +BEGIN_DECLARE_SIM_OBJECT_PARAMS(AlphaITB) Param<int> size; -END_DECLARE_SIM_OBJECT_PARAMS(AlphaItb) +END_DECLARE_SIM_OBJECT_PARAMS(AlphaITB) -BEGIN_INIT_SIM_OBJECT_PARAMS(AlphaItb) +BEGIN_INIT_SIM_OBJECT_PARAMS(AlphaITB) INIT_PARAM_DFLT(size, "TLB size", 48) -END_INIT_SIM_OBJECT_PARAMS(AlphaItb) +END_INIT_SIM_OBJECT_PARAMS(AlphaITB) -CREATE_SIM_OBJECT(AlphaItb) +CREATE_SIM_OBJECT(AlphaITB) { - return new AlphaItb(getInstanceName(), size); + return new AlphaITB(getInstanceName(), size); } -REGISTER_SIM_OBJECT("AlphaITB", AlphaItb) +REGISTER_SIM_OBJECT("AlphaITB", AlphaITB) -BEGIN_DECLARE_SIM_OBJECT_PARAMS(AlphaDtb) +BEGIN_DECLARE_SIM_OBJECT_PARAMS(AlphaDTB) Param<int> size; -END_DECLARE_SIM_OBJECT_PARAMS(AlphaDtb) +END_DECLARE_SIM_OBJECT_PARAMS(AlphaDTB) -BEGIN_INIT_SIM_OBJECT_PARAMS(AlphaDtb) +BEGIN_INIT_SIM_OBJECT_PARAMS(AlphaDTB) INIT_PARAM_DFLT(size, "TLB size", 64) -END_INIT_SIM_OBJECT_PARAMS(AlphaDtb) +END_INIT_SIM_OBJECT_PARAMS(AlphaDTB) -CREATE_SIM_OBJECT(AlphaDtb) +CREATE_SIM_OBJECT(AlphaDTB) { - return new AlphaDtb(getInstanceName(), size); + return new AlphaDTB(getInstanceName(), size); } -REGISTER_SIM_OBJECT("AlphaDTB", AlphaDtb) +REGISTER_SIM_OBJECT("AlphaDTB", AlphaDTB) diff --git a/arch/alpha/alpha_memory.hh b/arch/alpha/alpha_memory.hh index 999eec228..12196c44b 100644 --- a/arch/alpha/alpha_memory.hh +++ b/arch/alpha/alpha_memory.hh @@ -37,7 +37,7 @@ class ExecContext; -class AlphaTlb : public SimObject +class AlphaTLB : public SimObject { protected: typedef std::multimap<Addr, int> PageTable; @@ -51,8 +51,8 @@ class AlphaTlb : public SimObject AlphaISA::PTE *lookup(Addr vpn, uint8_t asn) const; public: - AlphaTlb(const std::string &name, int size); - virtual ~AlphaTlb(); + AlphaTLB(const std::string &name, int size); + virtual ~AlphaTLB(); int getsize() const { return size; } @@ -77,7 +77,7 @@ class AlphaTlb : public SimObject virtual void unserialize(Checkpoint *cp, const std::string §ion); }; -class AlphaItb : public AlphaTlb +class AlphaITB : public AlphaTLB { protected: mutable Statistics::Scalar<> hits; @@ -89,13 +89,13 @@ class AlphaItb : public AlphaTlb void fault(Addr pc, ExecContext *xc) const; public: - AlphaItb(const std::string &name, int size); + AlphaITB(const std::string &name, int size); virtual void regStats(); Fault translate(MemReqPtr &req) const; }; -class AlphaDtb : public AlphaTlb +class AlphaDTB : public AlphaTLB { protected: mutable Statistics::Scalar<> read_hits; @@ -115,7 +115,7 @@ class AlphaDtb : public AlphaTlb void fault(Addr pc, uint64_t flags, ExecContext *xc) const; public: - AlphaDtb(const std::string &name, int size); + AlphaDTB(const std::string &name, int size); virtual void regStats(); Fault translate(MemReqPtr &req, bool write) const; diff --git a/arch/alpha/ev5.cc b/arch/alpha/ev5.cc index 551cbdabf..9b3ac5fff 100644 --- a/arch/alpha/ev5.cc +++ b/arch/alpha/ev5.cc @@ -68,11 +68,11 @@ AlphaISA::fault_addr[Num_Faults] = { 0x0201, /* Ndtb_Miss_Fault */ 0x0281, /* Pdtb_Miss_Fault */ 0x0301, /* Alignment_Fault */ - 0x0381, /* Dtb_Fault_Fault */ - 0x0381, /* Dtb_Acv_Fault */ - 0x0181, /* Itb_Miss_Fault */ - 0x0181, /* Itb_Fault_Fault */ - 0x0081, /* Itb_Acv_Fault */ + 0x0381, /* DTB_Fault_Fault */ + 0x0381, /* DTB_Acv_Fault */ + 0x0181, /* ITB_Miss_Fault */ + 0x0181, /* ITB_Fault_Fault */ + 0x0081, /* ITB_Acv_Fault */ 0x0481, /* Unimplemented_Opcode_Fault */ 0x0581, /* Fen_Fault */ 0x2001, /* Pal_Fault */ diff --git a/arch/alpha/faults.hh b/arch/alpha/faults.hh index bc8a4da0e..33aa55439 100644 --- a/arch/alpha/faults.hh +++ b/arch/alpha/faults.hh @@ -38,11 +38,11 @@ enum Fault { Ndtb_Miss_Fault, // DTB miss Pdtb_Miss_Fault, // nested DTB miss Alignment_Fault, // unaligned access - Dtb_Fault_Fault, // DTB page fault - Dtb_Acv_Fault, // DTB access violation - Itb_Miss_Fault, // ITB miss - Itb_Fault_Fault, // ITB page fault - Itb_Acv_Fault, // ITB access violation + DTB_Fault_Fault, // DTB page fault + DTB_Acv_Fault, // DTB access violation + ITB_Miss_Fault, // ITB miss + ITB_Fault_Fault, // ITB page fault + ITB_Acv_Fault, // ITB access violation Unimplemented_Opcode_Fault, // invalid/unimplemented instruction Fen_Fault, // FP not-enabled fault Pal_Fault, // call_pal S/W interrupt diff --git a/arch/alpha/isa_desc b/arch/alpha/isa_desc index 0da087f97..0d1e7138f 100644 --- a/arch/alpha/isa_desc +++ b/arch/alpha/isa_desc @@ -5,7 +5,7 @@ let {{ global rcs_id - rcs_id = "$Id: s.isa_desc 1.43 04/02/29 22:41:10-05:00 ehallnor@zazzer.eecs.umich.edu $" + rcs_id = "$Id$" }}; @@ -22,9 +22,7 @@ let {{ #include "base/misc.hh" #include "cpu/exec_context.hh" #include "cpu/exetrace.hh" -#include "cpu/full_cpu/full_cpu.hh" -#include "cpu/full_cpu/op_class.hh" -#include "cpu/full_cpu/spec_state.hh" +#include "cpu/full_cpu/dyn_inst.hh" #include "cpu/simple_cpu/simple_cpu.hh" #include "cpu/static_inst.hh" #include "sim/annotation.hh" @@ -143,7 +141,8 @@ declare {{ /// @retval Full-system mode: No_Fault if FP is enabled, Fen_Fault /// if not. Non-full-system mode: always returns No_Fault. #ifdef FULL_SYSTEM - inline Fault checkFpEnableFault(ExecContext *xc) + template <class XC> + inline Fault checkFpEnableFault(XC *xc) { Fault fault = No_Fault; // dummy... this ipr access should not fault if (!ICSR_FPE(xc->readIpr(AlphaISA::IPR_ICSR, fault))) { @@ -152,7 +151,8 @@ declare {{ return fault; } #else - inline Fault checkFpEnableFault(ExecContext *xc) + template <class XC> + inline Fault checkFpEnableFault(XC *xc) { return No_Fault; } @@ -239,42 +239,27 @@ def template BasicDeclare {{ %(constructor)s; } - Fault execute(SimpleCPU *cpu, ExecContext *xc, - Trace::InstRecord *traceData) - { - SimpleCPU *memAccessObj __attribute__((unused)) = cpu; - Fault fault = No_Fault; + %(exec_func_declarations)s + }; +}}; - %(fp_enable_check)s; - %(exec_decl)s; - %(simple_rd)s; - %(code)s; +def template BasicExecute {{ + Fault %(class_name)s::execute(%(cpu_model)s *xc, + Trace::InstRecord *traceData) + { + Fault fault = No_Fault; - if (fault == No_Fault) { - %(simple_wb)s; - } + %(fp_enable_check)s; + %(op_decl)s; + %(op_rd)s; + %(code)s; - return fault; + if (fault == No_Fault) { + %(op_wb)s; } - Fault execute(FullCPU *cpu, SpecExecContext *xc, DynInst *dynInst, - Trace::InstRecord *traceData) - { - DynInst *memAccessObj __attribute__((unused)) = dynInst; - Fault fault = No_Fault; - - %(fp_enable_check)s; - %(exec_decl)s; - %(dtld_rd)s; - %(code)s; - - if (fault == No_Fault) { - %(dtld_wb)s; - } - - return fault; - } - }; + return fault; + } }}; def template BasicDecode {{ @@ -288,7 +273,7 @@ def template BasicDecodeWithMnemonic {{ // The most basic instruction format... used only for a few misc. insts def format BasicOperate(code, *flags) {{ iop = InstObjParams(name, Name, 'AlphaStaticInst', CodeBlock(code), flags) - return iop.subst('BasicDeclare', 'BasicDecode') + return iop.subst('BasicDeclare', 'BasicDecode', 'BasicExecute') }}; @@ -315,18 +300,6 @@ declare {{ ~Nop() { } - Fault execute(SimpleCPU *cpu, ExecContext *xc, - Trace::InstRecord *traceData) - { - return No_Fault; - } - - Fault execute(FullCPU *cpu, SpecExecContext *xc, DynInst *dynInst, - Trace::InstRecord *traceData) - { - return No_Fault; - } - std::string generateDisassembly(Addr pc, const SymbolTable *symtab) { #ifdef SS_COMPATIBLE_DISASSEMBLY @@ -335,6 +308,12 @@ declare {{ return csprintf("%-10s (%s)", "nop", originalDisassembly); #endif } + + Fault execute(SimpleCPUExecContext *, Trace::InstRecord *) + { return No_Fault; } + + Fault execute(FullCPUExecContext *, Trace::InstRecord *) + { return No_Fault; } }; /// Helper function for decoding nops. Substitute Nop object @@ -350,7 +329,7 @@ declare {{ }}; def format Nop() {{ - return ('', 'return new Nop("%s", machInst);\n' % name) + return ('', 'return new Nop("%s", machInst);\n' % name, 'return No_Fault;') }}; @@ -370,7 +349,7 @@ def template OperateNopCheckDecode {{ def format BasicOperateWithNopCheck(code, *opt_args) {{ iop = InstObjParams(name, Name, 'AlphaStaticInst', CodeBlock(code), opt_args) - return iop.subst('BasicDeclare', 'OperateNopCheckDecode') + return iop.subst('BasicDeclare', 'OperateNopCheckDecode', 'BasicExecute') }}; @@ -454,21 +433,24 @@ def format IntegerOperate(code, *opt_flags) {{ # generate declaration for register version cblk = CodeBlock(code) iop = InstObjParams(name, Name, 'AlphaStaticInst', cblk, opt_flags) - decls = iop.subst('BasicDeclare') + (decls, exec_code) = iop.subst('BasicDeclare', 'BasicExecute') if uses_imm: # append declaration for imm version imm_cblk = CodeBlock(imm_code) imm_iop = InstObjParams(name, Name + 'Imm', 'IntegerImm', imm_cblk, opt_flags) - decls += imm_iop.subst('BasicDeclare') + (imm_decls, imm_exec_code) = \ + imm_iop.subst('BasicDeclare', 'BasicExecute') + decls += imm_decls + exec_code += imm_exec_code # decode checks IMM bit to pick correct version decode = iop.subst('RegOrImmDecode') else: # no imm version: just check for nop decode = iop.subst('OperateNopCheckDecode') - return (decls, decode) + return (decls, decode, exec_code) }}; @@ -544,10 +526,10 @@ declare {{ #if defined(linux) int - getC99RoundingMode(ExecContext *xc) + getC99RoundingMode(uint64_t fpcr_val) { if (roundingMode == Dynamic) { - return alphaToC99RoundingMode[bits(xc->readFpcr(), 59, 58)]; + return alphaToC99RoundingMode[bits(fpcr_val, 59, 58)]; } else { return alphaToC99RoundingMode[roundingMode]; @@ -618,124 +600,6 @@ declare {{ }}; -def template FloatingPointDeclare {{ - /** - * "Fast" static instruction class for "%(mnemonic)s" (imprecise - * trapping mode, normal rounding mode). - */ - class %(class_name)sFast : public %(base_class)s - { - public: - /// Constructor. - %(class_name)sFast(MachInst machInst) - : %(base_class)s("%(mnemonic)s", machInst, %(op_class)s) - { - %(constructor)s; - } - - Fault execute(SimpleCPU *cpu, ExecContext *xc, - Trace::InstRecord *traceData) - { - Fault fault = No_Fault; - - %(fp_enable_check)s; - %(exec_decl)s; - %(simple_rd)s; - %(code)s; - - if (fault == No_Fault) { - %(simple_wb)s; - } - - return fault; - } - - Fault execute(FullCPU *cpu, SpecExecContext *xc, DynInst *dynInst, - Trace::InstRecord *traceData) - { - Fault fault = No_Fault; - - %(fp_enable_check)s; - %(exec_decl)s; - %(dtld_rd)s; - %(code)s; - - if (fault == No_Fault) { - %(dtld_wb)s; - } - - return fault; - } - }; - - /** - * General static instruction class for "%(mnemonic)s". Supports - * all the various rounding and trapping modes. - */ - class %(class_name)sGeneral : public %(base_class)s - { - public: - /// Constructor. - %(class_name)sGeneral(MachInst machInst) - : %(base_class)s("%(mnemonic)s", machInst, %(op_class)s) - { - %(constructor)s; - } - - Fault execute(SimpleCPU *cpu, ExecContext *xc, - Trace::InstRecord *traceData) - { - Fault fault = No_Fault; - - %(fp_enable_check)s; - %(exec_decl)s; - %(simple_rd)s; - -#if defined(linux) - fesetround(getC99RoundingMode(xc)); -#endif - - %(code)s; - -#if defined(linux) - fesetround(FE_TONEAREST); -#endif - - if (fault == No_Fault) { - %(simple_wb)s; - } - - return fault; - } - - Fault execute(FullCPU *cpu, SpecExecContext *xc, DynInst *dynInst, - Trace::InstRecord *traceData) - { - Fault fault = No_Fault; - - %(fp_enable_check)s; - %(exec_decl)s; - %(dtld_rd)s; - -#if defined(linux) - fesetround(getC99RoundingMode(xc)); -#endif - - %(code)s; - -#if defined(linux) - fesetround(FE_TONEAREST); -#endif - - if (fault == No_Fault) { - %(dtld_wb)s; - } - - return fault; - } - }; -}}; - def template FloatingPointDecode {{ { bool fast = (FP_TRAPMODE == AlphaFP::Imprecise @@ -752,15 +616,34 @@ def template FloatingPointDecode {{ } }}; - // General format for floating-point operate instructions: // - Checks trapping and rounding mode flags. Trapping modes // currently unimplemented (will fail). // - Generates NOP if FC == 31. def format FloatingPointOperate(code, *opt_args) {{ - iop = InstObjParams(name, Name, 'AlphaFP', CodeBlock(code), - opt_args) - return iop.subst('FloatingPointDeclare', 'FloatingPointDecode') + iop = InstObjParams(name, Name, 'AlphaFP', CodeBlock(code), opt_args) + decode = iop.subst('FloatingPointDecode') + + fast_iop = InstObjParams(name, Name + 'Fast', 'AlphaFP', + CodeBlock(code), opt_args) + (fast_declare, fast_exec) = fast_iop.subst('BasicDeclare', 'BasicExecute') + + gen_code_prefix = r''' +#if defined(linux) + fesetround(getC99RoundingMode(xc->readFpcr())); +#endif +''' + gen_code_suffix = r''' +#if defined(linux) + fesetround(FE_TONEAREST); +#endif +''' + + gen_iop = InstObjParams(name, Name + 'General', 'AlphaFP', + CodeBlock(gen_code_prefix + code + gen_code_suffix), opt_args) + (gen_declare, gen_exec) = gen_iop.subst('BasicDeclare', 'BasicExecute') + + return (fast_declare + gen_declare, decode, fast_exec + gen_exec) }}; @@ -833,13 +716,11 @@ declare {{ { } - Fault execute(SimpleCPU *cpu, ExecContext *xc, - Trace::InstRecord *traceData) - { panic("attempt to execute eacomp"); } + Fault execute(SimpleCPUExecContext *, Trace::InstRecord *) + { panic("attempt to execute eacomp"); } - Fault execute(FullCPU *cpu, SpecExecContext *xc, DynInst *dynInst, - Trace::InstRecord *traceData) - { panic("attempt to execute eacomp"); } + Fault execute(FullCPUExecContext *, Trace::InstRecord *) + { panic("attempt to execute eacomp"); } }; /** @@ -855,13 +736,11 @@ declare {{ { } - Fault execute(SimpleCPU *cpu, ExecContext *xc, - Trace::InstRecord *traceData) - { panic("attempt to execute memacc"); } + Fault execute(SimpleCPUExecContext *, Trace::InstRecord *) + { panic("attempt to execute memacc"); } - Fault execute(FullCPU *cpu, SpecExecContext *xc, DynInst *dynInst, - Trace::InstRecord *traceData) - { panic("attempt to execute memacc"); } + Fault execute(FullCPUExecContext *, Trace::InstRecord *) + { panic("attempt to execute memacc"); } }; }}; @@ -869,7 +748,7 @@ declare {{ def format LoadAddress(code) {{ iop = InstObjParams(name, Name, 'Memory', CodeBlock(code)) - return iop.subst('BasicDeclare', 'BasicDecode') + return iop.subst('BasicDeclare', 'BasicDecode', 'BasicExecute') }}; @@ -927,72 +806,42 @@ def template LoadStoreDeclare {{ %(constructor)s; } - Fault execute(SimpleCPU *cpu, ExecContext *xc, - Trace::InstRecord *traceData) - { - SimpleCPU *memAccessObj = cpu; - Addr EA; - Fault fault = No_Fault; - - %(fp_enable_check)s; - %(exec_decl)s; - %(simple_nonmem_rd)s; - %(ea_code)s; - - if (fault == No_Fault) { - %(simple_mem_rd)s; - %(memacc_code)s; - } - - if (fault == No_Fault) { - %(simple_mem_wb)s; - } + %(exec_func_declarations)s + }; +}}; - if (fault == No_Fault) { - %(postacc_code)s; - } +def template LoadStoreExecute {{ + Fault %(class_name)s::execute(%(cpu_model)s *xc, + Trace::InstRecord *traceData) + { + Addr EA; + Fault fault = No_Fault; - if (fault == No_Fault) { - %(simple_nonmem_wb)s; - } + %(fp_enable_check)s; + %(op_decl)s; + %(op_nonmem_rd)s; + %(ea_code)s; - return fault; + if (fault == No_Fault) { + %(op_mem_rd)s; + %(memacc_code)s; } - Fault execute(FullCPU *cpu, SpecExecContext *xc, DynInst *dynInst, - Trace::InstRecord *traceData) - { - DynInst *memAccessObj = dynInst; - Addr EA; - Fault fault = No_Fault; - - %(fp_enable_check)s; - %(exec_decl)s; - %(dtld_nonmem_rd)s; - %(ea_code)s; - - if (fault == No_Fault) { - %(dtld_mem_rd)s; - %(memacc_code)s; - } - - if (fault == No_Fault) { - %(dtld_mem_wb)s; - } - - if (fault == No_Fault) { - %(postacc_code)s; - } + if (fault == No_Fault) { + %(op_mem_wb)s; + } - if (fault == No_Fault) { - %(dtld_nonmem_wb)s; - } + if (fault == No_Fault) { + %(postacc_code)s; + } - return fault; + if (fault == No_Fault) { + %(op_nonmem_wb)s; } - }; -}}; + return fault; + } +}}; def template PrefetchDeclare {{ /** @@ -1048,45 +897,30 @@ def template PrefetchDeclare {{ %(constructor)s; } - Fault execute(SimpleCPU *cpu, ExecContext *xc, - Trace::InstRecord *traceData) - { - Addr EA; - Fault fault = No_Fault; + %(exec_func_declarations)s + }; +}}; - %(fp_enable_check)s; - %(exec_decl)s; - %(simple_nonmem_rd)s; - %(ea_code)s; +def template PrefetchExecute {{ + Fault %(class_name)s::execute(%(cpu_model)s *xc, + Trace::InstRecord *traceData) + { + Addr EA; + Fault fault = No_Fault; - if (fault == No_Fault) { - cpu->prefetch(EA, memAccessFlags); - } + %(fp_enable_check)s; + %(op_decl)s; + %(op_nonmem_rd)s; + %(ea_code)s; - return No_Fault; + if (fault == No_Fault) { + xc->prefetch(EA, memAccessFlags); } - Fault execute(FullCPU *cpu, SpecExecContext *xc, DynInst *dynInst, - Trace::InstRecord *traceData) - { - Addr EA; - Fault fault = No_Fault; - - %(fp_enable_check)s; - %(exec_decl)s; - %(dtld_nonmem_rd)s; - %(ea_code)s; - - if (fault == No_Fault) { - dynInst->prefetch(EA, memAccessFlags); - } - - return No_Fault; - } - }; + return No_Fault; + } }}; - // load instructions use Ra as dest, so check for // Ra == 31 to detect nops def template LoadNopCheckDecode {{ @@ -1118,7 +952,8 @@ global LoadStoreBase def LoadStoreBase(name, Name, ea_code, memacc_code, postacc_code = '', base_class = 'Memory', flags = [], declare_template = 'LoadStoreDeclare', - decode_template = 'BasicDecode'): + decode_template = 'BasicDecode', + exec_template = 'LoadStoreExecute'): # Segregate flags into instruction flags (handled by InstObjParams) # and memory access flags (handled here). @@ -1149,7 +984,7 @@ def LoadStoreBase(name, Name, ea_code, memacc_code, postacc_code = '', if mem_flags != '': iop.constructor += '\n\tmemAccessFlags = ' + mem_flags + ';' - return iop.subst(declare_template, decode_template) + return iop.subst(declare_template, decode_template, exec_template) }}; @@ -1163,7 +998,7 @@ def format LoadOrNop(ea_code, memacc_code, *flags) {{ // Note that the flags passed in apply only to the prefetch version def format LoadOrPrefetch(ea_code, memacc_code, *pf_flags) {{ # declare the load instruction object and generate the decode block - (decls, decode) = \ + (decls, decode, exec_code) = \ LoadStoreBase(name, Name, ea_code, memacc_code, decode_template = 'LoadPrefetchCheckDecode') @@ -1172,12 +1007,13 @@ def format LoadOrPrefetch(ea_code, memacc_code, *pf_flags) {{ # convert flags from tuple to list to make them mutable pf_flags = list(pf_flags) + ['IsMemRef', 'IsLoad', 'IsDataPrefetch', 'RdPort'] - (pfdecls, pfdecode) = \ + (pfdecls, pfdecode, pfexec) = \ LoadStoreBase(name, Name + 'Prefetch', ea_code, '', flags = pf_flags, - declare_template = 'PrefetchDeclare') + declare_template = 'PrefetchDeclare', + exec_template = 'PrefetchExecute') - return (decls + pfdecls, decode) + return (decls + pfdecls, decode, exec_code + pfexec) }}; @@ -1369,7 +1205,7 @@ def format CondBranch(code) {{ code = 'bool cond;\n' + code + '\nif (cond) NPC = NPC + disp;\n'; iop = InstObjParams(name, Name, 'Branch', CodeBlock(code), ('IsDirectControl', 'IsCondControl')) - return iop.subst('BasicDeclare', 'BasicDecode') + return iop.subst('BasicDeclare', 'BasicDecode', 'BasicExecute') }}; let {{ @@ -1379,17 +1215,20 @@ def UncondCtrlBase(name, Name, base_class, npc_expr, flags): nolink_code = 'NPC = %s;\n' % npc_expr nolink_iop = InstObjParams(name, Name, base_class, CodeBlock(nolink_code), flags) - decls = nolink_iop.subst('BasicDeclare') + (decls, exec_code) = nolink_iop.subst('BasicDeclare', 'BasicExecute') # Generate declaration of '*AndLink' version, append to decls link_code = 'Ra = NPC & ~3;\n' + nolink_code link_iop = InstObjParams(name, Name + 'AndLink', base_class, CodeBlock(link_code), flags) - decls += link_iop.subst('BasicDeclare') + (link_decls, link_exec_code) = \ + link_iop.subst('BasicDeclare', 'BasicExecute') + decls += link_decls + exec_code += link_exec_code # need to use link_iop for the decode template since it is expecting # the shorter version of class_name (w/o "AndLink") - return (decls, nolink_iop.subst('JumpOrBranchDecode')) + return (decls, nolink_iop.subst('JumpOrBranchDecode'), exec_code) }}; def format UncondBranch(*flags) {{ @@ -1432,7 +1271,7 @@ declare {{ def format EmulatedCallPal(code) {{ iop = InstObjParams(name, Name, 'EmulatedCallPal', CodeBlock(code)) - return iop.subst('BasicDeclare', 'BasicDecode') + return iop.subst('BasicDeclare', 'BasicDecode', 'BasicExecute') }}; declare {{ @@ -1483,7 +1322,7 @@ declare {{ def format CallPal(code) {{ iop = InstObjParams(name, Name, 'CallPalBase', CodeBlock(code)) - return iop.subst('BasicDeclare', 'BasicDecode') + return iop.subst('BasicDeclare', 'BasicDecode', 'BasicExecute') }}; // @@ -1585,7 +1424,7 @@ declare {{ def format HwMoveIPR(code) {{ iop = InstObjParams(name, Name, 'HwMoveIPR', CodeBlock(code)) - return iop.subst('BasicDeclare', 'BasicDecode') + return iop.subst('BasicDeclare', 'BasicDecode', 'BasicExecute') }}; declare {{ @@ -1605,7 +1444,7 @@ declare {{ { } - Fault execute(SimpleCPU *cpu, ExecContext *xc, + Fault execute(SimpleCPUExecContext *xc, Trace::InstRecord *traceData) { panic("attempt to execute unimplemented instruction '%s' " @@ -1613,11 +1452,11 @@ declare {{ return Unimplemented_Opcode_Fault; } - Fault execute(FullCPU *cpu, SpecExecContext *xc, DynInst *dynInst, + Fault execute(FullCPUExecContext *xc, Trace::InstRecord *traceData) { // don't panic if this is a misspeculated instruction - if (!xc->spec_mode) + if (!xc->misspeculating()) panic("attempt to execute unimplemented instruction '%s' " "(inst 0x%08x, opcode 0x%x)", mnemonic, machInst, OPCODE); @@ -1652,7 +1491,7 @@ declare {{ { } - Fault execute(SimpleCPU *cpu, ExecContext *xc, + Fault execute(SimpleCPUExecContext *xc, Trace::InstRecord *traceData) { if (!warned) { @@ -1663,10 +1502,10 @@ declare {{ return No_Fault; } - Fault execute(FullCPU *cpu, SpecExecContext *xc, DynInst *dynInst, + Fault execute(FullCPUExecContext *xc, Trace::InstRecord *traceData) { - if (!xc->spec_mode && !warned) { + if (!xc->misspeculating() && !warned) { warn("instruction '%s' unimplemented\n", mnemonic); warned = true; } @@ -1703,12 +1542,12 @@ def template WarnUnimplDeclare {{ def format FailUnimpl() {{ iop = InstObjParams(name, 'FailUnimplemented') - return ('', iop.subst('BasicDecodeWithMnemonic')) + return ('', iop.subst('BasicDecodeWithMnemonic'), '') }}; def format WarnUnimpl() {{ iop = InstObjParams(name, Name, 'WarnUnimplemented') - return iop.subst('WarnUnimplDeclare', 'BasicDecode') + return iop.subst('WarnUnimplDeclare', 'BasicDecode') + [''] }}; declare {{ @@ -1726,7 +1565,7 @@ declare {{ { } - Fault execute(SimpleCPU *cpu, ExecContext *xc, + Fault execute(SimpleCPUExecContext *xc, Trace::InstRecord *traceData) { panic("attempt to execute unknown instruction " @@ -1734,11 +1573,11 @@ declare {{ return Unimplemented_Opcode_Fault; } - Fault execute(FullCPU *cpu, SpecExecContext *xc, DynInst *dynInst, + Fault execute(FullCPUExecContext *xc, Trace::InstRecord *traceData) { // don't panic if this is a misspeculated instruction - if (!xc->spec_mode) + if (!xc->misspeculating()) panic("attempt to execute unknown instruction " "(inst 0x%08x, opcode 0x%x)", machInst, OPCODE); return Unimplemented_Opcode_Fault; @@ -1753,7 +1592,7 @@ declare {{ }}; def format Unknown() {{ - return ('', 'return new Unknown(machInst);\n') + return ('', 'return new Unknown(machInst);\n', '') }}; declare {{ @@ -1855,7 +1694,7 @@ decode OPCODE default Unknown::unknown() { 0x2a: ldl_l({{ EA = Rb + disp; }}, {{ Ra.sl = Mem.sl; }}, LOCKED); 0x2b: ldq_l({{ EA = Rb + disp; }}, {{ Ra.uq = Mem.uq; }}, LOCKED); 0x20: copy_load({{EA = Ra;}}, - {{ fault = memAccessObj->copySrcTranslate(EA);}}, + {{ fault = xc->copySrcTranslate(EA);}}, IsMemRef, IsLoad, IsCopy); } @@ -1877,7 +1716,7 @@ decode OPCODE default Unknown::unknown() { 0x26: sts({{ EA = Rb + disp; }}, {{ Mem.ul = t_to_s(Fa.uq); }}); 0x27: stt({{ EA = Rb + disp; }}, {{ Mem.df = Fa; }}); 0x24: copy_store({{EA = Rb;}}, - {{ fault = memAccessObj->copy(EA);}}, + {{ fault = xc->copy(EA);}}, IsMemRef, IsStore, IsCopy); } @@ -2383,7 +2222,7 @@ decode OPCODE default Unknown::unknown() { format MiscPrefetch { 0xf800: wh64({{ EA = Rb; }}, - {{ memAccessObj->writeHint(EA, 64); }}, + {{ xc->writeHint(EA, 64); }}, IsMemRef, IsStore, WrPort); } @@ -2421,15 +2260,15 @@ decode OPCODE default Unknown::unknown() { #ifdef FULL_SYSTEM format BasicOperate { 0xe000: rc({{ - Ra = xc->regs.intrflag; + Ra = xc->readIntrFlag(); if (!xc->misspeculating()) { - xc->regs.intrflag = 0; + xc->setIntrFlag(0); } }}); 0xf000: rs({{ - Ra = xc->regs.intrflag; + Ra = xc->readIntrFlag(); if (!xc->misspeculating()) { - xc->regs.intrflag = 1; + xc->setIntrFlag(1); } }}); } @@ -2458,10 +2297,10 @@ decode OPCODE default Unknown::unknown() { // on this PAL call (including maybe suppress it) dopal = xc->simPalCheck(palFunc); - Annotate::Callpal(xc, palFunc); + Annotate::Callpal(xc->xcBase(), palFunc); if (dopal) { - AlphaISA::swap_palshadow(&xc->regs, true); + AlphaISA::swap_palshadow(&xc->xcBase()->regs, true); xc->setIpr(AlphaISA::IPR_EXC_ADDR, NPC); } } @@ -2519,48 +2358,48 @@ decode OPCODE default Unknown::unknown() { 0x01: decode M5FUNC { 0x00: arm({{ if (!xc->misspeculating()) { - Annotate::ARM(xc); - xc->kernelStats.arm(); + Annotate::ARM(xc->xcBase()); + xc->xcBase()->kernelStats.arm(); } }}); 0x01: quiesce({{ if (!xc->misspeculating()) - AlphaPseudo::quiesce(xc); + AlphaPseudo::quiesce(xc->xcBase()); }}); 0x10: ivlb({{ if (!xc->misspeculating()) { - Annotate::BeginInterval(xc); - xc->kernelStats.ivlb(); + Annotate::BeginInterval(xc->xcBase()); + xc->xcBase()->kernelStats.ivlb(); } }}, No_OpClass); 0x11: ivle({{ if (!xc->misspeculating()) - Annotate::EndInterval(xc); + Annotate::EndInterval(xc->xcBase()); }}, No_OpClass); 0x20: m5exit_old({{ if (!xc->misspeculating()) - AlphaPseudo::m5exit_old(xc); + AlphaPseudo::m5exit_old(xc->xcBase()); }}, No_OpClass); 0x21: m5exit({{ if (!xc->misspeculating()) - AlphaPseudo::m5exit(xc); + AlphaPseudo::m5exit(xc->xcBase()); }}, No_OpClass); - 0x30: initparam({{ Ra = cpu->system->init_param; }}); + 0x30: initparam({{ Ra = xc->xcBase()->cpu->system->init_param; }}); 0x40: resetstats({{ if (!xc->misspeculating()) - AlphaPseudo::resetstats(xc); + AlphaPseudo::resetstats(xc->xcBase()); }}); 0x41: dumpstats({{ if (!xc->misspeculating()) - AlphaPseudo::dumpstats(xc); + AlphaPseudo::dumpstats(xc->xcBase()); }}); 0x42: dumpresetstats({{ if (!xc->misspeculating()) - AlphaPseudo::dumpresetstats(xc); + AlphaPseudo::dumpresetstats(xc->xcBase()); }}); 0x43: m5checkpoint({{ if (!xc->misspeculating()) - AlphaPseudo::m5checkpoint(xc); + AlphaPseudo::m5checkpoint(xc->xcBase()); }}); } } @@ -2568,7 +2407,7 @@ decode OPCODE default Unknown::unknown() { format HwMoveIPR { 0x19: hw_mfpr({{ // this instruction is only valid in PAL mode - if (!PC_PAL(xc->regs.pc)) { + if (!xc->inPalMode()) { fault = Unimplemented_Opcode_Fault; } else { @@ -2577,7 +2416,7 @@ decode OPCODE default Unknown::unknown() { }}); 0x1d: hw_mtpr({{ // this instruction is only valid in PAL mode - if (!PC_PAL(xc->regs.pc)) { + if (!xc->inPalMode()) { fault = Unimplemented_Opcode_Fault; } else { diff --git a/arch/alpha/pseudo_inst.cc b/arch/alpha/pseudo_inst.cc index 7f8c6b17c..194dc6400 100644 --- a/arch/alpha/pseudo_inst.cc +++ b/arch/alpha/pseudo_inst.cc @@ -34,7 +34,8 @@ #include "sim/param.hh" #include "sim/serialize.hh" #include "sim/sim_exit.hh" -#include "sim/sim_stats.hh" +#include "sim/stat_control.hh" +#include "sim/stats.hh" using namespace std; using namespace Statistics; @@ -82,6 +83,7 @@ namespace AlphaPseudo Tick when = curTick + NS2Ticks(delay); Tick repeat = NS2Ticks(period); + using namespace Statistics; SetupEvent(Reset, when, repeat); } @@ -97,6 +99,7 @@ namespace AlphaPseudo Tick when = curTick + NS2Ticks(delay); Tick repeat = NS2Ticks(period); + using namespace Statistics; SetupEvent(Dump, when, repeat); } @@ -112,6 +115,7 @@ namespace AlphaPseudo Tick when = curTick + NS2Ticks(delay); Tick repeat = NS2Ticks(period); + using namespace Statistics; SetupEvent(Dump|Reset, when, repeat); } diff --git a/arch/isa_parser.py b/arch/isa_parser.py index 2e3c0df35..0ee9e2e2d 100755 --- a/arch/isa_parser.py +++ b/arch/isa_parser.py @@ -32,20 +32,10 @@ import os import sys import re import string +import traceback # get type names from types import * -# Check arguments. Right now there are only two: the name of the ISA -# description (input) file and the name of the C++ decoder (output) file. -isa_desc_filename = sys.argv[1] -decoder_filename = sys.argv[2] - -# Might as well suck the file in while we're here. This way if it's a -# bad filename we don't waste a lot of time building the parser :-). -input = open(isa_desc_filename) -isa_desc = input.read() -input.close() - # Prepend the directory where the PLY lex & yacc modules are found # to the search path. Assumes we're compiling in a subdirectory # of 'build' in the current tree. @@ -225,8 +215,8 @@ def p_specification(t): isa_name = t[2] namespace = isa_name + "Inst" global_decls2 = t[3] - (inst_decls, code) = t[4] - code = indent(code) + (inst_decls, decode_code, exec_code) = t[4] + decode_code = indent(decode_code) # grab the last three path components of isa_desc_filename filename = '/'.join(isa_desc_filename.split('/')[-3:]) # if the isa_desc file defines a 'rcs_id' string, @@ -306,6 +296,8 @@ namespace %(namespace)s %(inst_decls)s +%(exec_code)s + } // namespace %(namespace)s ////////////////////// @@ -316,7 +308,7 @@ StaticInstPtr<%(isa_name)s> %(isa_name)s::decodeInst(%(isa_name)s::MachInst machInst) { using namespace %(namespace)s; -%(code)s +%(decode_code)s } // decodeInst ''' % vars() output.close() @@ -461,18 +453,19 @@ def p_param_1(t): def p_decode_block(t): 'decode_block : DECODE ID opt_default LBRACE decode_stmt_list RBRACE' default_defaults = defaultStack.pop() - (decls, code, has_default) = t[5] + (decls, decode_code, exec_code, has_default) = t[5] # use the "default defaults" only if there was no explicit # default statement in decode_stmt_list if not has_default: - (default_decls, default_code) = default_defaults + (default_decls, default_decode, default_exec) = default_defaults decls += default_decls - code += default_code + decode_code += default_decode + exec_code += default_exec t[0] = (decls, ''' switch (%s) { %s } -''' % (t[2], indent(code))) +''' % (t[2], indent(decode_code)), exec_code) # The opt_default statement serves only to push the "default defaults" # onto defaultStack. This value will be used by nested decode blocks, @@ -488,8 +481,8 @@ def p_opt_default_0(t): def p_opt_default_1(t): 'opt_default : DEFAULT inst' # push the new default - (decls, code) = t[2] - defaultStack.push((decls, '\ndefault:\n%sbreak;' % code)) + (decls, decode_code, exec_code) = t[2] + defaultStack.push((decls, '\ndefault:\n%sbreak;' % decode_code, exec_code)) # no meaningful value returned t[0] = None @@ -499,12 +492,12 @@ def p_decode_stmt_list_0(t): def p_decode_stmt_list_1(t): 'decode_stmt_list : decode_stmt decode_stmt_list' - (decls1, code1, has_default1) = t[1] - (decls2, code2, has_default2) = t[2] + (decls1, decode_code1, exec_code1, has_default1) = t[1] + (decls2, decode_code2, exec_code2, has_default2) = t[2] if (has_default1 and has_default2): error(t.lineno(1), 'Two default cases in decode block') - t[0] = (decls1 + '\n' + decls2, code1 + '\n' + code2, - has_default1 or has_default2) + t[0] = (decls1 + '\n' + decls2, decode_code1 + '\n' + decode_code2, + exec_code1 + '\n' + exec_code2, has_default1 or has_default2) # # Decode statement rules @@ -525,7 +518,7 @@ def p_decode_stmt_list_1(t): # the other statements. def p_decode_stmt_cpp(t): 'decode_stmt : CPPDIRECTIVE' - t[0] = (t[1], t[1], 0) + t[0] = (t[1], t[1], t[1], 0) # A format block 'format <foo> { ... }' sets the default instruction # format used to handle instruction definitions inside the block. @@ -555,17 +548,19 @@ def p_push_format_id(t): def p_decode_stmt_decode(t): 'decode_stmt : case_label COLON decode_block' (label, is_default) = t[1] - (decls, code) = t[3] + (decls, decode_code, exec_code) = t[3] # just wrap the decoding code from the block as a case in the # outer switch statement. - t[0] = (decls, '\n%s:\n%s' % (label, indent(code)), is_default) + t[0] = (decls, '\n%s:\n%s' % (label, indent(decode_code)), + exec_code, is_default) # Instruction definition (finally!). def p_decode_stmt_inst(t): 'decode_stmt : case_label COLON inst SEMI' (label, is_default) = t[1] - (decls, code) = t[3] - t[0] = (decls, '\n%s:%sbreak;' % (label, indent(code)), is_default) + (decls, decode_code, exec_code) = t[3] + t[0] = (decls, '\n%s:%sbreak;' % (label, indent(decode_code)), + exec_code, is_default) # The case label is either a list of one or more constants or 'default' def p_case_label_0(t): @@ -596,12 +591,13 @@ def p_inst_0(t): 'inst : ID LPAREN arg_list RPAREN' # Pass the ID and arg list to the current format class to deal with. currentFormat = formatStack.top() - (decls, code) = currentFormat.defineInst(t[1], t[3], t.lineno(1)) + (decls, decode_code, exec_code) = \ + currentFormat.defineInst(t[1], t[3], t.lineno(1)) args = ','.join(map(str, t[3])) args = re.sub('(?m)^', '//', args) args = re.sub('^//', '', args) comment = '// %s::%s(%s)\n' % (currentFormat.id, t[1], args) - t[0] = (comment + decls, comment + code) + t[0] = (comment + decls, comment + decode_code, comment + exec_code) # Define an instruction using an explicitly specified format: # "<fmt>::<mnemonic>(<args>)" @@ -611,9 +607,10 @@ def p_inst_1(t): format = formatMap[t[1]] except KeyError: error(t.lineno(1), 'instruction format "%s" not defined.' % t[1]) - (decls, code) = format.defineInst(t[3], t[5], t.lineno(1)) + (decls, decode_code, exec_code) = \ + format.defineInst(t[3], t[5], t.lineno(1)) comment = '// %s::%s(%s)\n' % (t[1], t[3], t[5]) - t[0] = (comment + decls, comment + code) + t[0] = (comment + decls, comment + decode_code, comment + exec_code) def p_arg_list_0(t): 'arg_list : empty' @@ -673,7 +670,8 @@ class Format: code = ' pass\n' param_list = string.join(params, ", ") f = 'def defInst(name, Name, ' + param_list + '):\n' + code - exec(f) + c = compile(f, 'def format ' + id, 'exec') + exec(c) self.func = defInst def defineInst(self, name, args, lineno): @@ -773,8 +771,9 @@ def error(lineno, string): # Like error(), but include a Python stack backtrace (for processing # Python exceptions). def error_bt(lineno, string): + traceback.print_exc() print >> sys.stderr, "%s:%d: %s" % (isa_desc_filename, lineno, string) - raise + sys.exit(1) ##################################################################### @@ -944,7 +943,7 @@ class IntRegOperandTraits(OperandTraits): (op_desc.dest_reg_idx, self.reg_spec) return c - def makeRead(self, op_desc, cpu_model): + def makeRead(self, op_desc): (size, type, is_signed) = operandSizeMap[op_desc.eff_ext] if (type == 'float' or type == 'double'): error(0, 'Attempt to read integer register as FP') @@ -955,7 +954,7 @@ class IntRegOperandTraits(OperandTraits): return '%s = bits(xc->readIntReg(_srcRegIdx[%d]), %d, 0);\n' % \ (op_desc.munged_name, op_desc.src_reg_idx, size-1) - def makeWrite(self, op_desc, cpu_model): + def makeWrite(self, op_desc): (size, type, is_signed) = operandSizeMap[op_desc.eff_ext] if (type == 'float' or type == 'double'): error(0, 'Attempt to write integer register as FP') @@ -988,7 +987,7 @@ class FloatRegOperandTraits(OperandTraits): (op_desc.dest_reg_idx, self.reg_spec) return c - def makeRead(self, op_desc, cpu_model): + def makeRead(self, op_desc): (size, type, is_signed) = operandSizeMap[op_desc.eff_ext] bit_select = 0 if (type == 'float'): @@ -1007,7 +1006,7 @@ class FloatRegOperandTraits(OperandTraits): else: return '%s = %s;\n' % (op_desc.munged_name, base) - def makeWrite(self, op_desc, cpu_model): + def makeWrite(self, op_desc): (size, type, is_signed) = operandSizeMap[op_desc.eff_ext] final_val = op_desc.munged_name if (type == 'float'): @@ -1044,7 +1043,7 @@ class ControlRegOperandTraits(OperandTraits): (op_desc.dest_reg_idx, self.reg_spec) return c - def makeRead(self, op_desc, cpu_model): + def makeRead(self, op_desc): (size, type, is_signed) = operandSizeMap[op_desc.eff_ext] bit_select = 0 if (type == 'float' or type == 'double'): @@ -1056,7 +1055,7 @@ class ControlRegOperandTraits(OperandTraits): return '%s = bits(%s, %d, 0);\n' % \ (op_desc.munged_name, base, size-1) - def makeWrite(self, op_desc, cpu_model): + def makeWrite(self, op_desc): (size, type, is_signed) = operandSizeMap[op_desc.eff_ext] if (type == 'float' or type == 'double'): error(0, 'Attempt to write control register as FP') @@ -1087,16 +1086,16 @@ class MemOperandTraits(OperandTraits): c += 'uint64_t %s_write_result = 0;\n' % op_desc.base_name return c - def makeRead(self, op_desc, cpu_model): + def makeRead(self, op_desc): (size, type, is_signed) = operandSizeMap[op_desc.eff_ext] eff_type = 'uint%d_t' % size - return 'fault = memAccessObj->read(EA, (%s&)%s, %s_flags);\n' \ + return 'fault = xc->read(EA, (%s&)%s, %s_flags);\n' \ % (eff_type, op_desc.munged_name, op_desc.base_name) - def makeWrite(self, op_desc, cpu_model): + def makeWrite(self, op_desc): (size, type, is_signed) = operandSizeMap[op_desc.eff_ext] eff_type = 'uint%d_t' % size - return 'fault = memAccessObj->write((%s&)%s, EA, %s_flags,' \ + return 'fault = xc->write((%s&)%s, EA, %s_flags,' \ ' &%s_write_result);\n' \ % (eff_type, op_desc.munged_name, op_desc.base_name, op_desc.base_name) @@ -1105,10 +1104,10 @@ class NPCOperandTraits(OperandTraits): def makeConstructor(self, op_desc): return '' - def makeRead(self, op_desc, cpu_model): + def makeRead(self, op_desc): return '%s = xc->readPC() + 4;\n' % op_desc.munged_name - def makeWrite(self, op_desc, cpu_model): + def makeWrite(self, op_desc): return 'xc->setNextPC(%s);\n' % op_desc.munged_name @@ -1172,21 +1171,17 @@ class OperandDescriptor: def finalize(self): self.flags = self.traits.getFlags(self) self.constructor = self.traits.makeConstructor(self) - self.exec_decl = self.traits.makeDecl(self) + self.op_decl = self.traits.makeDecl(self) if self.is_src: - self.simple_rd = self.traits.makeRead(self, 'simple') - self.dtld_rd = self.traits.makeRead(self, 'dtld') + self.op_rd = self.traits.makeRead(self) else: - self.simple_rd = '' - self.dtld_rd = '' + self.op_rd = '' if self.is_dest: - self.simple_wb = self.traits.makeWrite(self, 'simple') - self.dtld_wb = self.traits.makeWrite(self, 'dtld') + self.op_wb = self.traits.makeWrite(self) else: - self.simple_wb = '' - self.dtld_wb = '' + self.op_wb = '' class OperandDescriptorList: def __init__(self): @@ -1348,32 +1343,21 @@ class CodeBlock: self.constructor += \ '\n\t_numIntDestRegs = %d;' % self.operands.numIntDestRegs - self.exec_decl = self.operands.concatAttrStrings('exec_decl') + self.op_decl = self.operands.concatAttrStrings('op_decl') is_mem = lambda op: op.traits.isMem() not_mem = lambda op: not op.traits.isMem() - self.simple_rd = self.operands.concatAttrStrings('simple_rd') - self.simple_wb = self.operands.concatAttrStrings('simple_wb') - self.simple_mem_rd = \ - self.operands.concatSomeAttrStrings(is_mem, 'simple_rd') - self.simple_mem_wb = \ - self.operands.concatSomeAttrStrings(is_mem, 'simple_wb') - self.simple_nonmem_rd = \ - self.operands.concatSomeAttrStrings(not_mem, 'simple_rd') - self.simple_nonmem_wb = \ - self.operands.concatSomeAttrStrings(not_mem, 'simple_wb') - - self.dtld_rd = self.operands.concatAttrStrings('dtld_rd') - self.dtld_wb = self.operands.concatAttrStrings('dtld_wb') - self.dtld_mem_rd = \ - self.operands.concatSomeAttrStrings(is_mem, 'dtld_rd') - self.dtld_mem_wb = \ - self.operands.concatSomeAttrStrings(is_mem, 'dtld_wb') - self.dtld_nonmem_rd = \ - self.operands.concatSomeAttrStrings(not_mem, 'dtld_rd') - self.dtld_nonmem_wb = \ - self.operands.concatSomeAttrStrings(not_mem, 'dtld_wb') + self.op_rd = self.operands.concatAttrStrings('op_rd') + self.op_wb = self.operands.concatAttrStrings('op_wb') + self.op_mem_rd = \ + self.operands.concatSomeAttrStrings(is_mem, 'op_rd') + self.op_mem_wb = \ + self.operands.concatSomeAttrStrings(is_mem, 'op_wb') + self.op_nonmem_rd = \ + self.operands.concatSomeAttrStrings(not_mem, 'op_rd') + self.op_nonmem_wb = \ + self.operands.concatSomeAttrStrings(not_mem, 'op_wb') self.flags = self.operands.concatAttrLists('flags') @@ -1401,6 +1385,10 @@ class InstObjParams: self.mnemonic = mnem self.class_name = class_name self.base_class = base_class + self.exec_func_declarations = ''' + Fault execute(SimpleCPUExecContext *, Trace::InstRecord *); + Fault execute(FullCPUExecContext *, Trace::InstRecord *); +''' if code_block: for code_attr in code_block.__dict__.keys(): setattr(self, code_attr, getattr(code_block, code_attr)) @@ -1431,20 +1419,48 @@ class InstObjParams: else: self.fp_enable_check = '' + def _subst(self, template): + try: + return template % self.__dict__ + except KeyError, key: + raise KeyError, 'InstObjParams.subst: no definition for %s' % key + def subst(self, *args): result = [] for t in args: - if not templateMap.has_key(t): + try: template = templateMap[t] + except KeyError: error(0, 'InstObjParams::subst: undefined template "%s"' % t) - try: - result.append(templateMap[t] % self.__dict__) - except KeyError, key: - error(0, 'InstObjParams::subst: no definition for "%s"' % key) + if template.find('%(cpu_model)') != -1: + tmp = '' + for cpu_model in ('SimpleCPUExecContext', 'FullCPUExecContext'): + self.cpu_model = cpu_model + tmp += self._subst(template) + result.append(tmp) + else: + result.append(self._subst(template)) if len(args) == 1: result = result[0] return result # -# All set... read in and parse the ISA description. +# Read in and parse the ISA description. # -yacc.parse(isa_desc) +def parse_isa_desc(isa_desc_file, decoder_file): + # Arguments are the name of the ISA description (input) file and + # the name of the C++ decoder (output) file. + global isa_desc_filename, decoder_filename + isa_desc_filename = isa_desc_file + decoder_filename = decoder_file + + # Suck the ISA description file in. + input = open(isa_desc_filename) + isa_desc = input.read() + input.close() + + # Parse it. + yacc.parse(isa_desc) + +# Called as script: get args from command line. +if __name__ == '__main__': + parse_isa_desc(sys.argv[1], sys.argv[2]) diff --git a/base/compression/lzss_compression.cc b/base/compression/lzss_compression.cc index 8f235b808..2f6c5d338 100644 --- a/base/compression/lzss_compression.cc +++ b/base/compression/lzss_compression.cc @@ -36,21 +36,32 @@ #include "base/misc.hh" //for fatal -int -LZSSCompression::findSubString(uint8_t *src, int front, int back, int size) +void +LZSSCompression::findSubString(uint8_t *src, int back, int size, uint16_t &L, + uint16_t &P) { - int subSize = 0; - int max_length = 2048; - if (size - back < max_length) { - max_length = size - back; - } - for (int i = 0; i < max_length; ++i) { - if (src[front+i] != src[back+i]) { - return subSize; + int front = 0; + int max_length = size - back; + L = 0; + P = back - 1; + while (front < back) { + while (src[front] != src[back] && front < back) ++front; + if (front >= back) { + return; + } + int i = 1; + while (src[front+i] == src[back+i] && i < max_length) ++i; + if (i >= L) { + L = i; + P = front; + } + if (src[front+i] != src[back+i-1]) { + // can't find a longer substring until past this point. + front += i; + } else { + ++front; } - ++subSize; } - return subSize; } int @@ -106,13 +117,7 @@ LZSSCompression::compress(uint8_t *dest, uint8_t *src, int size) ++i; continue; } - for (int j = 0; j < i; ++j) { - int sub_size = findSubString(src, j, i, size); - if (sub_size >= L) { - L = sub_size; - P = j; - } - } + findSubString(src, i, size, L, P); if (L > 1) { // Output the string reference emitString(&dest[dest_index], P, L); diff --git a/base/compression/lzss_compression.hh b/base/compression/lzss_compression.hh index 755a52c92..9707a8aca 100644 --- a/base/compression/lzss_compression.hh +++ b/base/compression/lzss_compression.hh @@ -41,14 +41,15 @@ class LZSSCompression { /** - * Finds the longest substrings that start at the given offsets. + * Finds the longest substring for the given offset. * @param src The source block that we search for substrings. - * @param front The smaller offset. * @param back The larger offset. * @param size The size of the source block. - * @return The size of the longest substring. + * @param L The length of the largest substring. + * @param P The starting offset of the largest substring. */ - int findSubString(uint8_t *src, int front, int back, int size); + void findSubString(uint8_t *src, int back, int size, uint16_t &L, + uint16_t &P); /** * Emit an encoded byte to the compressed data array. If the 2 high diff --git a/base/hashmap.hh b/base/hashmap.hh index 995e98a90..59c1fe3aa 100644 --- a/base/hashmap.hh +++ b/base/hashmap.hh @@ -57,7 +57,7 @@ namespace m5 { // namespace __hash_namespace { -#if !defined(__LP64__) +#if !defined(__LP64__) && !defined(__alpha__) template<> struct hash<uint64_t> { size_t operator()(uint64_t r) const { diff --git a/base/hybrid_pred.cc b/base/hybrid_pred.cc index 83ce7f987..12bab975b 100644 --- a/base/hybrid_pred.cc +++ b/base/hybrid_pred.cc @@ -31,7 +31,7 @@ #include "base/hybrid_pred.hh" #include "base/statistics.hh" -#include "sim/sim_stats.hh" +#include "sim/stats.hh" using namespace std; diff --git a/base/hybrid_pred.hh b/base/hybrid_pred.hh index 3fdab9153..9063f3084 100644 --- a/base/hybrid_pred.hh +++ b/base/hybrid_pred.hh @@ -41,9 +41,7 @@ #include <string> #include "base/sat_counter.hh" - #include "base/statistics.hh" -#include "sim/sim_stats.hh" class HybridPredictor : public GenericPredictor { diff --git a/base/loader/elf_object.cc b/base/loader/elf_object.cc index 98e3198a6..a0c0c0551 100644 --- a/base/loader/elf_object.cc +++ b/base/loader/elf_object.cc @@ -36,6 +36,7 @@ // set this now (it causes things to break on 64-bit platforms). #define __LIBELF64_LINUX 0 #define __LIBELF_NEED_LINK_H 0 +#define __LIBELF_SYMBOL_VERSIONS 0 #include <libelf/libelf.h> #include <libelf/gelf.h> diff --git a/base/mysql.cc b/base/mysql.cc new file mode 100644 index 000000000..8481e74e2 --- /dev/null +++ b/base/mysql.cc @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2003-2004 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. + */ + +#include <iostream> + +#include "base/mysql.hh" + +using namespace std; + +namespace MySQL { + +inline const char * +charstar(const string &string) +{ + return string.empty() ? NULL : string.c_str(); +} + +ostream & +operator<<(ostream &stream, const Error &error) +{ + stream << error.string(); + return stream; +} + +/* + * The connection class + */ +Connection::Connection() + : valid(false) +{ +} + +Connection::~Connection() +{ + if (valid) + close(); +} + + +bool +Connection::connect(const string &xhost, const string &xuser, + const string &xpasswd, const string &xdatabase) +{ + if (connected()) + return error.set("Already Connected"); + + _host = xhost; + _user = xuser; + _passwd = xpasswd; + _database = xdatabase; + + error.clear(); + + mysql_init(&mysql); + mysql_options(&mysql, MYSQL_OPT_COMPRESS, 0); // might want to be 1 + mysql_options(&mysql, MYSQL_READ_DEFAULT_GROUP, "odbc"); + if (!mysql_real_connect(&mysql, charstar(_host), charstar(_user), + charstar(_passwd), charstar(_database), + 0, NULL, 0)) + return error.set(mysql_error(&mysql)); + + valid = true; + return false; +} + +void +Connection::close() +{ + mysql_close(&mysql); +} + +/* namespace MySQL */ } diff --git a/base/mysql.hh b/base/mysql.hh new file mode 100644 index 000000000..89bec73d0 --- /dev/null +++ b/base/mysql.hh @@ -0,0 +1,410 @@ +/* + * Copyright (c) 2003-2004 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. + */ + +#ifndef __BASE_MYQSL_HH__ +#define __BASE_MYQSL_HH__ + +#define TO_BE_INCLUDED_LATER 0 + +#include <cassert> +#include <iosfwd> +#include <mysql.h> +#include <string> +#include <sstream> + +namespace MySQL { + +class Error +{ + protected: + const char *error; + + public: + Error() : error(NULL) {} + + Error &clear() { error = NULL; return *this; } + Error &set(const char *err) { error = err; return *this; } + + const char *string() const { return error; } + + operator bool() const { return error != NULL; } + bool operator!() const { return error == NULL; } +}; + +std::ostream &operator<<(std::ostream &stream, const Error &error); + +class Result +{ + private: + MYSQL_RES *result; + int *refcount; + + void + decref() + { + if (!refcount) + return; + + *refcount -= 1; + if (*refcount == 0) { + mysql_free_result(result); + delete refcount; + } + + refcount = NULL; + } + + public: + Result() + : result(0), refcount(NULL) + { } + + Result(MYSQL_RES *res) + : result(res) + { + if (result) + refcount = new int(1); + } + + Result(const Result &result) + : result(result.result), refcount(result.refcount) + { + if (result) + *refcount += 1; + } + + ~Result() + { + decref(); + } + + const Result & + operator=(MYSQL_RES *res) + { + decref(); + result = res; + if (result) + refcount = new int(1); + + return *this; + } + + const Result & + operator=(const Result &res) + { + decref(); + result = res.result; + refcount = res.refcount; + if (result) + *refcount += 1; + + return *this; + } + + operator bool() const { return result != NULL; } + bool operator!() const { return result == NULL; } + + unsigned + num_fields() + { + assert(result); + return mysql_num_fields(result); + } + + MYSQL_ROW + fetch_row() + { + return mysql_fetch_row(result); + } + + unsigned long * + fetch_lengths() + { + return mysql_fetch_lengths(result); + } +}; + +typedef MYSQL_ROW Row; + +class Connection +{ + protected: + MYSQL mysql; + bool valid; + + protected: + std::string _host; + std::string _user; + std::string _passwd; + std::string _database; + + public: + Connection(); + virtual ~Connection(); + + bool connected() const { return valid; } + bool connect(const std::string &host, const std::string &user, + const std::string &passwd, const std::string &database); + void close(); + + public: + Error error; + operator MYSQL *() { return &mysql; } + + public: + bool + query(const std::string &sql) + { + error.clear(); + if (mysql_real_query(&mysql, sql.c_str(), sql.size())) + error.set(mysql_error(&mysql)); + + return error; + } + + bool + query(const std::stringstream &sql) + { + return query(sql.str()); + } + + unsigned + field_count() + { + return mysql_field_count(&mysql); + } + + unsigned + affected_rows() + { + return mysql_affected_rows(&mysql); + } + + unsigned + insert_id() + { + return mysql_insert_id(&mysql); + } + + + Result + store_result() + { + error.clear(); + Result result = mysql_store_result(&mysql); + if (!result) + error.set(mysql_error(&mysql)); + + return result; + } +}; + +#if 0 +class BindProxy +{ + MYSQL_BIND *bind; + BindProxy(MYSQL_BIND *b) : bind(b) {} + + void operator=(bool &buffer) + { + bind->buffer_type = MYSQL_TYPE_TINY; + bind->buffer = (char *)&buffer; + } + + void operator=(int8_t &buffer) + { + bind->buffer_type = MYSQL_TYPE_TINY; + bind->buffer = (char *)&buffer; + } + + void operator=(int16_t &buffer) + { + bind->buffer_type = MYSQL_TYPE_SHORT; + bind->buffer = (char *)&buffer; + } + + void operator=(int32_t &buffer) + { + bind->buffer_type = MYSQL_TYPE_LONG; + bind->buffer = (char *)&buffer; + } + + void operator=(int64_t &buffer) + { + bind->buffer_type = MYSQL_TYPE_LONGLONG; + bind->buffer = (char *)&buffer; + } + + void operator=(uint8_t &buffer) + { + bind->buffer_type = MYSQL_TYPE_TINY; + bind->buffer = (char *)&buffer; + } + + void operator=(uint16_t &buffer) + { + bind->buffer_type = MYSQL_TYPE_SHORT; + bind->buffer = (char *)&buffer; + } + + void operator=(uint32_t &buffer) + { + bind->buffer_type = MYSQL_TYPE_LONG; + bind->buffer = (char *)&buffer; + } + + void operator=(uint64_t &buffer) + { + bind->buffer_type = MYSQL_TYPE_LONGLONG; + bind->buffer = (char *)&buffer; + } + + void operator=(float &buffer) + { + bind->buffer_type = MYSQL_TYPE_FLOAT; + bind->buffer = (char *)&buffer; + } + + void operator=(double &buffer) + { + bind->buffer_type = MYSQL_TYPE_DOUBLE; + bind->buffer = (char *)&buffer; + } + + void operator=(Time &buffer) + { + bind->buffer_type = MYSQL_TYPE_DATE; + bind->buffer = (char *)&buffer; + } + + void operator=(const char *buffer) + { + bind->buffer_type = MYSQL_TYPE_VAR_STRING; + bind->buffer = buffer; + } + + void operator=(const std::string &buffer) + { + bind->buffer_type = MYSQL_TYPE_VAR_STRING; + bind->buffer = (char *)&buffer; + bind->length = buffer.length; + } + + bool + set_null(bool null) + { + bind->is_null = null; + } +}; + +class Statement +{ + protected: + Error &error; + MYSQL_STMT *stmt; + MYSQL_BIND *bind; + int size; + + public: + Statement(Connection &mysql) + : error(mysql.error), bind(NULL), size(0) + { + stmt = mysql_stmt_init(mysql); + assert(valid() && "mysql_stmt_init(), out of memory\n"); + } + + ~Statement() + { + assert(valid()); + error.clear(); + if (mysql_stmt_close(stmt)) + error.set(mysql_stmt_error(stmt)); + + if (bind) + delete [] bind; + } + + bool valid() + { + return stmt != NULL; + } + + void prepare(const std::string &query) + { + assert(valid()); + mysql.error.clear(); + if (mysql_stmt_prepare(mysql, query, strlen(query))) + mysql.error.set(mysql_stmt_error(stmt)); + + int size = count(); + bind = new MYSQL_BIND[size]; + } + + unsigned count() + { + assert(valid()); + return mysql_stmt_param_count(stmt); + } + + unsigned affected() + { + assert(valid()); + return mysql_stmt_affected_rows(stmt); + } + + void bind(MYSQL_BIND *bind) + { + mysql.error.clear(); + if (mysql_stmt_bind_param(stmt, bind)) + mysql.error.set(mysql_stmt_error(stmt)); + } + + BindProxy operator[](int index) + { + assert(index > 0 && index < N); + return &bind[N]; + } + + operator MYSQL_BIND *() + { + return bind; + } + + void operator()() + { + assert(valid()); + error.clear(); + if (mysql_stmt_execute(stmt)) + error.set(mysql_stmt_error(stmt)); + } +} +#endif + +/* namespace MySQL */ } + +#endif // __BASE_MYQSL_HH__ diff --git a/base/sat_counter.cc b/base/sat_counter.cc index c26690a1a..a8367d8a0 100644 --- a/base/sat_counter.cc +++ b/base/sat_counter.cc @@ -29,9 +29,8 @@ #include <sstream> #include "base/sat_counter.hh" - #include "base/statistics.hh" -#include "sim/sim_stats.hh" +#include "sim/stats.hh" using namespace std; diff --git a/base/sat_counter.hh b/base/sat_counter.hh index 62c18f6b4..a5d9c7e8a 100644 --- a/base/sat_counter.hh +++ b/base/sat_counter.hh @@ -34,7 +34,7 @@ #include "base/predictor.hh" #include "base/statistics.hh" -#include "sim/sim_stats.hh" +#include "sim/stats.hh" // // diff --git a/base/statistics.cc b/base/statistics.cc index dce545f18..1a44cd342 100644 --- a/base/statistics.cc +++ b/base/statistics.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003 The Regents of The University of Michigan + * Copyright (c) 2003-2004 The Regents of The University of Michigan * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -42,343 +42,28 @@ #include "base/str.hh" #include "base/time.hh" #include "base/trace.hh" - -#ifdef __M5_NAN -float -__nan() -{ - union { - uint32_t ui; - float f; - } nan; - - nan.ui = 0x7fc00000; - return nan.f; -} -#endif - -#ifdef DEBUG -static int total_stats = 0; -#endif +#include "base/stats/statdb.hh" using namespace std; -// This is a hack to get this parameter from the old stats package. namespace Statistics { -bool PrintDescriptions = true; -DisplayMode DefaultMode = mode_simplescalar; - -namespace Database -{ - class Data - { - private: - typedef list<StatData *> list_t; - typedef map<void *, StatData *> map_t; - - list<MainBin *> bins; - - list_t allStats; - list_t printStats; - map_t statMap; - - ofstream *stream; - Python *py; - - public: - Data(); - ~Data(); - - void dump(ostream &stream, DisplayMode mode); - void display(ostream &stream, DisplayMode mode); - void python_start(const string &file); - void python_dump(const string &name, const string &subname); - void python(const string &name, const string &subname, - const string &bin); - - StatData *find(void *stat); - void mapStat(void *stat, StatData *data); - - void check(); - void reset(); - void regBin(MainBin *bin, string name); - void regPrint(void *stat); - - static std::string name() { return "Statistics Database"; } - }; - -Data::Data() - : stream(0), py(0) -{ -} - -Data::~Data() -{ - if (stream) { - delete py; - ccprintf(*stream, "\n\nif __name__ == '__main__':\n"); - ccprintf(*stream, " program_display()\n"); - stream->close(); - delete stream; - } -} - -void -Data::dump(ostream &stream, DisplayMode mode) -{ - MainBin *orig = MainBin::curBin(); - - switch (mode) { - case mode_m5: - case mode_simplescalar: - display(stream, mode); - break; - default: - warn("invalid display mode!\n"); - display(stream, mode_m5); - break; - } - - if (orig) - orig->activate(); -} - -void -Data::display(ostream &stream, DisplayMode mode) -{ - if (!bins.empty()) { - list<MainBin *>::iterator i = bins.begin(); - list<MainBin *>::iterator bins_end = bins.end(); - ccprintf(stream, "PRINTING BINNED STATS\n"); - while (i != bins_end) { - (*i)->activate(); - ccprintf(stream,"---%s Bin------------\n", (*i)->name()); - - list_t::iterator j = printStats.begin(); - list_t::iterator end = printStats.end(); - while (j != end) { - StatData *stat = *j; - if (stat->dodisplay()) - stat->display(stream, mode); - ++j; - } - ++i; - ccprintf(stream, "---------------------------------\n"); - } - } else { - list_t::iterator i = printStats.begin(); - list_t::iterator end = printStats.end(); - while (i != end) { - StatData *stat = *i; - if (stat->dodisplay() && !stat->binned()) - stat->display(stream, mode); - ++i; - } - } -} - -void -Data::python_start(const string &file) -{ - if (stream) - panic("can't start python twice!"); - - stream = new ofstream(file.c_str(), ios::trunc); - py = new Python(*stream); - - ccprintf(*stream, "import sys\n"); - ccprintf(*stream, "sys.path.append('.')\n"); - ccprintf(*stream, "from m5stats import *\n\n"); -} - -void -Data::python_dump(const string &name, const string &subname) -{ - if (!py) - panic("Can't dump python without first opening the file"); - - if (bins.empty()) { - python(name, subname, ""); - } else { - list<MainBin *>::iterator i = bins.begin(); - list<MainBin *>::iterator end = bins.end(); - - while (i != end) { - (*i)->activate(); - python(name, subname, (*i)->name()); - ++i; - } - } -} - -void -Data::python(const string &name, const string &subname, const string &bin) -{ - py->name("collections.append"); - py->newline(); - py->name("Collection"); - py->newline(); - py->qarg(name); - py->newline(); - py->qarg(subname); - py->newline(); - py->qarg(bin); - py->newline(); - py->qarg(hostname()); - py->newline(); - py->qarg(Time::start.date()); - py->newline(); - py->list(); - list_t::iterator i = allStats.begin(); - list_t::iterator end = allStats.end(); - while (i != end) { - StatData *stat = *i; - py->newline(); - stat->python(*py); - ++i; - } - py->newline(); - py->listEnd(); - py->newline(); - py->nameEnd(); - py->newline(); - py->nameEnd(); - py->newline(); -} - -StatData * -Data::find(void *stat) -{ - map_t::const_iterator i = statMap.find(stat); - - if (i == statMap.end()) - return NULL; - - return (*i).second; -} - -void -Data::check() -{ - list_t::iterator i = allStats.begin(); - list_t::iterator end = allStats.end(); - - while (i != end) { - StatData *data = *i; - assert(data); - data->check(); - ++i; - } - - i = allStats.begin(); - int j = 0; - while (i != end) { - StatData *data = *i; - if (!(data->flags & print)) - data->name = "__Stat" + to_string(j++); - ++i; - } -} - -void -Data::reset() -{ - // reset non-binned stats - list_t::iterator i = allStats.begin(); - list_t::iterator end = allStats.end(); - while (i != end) { - StatData *data = *i; - if (!data->binned()) - data->reset(); - ++i; - } - - // save the bin so we can go back to where we were - MainBin *orig = MainBin::curBin(); - - // reset binned stats - list<MainBin *>::iterator bi = bins.begin(); - list<MainBin *>::iterator be = bins.end(); - while (bi != be) { - MainBin *bin = *bi; - bin->activate(); - - i = allStats.begin(); - while (i != end) { - StatData *data = *i; - if (data->binned()) - data->reset(); - ++i; - } - ++bi; - } - - // restore bin - MainBin::curBin() = orig; -} - -void -Data::mapStat(void *stat, StatData *data) -{ - if (statMap.find(stat) != statMap.end()) - panic("shouldn't register stat twice!"); - - allStats.push_back(data); - -#ifndef NDEBUG - bool success = -#endif - (statMap.insert(make_pair(stat, data))).second; - assert(statMap.find(stat) != statMap.end()); - assert(success && "this should never fail"); -} - -void -Data::regBin(MainBin *bin, string _name) -{ - bins.push_back(bin); - DPRINTF(Stats, "registering %s\n", _name); -} - -void -Data::regPrint(void *stat) -{ - StatData *data = find(stat); - - if (data->flags & print) - return; - - data->flags |= print; - - list_t::iterator j = printStats.insert(printStats.end(), data); - inplace_merge(printStats.begin(), j, printStats.end(), StatData::less); -} - -Data & -StatDB() -{ - static Data db; - return db; -} - -} StatData * DataAccess::find() const { - return Database::StatDB().find(const_cast<void *>((const void *)this)); + return Database::find(const_cast<void *>((const void *)this)); } const StatData * getStatData(const void *stat) { - return Database::StatDB().find(const_cast<void *>(stat)); + return Database::find(const_cast<void *>(stat)); } void DataAccess::map(StatData *data) { - Database::StatDB().mapStat(this, data); + Database::regStat(this, data); } StatData * @@ -406,15 +91,14 @@ DataAccess::setInit() void DataAccess::setPrint() { - Database::StatDB().regPrint(this); + Database::regPrint(this); } StatData::StatData() : flags(none), precision(-1), prereq(0) { -#ifdef DEBUG - number = total_stats++; -#endif + static int count = 0; + id = count++; } StatData::~StatData() @@ -452,7 +136,7 @@ StatData::baseCheck() const { if (!(flags & init)) { #ifdef DEBUG - cprintf("this is stat number %d\n", number); + cprintf("this is stat number %d\n", id); #endif panic("Not all stats have been initialized"); return false; @@ -466,719 +150,15 @@ StatData::baseCheck() const return true; } -string -ValueToString(result_t value, DisplayMode mode, int precision) -{ - stringstream val; - - if (!isnan(value)) { - if (precision != -1) - val.precision(precision); - else if (value == rint(value)) - val.precision(0); - - val.unsetf(ios::showpoint); - val.setf(ios::fixed); - val << value; - } else { - val << (mode == mode_m5 ? "no value" : "<err: div-0>"); - } - - return val.str(); -} - -struct ScalarPrint -{ - result_t value; - string name; - string desc; - StatFlags flags; - DisplayMode mode; - int precision; - result_t pdf; - result_t cdf; - - ScalarPrint() - : value(0.0), flags(0), mode(DefaultMode), precision(0), - pdf(NAN), cdf(NAN) - {} - - void operator()(ostream &stream) const; -}; - -void -ScalarPrint::operator()(ostream &stream) const -{ - if (flags & nozero && value == 0.0 || - flags & nonan && isnan(value)) - return; - - stringstream pdfstr, cdfstr; - - if (!isnan(pdf)) - ccprintf(pdfstr, "%.2f%%", pdf * 100.0); - - if (!isnan(cdf)) - ccprintf(cdfstr, "%.2f%%", cdf * 100.0); - - if (mode == mode_simplescalar && flags & __substat) { - ccprintf(stream, "%32s %12s %10s %10s", name, - ValueToString(value, mode, precision), pdfstr, cdfstr); - } else { - ccprintf(stream, "%-40s %12s %10s %10s", name, - ValueToString(value, mode, precision), pdfstr, cdfstr); - } - - if (PrintDescriptions) { - if (!desc.empty()) - ccprintf(stream, " # %s", desc); - } - stream << endl; -} - -struct VectorPrint -{ - string name; - string desc; - vector<string> subnames; - vector<string> subdescs; - StatFlags flags; - DisplayMode mode; - int precision; - rvec_t vec; - result_t total; - - VectorPrint() - : subnames(0), subdescs(0), flags(0), mode(DefaultMode), - precision(-1), total(NAN) - {} - - void operator()(ostream &stream) const; -}; - -void -VectorPrint::operator()(std::ostream &stream) const -{ - int _size = vec.size(); - result_t _total = 0.0; - - if (flags & (pdf | cdf)) { - for (int i = 0; i < _size; ++i) { - _total += vec[i]; - } - } - - string base = name + ((mode == mode_simplescalar) ? "_" : "::"); - - ScalarPrint print; - print.name = name; - print.desc = desc; - print.precision = precision; - print.flags = flags; - - bool havesub = !subnames.empty(); - - if (_size == 1) { - print.value = vec[0]; - print(stream); - } else if (mode == mode_m5) { - for (int i = 0; i < _size; ++i) { - if (havesub && (i >= subnames.size() || subnames[i].empty())) - continue; - - print.name = base + (havesub ? subnames[i] : to_string(i)); - print.desc = subdescs.empty() ? desc : subdescs[i]; - print.value = vec[i]; - - if (_total && (flags & pdf)) { - print.pdf = vec[i] / _total; - print.cdf += print.pdf; - } - - print(stream); - } - - if (flags & ::Statistics::total) { - print.name = base + "total"; - print.desc = desc; - print.value = total; - print(stream); - } - } else { - if (flags & ::Statistics::total) { - print.value = total; - print(stream); - } - - result_t _pdf = 0.0; - result_t _cdf = 0.0; - if (flags & dist) { - ccprintf(stream, "%s.start_dist\n", name); - for (int i = 0; i < _size; ++i) { - print.name = havesub ? subnames[i] : to_string(i); - print.desc = subdescs.empty() ? desc : subdescs[i]; - print.flags |= __substat; - print.value = vec[i]; - - if (_total) { - _pdf = vec[i] / _total; - _cdf += _pdf; - } - - if (flags & pdf) - print.pdf = _pdf; - if (flags & cdf) - print.cdf = _cdf; - - print(stream); - } - ccprintf(stream, "%s.end_dist\n", name); - } else { - for (int i = 0; i < _size; ++i) { - if (havesub && subnames[i].empty()) - continue; - - print.name = base; - print.name += havesub ? subnames[i] : to_string(i); - print.desc = subdescs.empty() ? desc : subdescs[i]; - print.value = vec[i]; - - if (_total) { - _pdf = vec[i] / _total; - _cdf += _pdf; - } else { - _pdf = _cdf = NAN; - } - - if (flags & pdf) { - print.pdf = _pdf; - print.cdf = _cdf; - } - - print(stream); - } - } - } -} - -struct DistPrint -{ - string name; - string desc; - StatFlags flags; - DisplayMode mode; - int precision; - - result_t min_val; - result_t max_val; - result_t underflow; - result_t overflow; - rvec_t vec; - result_t sum; - result_t squares; - result_t samples; - - int min; - int max; - int bucket_size; - int size; - bool fancy; - - void operator()(ostream &stream) const; -}; - -void -DistPrint::operator()(ostream &stream) const -{ - if (fancy) { - ScalarPrint print; - string base = name + ((mode == mode_m5) ? "::" : "_"); - - print.precision = precision; - print.flags = flags; - print.mode = mode; - print.desc = desc; - - print.name = base + "mean"; - print.value = samples ? sum / samples : NAN; - print(stream); - - print.name = base + "stdev"; - print.value = samples ? sqrt((samples * squares - sum * sum) / - (samples * (samples - 1.0))) : NAN; - print(stream); - - print.name = "**Ignore: " + base + "TOT"; - print.value = samples; - print(stream); - return; - } - - assert(size == vec.size()); - - result_t total = 0.0; - - total += underflow; - for (int i = 0; i < size; ++i) - total += vec[i]; - total += overflow; - - string base = name + (mode == mode_m5 ? "::" : "."); - - ScalarPrint print; - print.desc = (mode == mode_m5) ? desc : ""; - print.flags = flags; - print.mode = mode; - print.precision = precision; - - if (mode == mode_simplescalar) { - ccprintf(stream, "%-42s", base + "start_dist"); - if (PrintDescriptions && !desc.empty()) - ccprintf(stream, " # %s", desc); - stream << endl; - } - - print.name = base + "samples"; - print.value = samples; - print(stream); - - print.name = base + "min_value"; - print.value = min_val; - print(stream); - - if (mode == mode_m5 || underflow > 0.0) { - print.name = base + "underflows"; - print.value = underflow; - if (mode == mode_m5 && total) { - print.pdf = underflow / total; - print.cdf += print.pdf; - } - print(stream); - } - - - if (mode == mode_m5) { - for (int i = 0; i < size; ++i) { - stringstream namestr; - namestr << name; - - int low = i * bucket_size + min; - int high = ::min((i + 1) * bucket_size + min - 1, max); - namestr << low; - if (low < high) - namestr << "-" << high; - - print.name = namestr.str(); - print.value = vec[i]; - if (total) { - print.pdf = vec[i] / total; - print.cdf += print.pdf; - } - print(stream); - } - - } else { - int _min; - result_t _pdf; - result_t _cdf = 0.0; - - print.flags = flags | __substat; - - for (int i = 0; i < size; ++i) { - if (flags & nozero && vec[i] == 0.0 || - flags & nonan && isnan(vec[i])) - continue; - - _min = i * bucket_size + min; - _pdf = vec[i] / total * 100.0; - _cdf += _pdf; - - - print.name = ValueToString(_min, mode, 0); - print.value = vec[i]; - print.pdf = (flags & pdf) ? _pdf : NAN; - print.cdf = (flags & cdf) ? _cdf : NAN; - print(stream); - } - - print.flags = flags; - } - - if (mode == mode_m5 || overflow > 0.0) { - print.name = base + "overflows"; - print.value = overflow; - if (mode == mode_m5 && total) { - print.pdf = overflow / total; - print.cdf += print.pdf; - } else { - print.pdf = NAN; - print.cdf = NAN; - } - print(stream); - } - - print.pdf = NAN; - print.cdf = NAN; - - if (mode != mode_simplescalar) { - print.name = base + "total"; - print.value = total; - print(stream); - } - - print.name = base + "max_value"; - print.value = max_val; - print(stream); - - if (mode != mode_simplescalar && samples != 0) { - print.name = base + "mean"; - print.value = sum / samples; - print(stream); - - print.name = base + "stdev"; - print.value = sqrt((samples * squares - sum * sum) / - (samples * (samples - 1.0))); - print(stream); - } - - if (mode == mode_simplescalar) - ccprintf(stream, "%send_dist\n\n", base); -} void -ScalarDataBase::display(ostream &stream, DisplayMode mode) const -{ - ScalarPrint print; - print.value = val(); - print.name = name; - print.desc = desc; - print.flags = flags; - print.mode = mode; - print.precision = precision; - - print(stream); -} - -void -VectorDataBase::display(ostream &stream, DisplayMode mode) const -{ - int size = this->size(); - const_cast<VectorDataBase *>(this)->update(); - - VectorPrint print; - - print.name = name; - print.desc = desc; - print.flags = flags; - print.mode = mode; - print.precision = precision; - print.vec = val(); - print.total = total(); - - if (!subnames.empty()) { - for (int i = 0; i < size; ++i) { - if (!subnames[i].empty()) { - print.subnames = subnames; - print.subnames.resize(size); - for (int i = 0; i < size; ++i) { - if (!subnames[i].empty() && !subdescs[i].empty()) { - print.subdescs = subdescs; - print.subdescs.resize(size); - break; - } - } - break; - } - } - } - - print(stream); -} - -void -Vector2dDataBase::display(ostream &stream, DisplayMode mode) const -{ - const_cast<Vector2dDataBase *>(this)->update(); - - bool havesub = false; - VectorPrint print; - - print.subnames = y_subnames; - print.flags = flags; - print.mode = mode; - print.precision = precision; - - if (!subnames.empty()) { - for (int i = 0; i < x; ++i) - if (!subnames[i].empty()) - havesub = true; - } - - rvec_t tot_vec(y); - result_t super_total = 0.0; - for (int i = 0; i < x; ++i) { - if (havesub && (i >= subnames.size() || subnames[i].empty())) - continue; - - int iy = i * y; - rvec_t yvec(y); - - result_t total = 0.0; - for (int j = 0; j < y; ++j) { - yvec[j] = vec[iy + j]; - tot_vec[j] += yvec[j]; - total += yvec[j]; - super_total += yvec[j]; - } - - print.name = name + "_" + (havesub ? subnames[i] : to_string(i)); - print.desc = desc; - print.vec = yvec; - print.total = total; - print(stream); - } - - if ((flags & ::Statistics::total) && (x > 1)) { - print.name = name; - print.desc = desc; - print.vec = tot_vec; - print.total = super_total; - print(stream); - } -} - -void -DistDataBase::display(ostream &stream, DisplayMode mode) const -{ - const_cast<DistDataBase *>(this)->update(); - - DistPrint print; - - print.name = name; - print.desc = desc; - print.flags = flags; - print.mode = mode; - print.precision = precision; - - print.min_val = data.min_val; - print.max_val = data.max_val; - print.underflow = data.underflow; - print.overflow = data.overflow; - print.vec = data.vec; - print.sum = data.sum; - print.squares = data.squares; - print.samples = data.samples; - - print.min = data.min; - print.max = data.max; - print.bucket_size = data.bucket_size; - print.size = data.size; - print.fancy = data.fancy; - - print(stream); -} - -void -VectorDistDataBase::display(ostream &stream, DisplayMode mode) const -{ - const_cast<VectorDistDataBase *>(this)->update(); - - for (int i = 0; i < size(); ++i) { - DistPrint print; - - print.name = name + - (subnames[i].empty() ? ("_" + to_string(i)) : subnames[i]); - print.desc = subdescs[i].empty() ? desc : subdescs[i]; - print.flags = flags; - print.mode = mode; - print.precision = precision; - - print.min_val = data[i].min_val; - print.max_val = data[i].max_val; - print.underflow = data[i].underflow; - print.overflow = data[i].overflow; - print.vec = data[i].vec; - print.sum = data[i].sum; - print.squares = data[i].squares; - print.samples = data[i].samples; - - print.min = data[i].min; - print.max = data[i].max; - print.bucket_size = data[i].bucket_size; - print.size = data[i].size; - print.fancy = data[i].fancy; - - print(stream); - } -} - -void -ScalarDataBase::python(Python &py) const -{ - py.name("Scalar"); - py.qarg(name); - py.qqqarg(desc); - py.kwarg("binned", binned()); - py.kwarg("precision", precision); - py.kwarg("flags", flags); - if (prereq) - py.qkwarg("prereq", prereq->name); - py.kwarg("value", val()); - py.nameEnd(); -} - -void -VectorDataBase::python(Python &py) const -{ - const_cast<VectorDataBase *>(this)->update(); - - py.name("Vector"); - py.qarg(name); - py.qqqarg(desc); - py.kwarg("binned", binned()); - py.kwarg("precision", precision); - py.kwarg("flags", flags); - if (prereq) - py.qkwarg("prereq", prereq->name); - py.kwarg("value", val()); - if (!subnames.empty()) - py.qkwarg("subnames", subnames); - if (!subdescs.empty()) - py.qkwarg("subdescs", subdescs); - py.nameEnd(); -} - -void -DistDataData::python(Python &py, const string &name) const -{ - string s = name.empty() ? "" : name + "="; - - if (samples == 0 || fancy) - s += "SimpleDist"; - else - s += "FullDist"; - - py.name(s); - py.arg(sum); - py.arg(squares); - py.arg(samples); - if (samples && !fancy) { - py.arg(min_val); - py.arg(min_val); - py.arg(underflow); - py.arg(vec); - py.arg(overflow); - py.arg(min); - py.arg(max); - py.arg(bucket_size); - py.arg(size); - } - py.nameEnd(); -} - -void -FormulaDataBase::python(Python &py) const -{ - const_cast<FormulaDataBase *>(this)->update(); - - py.name("Formula"); - py.qarg(name); - py.qqqarg(desc); - py.kwarg("binned", binned()); - py.kwarg("precision", precision); - py.kwarg("flags", flags); - if (prereq) - py.qkwarg("prereq", prereq->name); - py.qkwarg("formula", str()); - if (!subnames.empty()) - py.qkwarg("subnames", subnames); - if (!subdescs.empty()) - py.qkwarg("subdescs", subdescs); - py.nameEnd(); -} - -void -DistDataBase::python(Python &py) const -{ - const_cast<DistDataBase *>(this)->update(); - - py.name("Dist"); - py.qarg(name); - py.qqqarg(desc); - py.kwarg("binned", binned()); - py.kwarg("precision", precision); - py.kwarg("flags", flags); - if (prereq) - py.qkwarg("prereq", prereq->name); - data.python(py, "dist"); - py.nameEnd(); -} - -void -VectorDistDataBase::python(Python &py) const -{ - const_cast<VectorDistDataBase *>(this)->update(); - - py.name("VectorDist"); - py.qarg(name); - py.qqqarg(desc); - py.kwarg("binned", binned()); - py.kwarg("precision", precision); - py.kwarg("flags", flags); - if (prereq) - py.qkwarg("prereq", prereq->name); - if (!subnames.empty()) - py.qkwarg("subnames", subnames); - if (!subdescs.empty()) - py.qkwarg("subdescs", subdescs); - - py.tuple("dist"); - typedef std::vector<DistDataData>::const_iterator iter; - iter i = data.begin(); - iter end = data.end(); - while (i != end) { - i->python(py, ""); - ++i; - } - py.tupleEnd(); - py.nameEnd(); -} - -void -Vector2dDataBase::python(Python &py) const -{ - const_cast<Vector2dDataBase *>(this)->update(); - - py.name("Vector2d"); - py.qarg(name); - py.qqqarg(desc); - py.kwarg("binned", binned()); - py.kwarg("precision", precision); - py.kwarg("flags", flags); - if (prereq) - py.qkwarg("prereq", prereq->name); - - py.kwarg("value", vec); - if (!subnames.empty()) - py.qkwarg("subnames", subnames); - if (!subdescs.empty()) - py.qkwarg("subdescs", subdescs); - if (!y_subnames.empty()) - py.qkwarg("ysubnames", y_subnames); - - py.kwarg("x", x); - py.kwarg("y", y); - py.nameEnd(); -} - -void -FormulaBase::val(rvec_t &vec) const +FormulaBase::result(VResult &vec) const { if (root) - vec = root->val(); + vec = root->result(); } -result_t +Result FormulaBase::total() const { return root ? root->total() : 0.0; @@ -1207,8 +187,8 @@ FormulaBase::reset() bool FormulaBase::zero() const { - rvec_t vec; - val(vec); + VResult vec; + result(vec); for (int i = 0; i < vec.size(); ++i) if (vec[i] != 0.0) return false; @@ -1250,7 +230,7 @@ const Formula & Formula::operator+=(Temp r) { if (root) - root = NodePtr(new BinaryNode<std::plus<result_t> >(root, r)); + root = NodePtr(new BinaryNode<std::plus<Result> >(root, r)); else root = r; assert(size()); @@ -1260,7 +240,7 @@ Formula::operator+=(Temp r) MainBin::MainBin(const string &name) : _name(name), mem(NULL), memsize(-1) { - Database::StatDB().regBin(this, name); + Database::regBin(this, name); } MainBin::~MainBin() @@ -1287,41 +267,83 @@ MainBin::memory(off_t off) void check() { - Database::StatDB().check(); -} + typedef Database::stat_list_t::iterator iter_t; -void -dump(ostream &stream, DisplayMode mode) -{ - Database::StatDB().dump(stream, mode); -} + iter_t i, end = Database::stats().end(); + for (i = Database::stats().begin(); i != end; ++i) { + StatData *data = *i; + assert(data); + data->check(); + } -void -python_start(const string &file) -{ - Database::StatDB().python_start(file); -} + int j = 0; + for (i = Database::stats().begin(); i != end; ++i) { + StatData *data = *i; + if (!(data->flags & print)) + data->name = "__Stat" + to_string(j++); + } -void -python_dump(const string &name, const string &subname) -{ - Database::StatDB().python_dump(name, subname); -} + Database::stats().sort(StatData::less); + + if (i == end) + return; + + iter_t last = i; + ++i; + + for (i = Database::stats().begin(); i != end; ++i) { + if ((*i)->name == (*last)->name) + panic("same name used twice! name=%s\n", (*i)->name); + last = i; + } +} CallbackQueue resetQueue; void -registerResetCallback(Callback *cb) +reset() { - resetQueue.add(cb); + // reset non-binned stats + Database::stat_list_t::iterator i = Database::stats().begin(); + Database::stat_list_t::iterator end = Database::stats().end(); + while (i != end) { + StatData *data = *i; + if (!data->binned()) + data->reset(); + ++i; + } + + // save the bin so we can go back to where we were + MainBin *orig = MainBin::curBin(); + + // reset binned stats + Database::bin_list_t::iterator bi = Database::bins().begin(); + Database::bin_list_t::iterator be = Database::bins().end(); + while (bi != be) { + MainBin *bin = *bi; + bin->activate(); + + i = Database::stats().begin(); + while (i != end) { + StatData *data = *i; + if (data->binned()) + data->reset(); + ++i; + } + ++bi; + } + + // restore bin + MainBin::curBin() = orig; + + resetQueue.process(); } void -reset() +registerResetCallback(Callback *cb) { - Database::StatDB().reset(); - resetQueue.process(); + resetQueue.add(cb); } -} // namespace Statistics +/* namespace Statistics */ } diff --git a/base/statistics.hh b/base/statistics.hh index 0dad31a5a..e7fc18d74 100644 --- a/base/statistics.hh +++ b/base/statistics.hh @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003 The Regents of The University of Michigan + * Copyright (c) 2003-2004 The Regents of The University of Michigan * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -42,8 +42,8 @@ * VectorStandardDeviation totals * Document Namespaces */ -#ifndef __STATISTICS_HH__ -#define __STATISTICS_HH__ +#ifndef __BASE_STATISTICS_HH__ +#define __BASE_STATISTICS_HH__ #include <algorithm> #include <cassert> @@ -58,66 +58,19 @@ #include "base/intmath.hh" #include "base/refcnt.hh" #include "base/str.hh" +#include "base/stats/bin.hh" +#include "base/stats/flags.hh" +#include "base/stats/visit.hh" +#include "base/stats/types.hh" #include "sim/host.hh" -#ifndef NAN -float __nan(); -/** Define Not a number. */ -#define NAN (__nan()) -/** Need to define __nan() */ -#define __M5_NAN -#endif - class Callback; -class Python; /** The current simulated cycle. */ extern Tick curTick; /* A namespace for all of the Statistics */ namespace Statistics { -/** All results are doubles. */ -typedef double result_t; -/** A vector to hold results. */ -typedef std::vector<result_t> rvec_t; - -/** - * Define the storage for format flags. - * @todo Can probably shrink this. - */ -typedef u_int32_t StatFlags; - -/** Nothing extra to print. */ -const StatFlags none = 0x00000000; -/** This Stat is Initialized */ -const StatFlags init = 0x00000001; -/** Print this stat. */ -const StatFlags print = 0x00000002; -/** Print the total. */ -const StatFlags total = 0x00000010; -/** Print the percent of the total that this entry represents. */ -const StatFlags pdf = 0x00000020; -/** Print the cumulative percentage of total upto this entry. */ -const StatFlags cdf = 0x00000040; -/** Print the distribution. */ -const StatFlags dist = 0x00000080; -/** Don't print if this is zero. */ -const StatFlags nozero = 0x00000100; -/** Don't print if this is NAN */ -const StatFlags nonan = 0x00000200; -/** Used for SS compatability. */ -const StatFlags __substat = 0x80000000; - -/** Mask of flags that can't be set directly */ -const StatFlags __reserved = init | print | __substat; - -enum DisplayMode -{ - mode_m5, - mode_simplescalar -}; - -extern DisplayMode DefaultMode; /* Contains the statistic implementation details */ ////////////////////////////////////////////////////////////////////// @@ -135,10 +88,13 @@ struct StatData StatFlags flags; /** The display precision. */ int precision; - - /** A pointer to a prerequisite Stat. */ const StatData *prereq; + /** + * A unique stat ID for each stat in the simulator. + * Can be used externally for lookups as well as for debugging. + */ + int id; StatData(); virtual ~StatData(); @@ -149,14 +105,6 @@ struct StatData virtual bool binned() const = 0; /** - * Print this stat to the given ostream. - * @param stream The stream to print to. - */ - virtual void display(std::ostream &stream, DisplayMode mode) const = 0; - virtual void python(Python &py) const = 0; - bool dodisplay() const { return !prereq || !prereq->zero(); } - - /** * Reset the corresponding stat to the default state. */ virtual void reset() = 0; @@ -176,6 +124,11 @@ struct StatData bool baseCheck() const; /** + * Visitor entry for outputing statistics data + */ + virtual void visit(Visit &visitor) = 0; + + /** * Checks if the first stat's name is alphabetically less than the second. * This function breaks names up at periods and considers each subname * separately. @@ -184,51 +137,46 @@ struct StatData * @return stat1's name is alphabetically before stat2's */ static bool less(StatData *stat1, StatData *stat2); - -#ifdef DEBUG - int number; -#endif }; -struct ScalarDataBase : public StatData +struct ScalarData : public StatData { - virtual result_t val() const = 0; - virtual result_t total() const = 0; - - virtual void display(std::ostream &stream, DisplayMode mode) const; - virtual void python(Python &py) const; + virtual Counter value() const = 0; + virtual Result result() const = 0; + virtual Result total() const = 0; }; -template <class T> -class ScalarData : public ScalarDataBase +template <class Stat> +class ScalarStatData : public ScalarData { protected: - T &s; + Stat &s; public: - ScalarData(T &stat) : s(stat) {} + ScalarStatData(Stat &stat) : s(stat) {} virtual bool binned() const { return s.binned(); } virtual bool check() const { return s.check(); } - virtual result_t val() const { return s.val(); } - virtual result_t total() const { return s.total(); } + virtual Counter value() const { return s.value(); } + virtual Result result() const { return s.result(); } + virtual Result total() const { return s.total(); } virtual void reset() { s.reset(); } virtual bool zero() const { return s.zero(); } + + virtual void visit(Visit &visitor) { visitor.visit(*this); } }; -struct VectorDataBase : public StatData +struct VectorData : public StatData { /** Names and descriptions of subfields. */ mutable std::vector<std::string> subnames; mutable std::vector<std::string> subdescs; - virtual void display(std::ostream &stream, DisplayMode mode) const; - virtual void python(Python &py) const; - virtual size_t size() const = 0; - virtual const rvec_t &val() const = 0; - virtual result_t total() const = 0; - virtual void update() + virtual const VCounter &value() const = 0; + virtual const VResult &result() const = 0; + virtual Result total() const = 0; + void update() { if (!subnames.empty()) { int s = size(); @@ -241,15 +189,16 @@ struct VectorDataBase : public StatData } }; -template <class T> -class VectorData : public VectorDataBase +template <class Stat> +class VectorStatData : public VectorData { protected: - T &s; - mutable rvec_t vec; + Stat &s; + mutable VCounter cvec; + mutable VResult rvec; public: - VectorData(T &stat) : s(stat) {} + VectorStatData(Stat &stat) : s(stat) {} virtual bool binned() const { return s.binned(); } virtual bool check() const { return s.check(); } @@ -257,66 +206,70 @@ class VectorData : public VectorDataBase virtual void reset() { s.reset(); } virtual size_t size() const { return s.size(); } - virtual const rvec_t &val() const + virtual VCounter &value() const { - s.val(vec); - return vec; + s.value(cvec); + return cvec; + } + virtual const VResult &result() const + { + s.result(rvec); + return rvec; } - virtual result_t total() const { return s.total(); } - virtual void update() + virtual Result total() const { return s.total(); } + virtual void visit(Visit &visitor) { - VectorDataBase::update(); + update(); s.update(this); + visitor.visit(*this); } }; struct DistDataData { - result_t min_val; - result_t max_val; - result_t underflow; - result_t overflow; - rvec_t vec; - result_t sum; - result_t squares; - result_t samples; - - int min; - int max; - int bucket_size; + Counter min_val; + Counter max_val; + Counter underflow; + Counter overflow; + VCounter cvec; + Counter sum; + Counter squares; + Counter samples; + + Counter min; + Counter max; + Counter bucket_size; int size; bool fancy; - - void python(Python &py, const std::string &name) const; }; -struct DistDataBase : public StatData +struct DistData : public StatData { /** Local storage for the entry values, used for printing. */ DistDataData data; - - virtual void display(std::ostream &stream, DisplayMode mode) const; - virtual void python(Python &py) const; - virtual void update() = 0; }; -template <class T> -class DistData : public DistDataBase +template <class Stat> +class DistStatData : public DistData { protected: - T &s; + Stat &s; public: - DistData(T &stat) : s(stat) {} + DistStatData(Stat &stat) : s(stat) {} virtual bool binned() const { return s.binned(); } virtual bool check() const { return s.check(); } virtual void reset() { s.reset(); } virtual bool zero() const { return s.zero(); } - virtual void update() { return s.update(this); } + virtual void visit(Visit &visitor) + { + s.update(this); + visitor.visit(*this); + } }; -struct VectorDistDataBase : public StatData +struct VectorDistData : public StatData { std::vector<DistDataData> data; @@ -325,12 +278,10 @@ struct VectorDistDataBase : public StatData mutable std::vector<std::string> subdescs; /** Local storage for the entry values, used for printing. */ - mutable rvec_t vec; + mutable VResult rvec; virtual size_t size() const = 0; - virtual void display(std::ostream &stream, DisplayMode mode) const; - virtual void python(Python &py) const; - virtual void update() + void update() { int s = size(); if (subnames.size() < s) @@ -341,29 +292,30 @@ struct VectorDistDataBase : public StatData } }; -template <class T> -class VectorDistData : public VectorDistDataBase +template <class Stat> +class VectorDistStatData : public VectorDistData { protected: - T &s; - typedef typename T::bin_t bin_t; + Stat &s; + typedef typename Stat::bin_t bin_t; public: - VectorDistData(T &stat) : s(stat) {} + VectorDistStatData(Stat &stat) : s(stat) {} virtual bool binned() const { return bin_t::binned; } virtual bool check() const { return s.check(); } virtual void reset() { s.reset(); } virtual size_t size() const { return s.size(); } virtual bool zero() const { return s.zero(); } - virtual void update() + virtual void visit(Visit &visitor) { - VectorDistDataBase::update(); - return s.update(this); + update(); + s.update(this); + visitor.visit(*this); } }; -struct Vector2dDataBase : public StatData +struct Vector2dData : public StatData { /** Names and descriptions of subfields. */ std::vector<std::string> subnames; @@ -371,37 +323,36 @@ struct Vector2dDataBase : public StatData std::vector<std::string> y_subnames; /** Local storage for the entry values, used for printing. */ - mutable rvec_t vec; + mutable VCounter cvec; mutable int x; mutable int y; - virtual void display(std::ostream &stream, DisplayMode mode) const; - virtual void python(Python &py) const; - virtual void update() + void update() { if (subnames.size() < x) subnames.resize(x); } }; -template <class T> -class Vector2dData : public Vector2dDataBase +template <class Stat> +class Vector2dStatData : public Vector2dData { protected: - T &s; - typedef typename T::bin_t bin_t; + Stat &s; + typedef typename Stat::bin_t bin_t; public: - Vector2dData(T &stat) : s(stat) {} + Vector2dStatData(Stat &stat) : s(stat) {} virtual bool binned() const { return bin_t::binned; } virtual bool check() const { return s.check(); } virtual void reset() { s.reset(); } virtual bool zero() const { return s.zero(); } - virtual void update() + virtual void visit(Visit &visitor) { - Vector2dDataBase::update(); + update(); s.update(this); + visitor.visit(*this); } }; @@ -502,8 +453,8 @@ class Wrap : public Child * @param prereq The prerequisite stat. * @return A reference to this stat. */ - template <class T> - Parent &prereq(const T &prereq) + template <class Stat> + Parent &prereq(const Stat &prereq) { statData()->prereq = prereq.statData(); return self(); @@ -571,9 +522,9 @@ class WrapVec2d : public WrapVec<Parent, Child, Data> Parent &ysubname(int index, const std::string subname) { Data<Child> *data = statData(); - assert(i < y); + assert(index < y); data->y_subnames.resize(y); - data->y_subnames[i] = subname.c_str(); + data->y_subnames[index] = subname.c_str(); return self(); } }; @@ -587,7 +538,6 @@ class WrapVec2d : public WrapVec<Parent, Child, Data> /** * Templatized storage and interface for a simple scalar stat. */ -template <typename T> struct StatStor { public: @@ -596,59 +546,54 @@ struct StatStor private: /** The statistic value. */ - T data; - static T &Null() - { - static T __T = T(); - return __T; - } + Counter data; public: /** * Builds this storage element and calls the base constructor of the * datatype. */ - StatStor(const Params &) : data(Null()) {} + StatStor(const Params &) : data(Counter()) {} /** * The the stat to the given value. * @param val The new value. * @param p The paramters of this storage type. */ - void set(T val, const Params &p) { data = val; } + void set(Counter val, const Params &p) { data = val; } /** * Increment the stat by the given value. * @param val The new value. * @param p The paramters of this storage type. */ - void inc(T val, const Params &p) { data += val; } + void inc(Counter val, const Params &p) { data += val; } /** * Decrement the stat by the given value. * @param val The new value. * @param p The paramters of this storage type. */ - void dec(T val, const Params &p) { data -= val; } + void dec(Counter val, const Params &p) { data -= val; } /** - * Return the value of this stat as a result type. - * @param p The parameters of this storage type. + * Return the value of this stat as its base type. + * @param p The params of this storage type. * @return The value of this stat. */ - result_t val(const Params &p) const { return (result_t)data; } + Counter value(const Params &p) const { return data; } /** - * Return the value of this stat as its base type. - * @param p The params of this storage type. + * Return the value of this stat as a result type. + * @param p The parameters of this storage type. * @return The value of this stat. */ - T value(const Params &p) const { return data; } + Result result(const Params &p) const { return (Result)data; } /** * Reset stat value to default */ - void reset() { data = Null(); } + void reset() { data = Counter(); } /** * @return true if zero value */ - bool zero() const { return data == Null(); } + bool zero() const { return data == Counter(); } }; /** @@ -659,7 +604,6 @@ struct StatStor * among other things. * @todo add lateny to the stat and fix binning. */ -template <typename T> struct AvgStor { public: @@ -670,12 +614,12 @@ struct AvgStor * The current count. We stash this here because the current * value is not a binned value. */ - T current; + Counter current; }; private: /** The total count for all cycles. */ - mutable result_t total; + mutable Result total; /** The cycle that current last changed. */ mutable Tick last; @@ -683,7 +627,7 @@ struct AvgStor /** * Build and initializes this stat storage. */ - AvgStor(Params &p) : total(0), last(0) { p.current = T(); } + AvgStor(Params &p) : total(0), last(0) { p.current = Counter(); } /** * Set the current count to the one provided, update the total and last @@ -691,7 +635,7 @@ struct AvgStor * @param val The new count. * @param p The parameters for this storage. */ - void set(T val, Params &p) { + void set(Counter val, Params &p) { total += p.current * (curTick - last); last = curTick; p.current = val; @@ -702,34 +646,35 @@ struct AvgStor * @param val The amount to increment. * @param p The parameters for this storage. */ - void inc(T val, Params &p) { set(p.current + val, p); } + void inc(Counter val, Params &p) { set(p.current + val, p); } /** * Deccrement the current count by the provided value, calls set. * @param val The amount to decrement. * @param p The parameters for this storage. */ - void dec(T val, Params &p) { set(p.current - val, p); } + void dec(Counter val, Params &p) { set(p.current - val, p); } + + /** + * Return the current count. + * @param p The parameters for this storage. + * @return The current count. + */ + Counter value(const Params &p) const { return p.current; } /** * Return the current average. * @param p The parameters for this storage. * @return The current average. */ - result_t val(const Params &p) const { + Result result(const Params &p) const + { total += p.current * (curTick - last); last = curTick; - return (result_t)(total + p.current) / (result_t)(curTick + 1); + return (Result)(total + p.current) / (Result)(curTick + 1); } /** - * Return the current count. - * @param p The parameters for this storage. - * @return The current count. - */ - T value(const Params &p) const { return p.current; } - - /** * Reset stat value to default */ void reset() @@ -749,16 +694,14 @@ struct AvgStor * Storage template. The storage for this stat is held within the Bin class. * This allows for breaking down statistics across multiple bins easily. */ -template <typename T, template <typename T> class Storage, class Bin> +template <class Storage, class Bin> class ScalarBase : public DataAccess { public: - /** Define the type of the storage class. */ - typedef Storage<T> storage_t; /** Define the params of the storage class. */ - typedef typename storage_t::Params params_t; + typedef typename Storage::Params params_t; /** Define the bin type. */ - typedef typename Bin::Bin<storage_t> bin_t; + typedef typename Bin::Bin<Storage> bin_t; protected: /** The bin of this stat. */ @@ -771,12 +714,12 @@ class ScalarBase : public DataAccess * Retrieve the storage from the bin. * @return The storage object for this stat. */ - storage_t *data() { return bin.data(params); } + Storage *data() { return bin.data(params); } /** * Retrieve a const pointer to the storage from the bin. * @return A const pointer to the storage object for this stat. */ - const storage_t *data() const + const Storage *data() const { bin_t *_bin = const_cast<bin_t *>(&bin); params_t *_params = const_cast<params_t *>(¶ms); @@ -798,7 +741,7 @@ class ScalarBase : public DataAccess * Return the current value of this stat as its base type. * @return The current value. */ - T value() const { return data()->value(params); } + Counter value() const { return data()->value(params); } public: /** @@ -869,11 +812,14 @@ class ScalarBase : public DataAccess */ void reset() { bin.reset(); } - result_t val() { return data()->val(params); } + Counter value() { return data()->value(params); } + + Result result() { return data()->result(params); } - result_t total() { return val(); } + Result total() { return result(); } + + bool zero() { return result() == 0.0; } - bool zero() { return val() == 0.0; } }; ////////////////////////////////////////////////////////////////////// @@ -881,23 +827,21 @@ class ScalarBase : public DataAccess // Vector Statistics // ////////////////////////////////////////////////////////////////////// -template <typename T, template <typename T> class Storage, class Bin> +template <class Storage, class Bin> class ScalarProxy; /** * Implementation of a vector of stats. The type of stat is determined by the * Storage class. @sa ScalarBase */ -template <typename T, template <typename T> class Storage, class Bin> +template <class Storage, class Bin> class VectorBase : public DataAccess { public: - /** Define the type of the storage class. */ - typedef Storage<T> storage_t; /** Define the params of the storage class. */ - typedef typename storage_t::Params params_t; + typedef typename Storage::Params params_t; /** Define the bin type. */ - typedef typename Bin::VectorBin<storage_t> bin_t; + typedef typename Bin::VectorBin<Storage> bin_t; protected: /** The bin of this stat. */ @@ -911,14 +855,14 @@ class VectorBase : public DataAccess * @param index The vector index to access. * @return The storage object at the given index. */ - storage_t *data(int index) { return bin.data(index, params); } + Storage *data(int index) { return bin.data(index, params); } /** * Retrieve a const pointer to the storage from the bin * for the given index. * @param index The vector index to access. * @return A const pointer to the storage object at the given index. */ - const storage_t *data(int index) const + const Storage *data(int index) const { bin_t *_bin = const_cast<bin_t *>(&bin); params_t *_params = const_cast<params_t *>(¶ms); @@ -933,15 +877,22 @@ class VectorBase : public DataAccess const VectorBase &operator=(const VectorBase &); public: + void value(VCounter &vec) const + { + vec.resize(size()); + for (int i = 0; i < size(); ++i) + vec[i] = data(i)->value(params); + } + /** * Copy the values to a local vector and return a reference to it. * @return A reference to a vector of the stat values. */ - void val(rvec_t &vec) const + void result(VResult &vec) const { vec.resize(size()); for (int i = 0; i < size(); ++i) - vec[i] = data(i)->val(params); + vec[i] = data(i)->result(params); } /** @@ -953,10 +904,10 @@ class VectorBase : public DataAccess * Return a total of all entries in this vector. * @return The total of all vector entries. */ - result_t total() const { - result_t total = 0.0; + Result total() const { + Result total = 0.0; for (int i = 0; i < size(); ++i) - total += data(i)->val(params); + total += data(i)->result(params); return total; } @@ -980,14 +931,14 @@ class VectorBase : public DataAccess VectorBase() {} /** Friend this class with the associated scalar proxy. */ - friend class ScalarProxy<T, Storage, Bin>; + friend class ScalarProxy<Storage, Bin>; /** * Return a reference (ScalarProxy) to the stat at the given index. * @param index The vector index to access. * @return A reference of the stat. */ - ScalarProxy<T, Storage, Bin> operator[](int index); + ScalarProxy<Storage, Bin> operator[](int index); void update(StatData *data) {} }; @@ -998,16 +949,14 @@ const StatData * getStatData(const void *stat); * A proxy class to access the stat at a given index in a VectorBase stat. * Behaves like a ScalarBase. */ -template <typename T, template <typename T> class Storage, class Bin> +template <class Storage, class Bin> class ScalarProxy { public: - /** Define the type of the storage class. */ - typedef Storage<T> storage_t; /** Define the params of the storage class. */ - typedef typename storage_t::Params params_t; + typedef typename Storage::Params params_t; /** Define the bin type. */ - typedef typename Bin::VectorBin<storage_t> bin_t; + typedef typename Bin::VectorBin<Storage> bin_t; private: /** Pointer to the bin in the parent VectorBase. */ @@ -1024,12 +973,12 @@ class ScalarProxy * Retrieve the storage from the bin. * @return The storage from the bin for this stat. */ - storage_t *data() { return bin->data(index, *params); } + Storage *data() { return bin->data(index, *params); } /** * Retrieve a const pointer to the storage from the bin. * @return A const pointer to the storage for this stat. */ - const storage_t *data() const + const Storage *data() const { bin_t *_bin = const_cast<bin_t *>(bin); params_t *_params = const_cast<params_t *>(params); @@ -1038,15 +987,16 @@ class ScalarProxy public: /** - * Return the current value of this statas a result type. + * Return the current value of this stat as its base type. * @return The current value. */ - result_t val() const { return data()->val(*params); } + Counter value() const { return data()->value(*params); } + /** - * Return the current value of this stat as its base type. + * Return the current value of this statas a result type. * @return The current value. */ - T value() const { return data()->value(*params); } + Result result() const { return data()->result(*params); } public: /** @@ -1144,24 +1094,23 @@ class ScalarProxy } }; -template <typename T, template <typename T> class Storage, class Bin> -inline ScalarProxy<T, Storage, Bin> -VectorBase<T, Storage, Bin>::operator[](int index) +template <class Storage, class Bin> +inline ScalarProxy<Storage, Bin> +VectorBase<Storage, Bin>::operator[](int index) { assert (index >= 0 && index < size()); - return ScalarProxy<T, Storage, Bin>(bin, params, index, this); + return ScalarProxy<Storage, Bin>(bin, params, index, this); } -template <typename T, template <typename T> class Storage, class Bin> +template <class Storage, class Bin> class VectorProxy; -template <typename T, template <typename T> class Storage, class Bin> +template <class Storage, class Bin> class Vector2dBase : public DataAccess { public: - typedef Storage<T> storage_t; - typedef typename storage_t::Params params_t; - typedef typename Bin::VectorBin<storage_t> bin_t; + typedef typename Storage::Params params_t; + typedef typename Bin::VectorBin<Storage> bin_t; protected: size_t x; @@ -1170,8 +1119,8 @@ class Vector2dBase : public DataAccess params_t params; protected: - storage_t *data(int index) { return bin.data(index, params); } - const storage_t *data(int index) const + Storage *data(int index) { return bin.data(index, params); } + const Storage *data(int index) const { bin_t *_bin = const_cast<bin_t *>(&bin); params_t *_params = const_cast<params_t *>(¶ms); @@ -1186,18 +1135,18 @@ class Vector2dBase : public DataAccess public: Vector2dBase() {} - void update(Vector2dDataBase *data) + void update(Vector2dData *data) { int size = this->size(); - data->vec.resize(size); + data->cvec.resize(size); for (int i = 0; i < size; ++i) - data->vec[i] = this->data(i)->val(params); + data->cvec[i] = this->data(i)->value(params); } std::string ysubname(int i) const { return (*y_subnames)[i]; } - friend class VectorProxy<T, Storage, Bin>; - VectorProxy<T, Storage, Bin> operator[](int index); + friend class VectorProxy<Storage, Bin>; + VectorProxy<Storage, Bin> operator[](int index); size_t size() const { return bin.size(); } bool zero() const { return data(0)->value(params) == 0.0; } @@ -1210,13 +1159,12 @@ class Vector2dBase : public DataAccess bool check() { return bin.initialized(); } }; -template <typename T, template <typename T> class Storage, class Bin> +template <class Storage, class Bin> class VectorProxy { public: - typedef Storage<T> storage_t; - typedef typename storage_t::Params params_t; - typedef typename Bin::VectorBin<storage_t> bin_t; + typedef typename Storage::Params params_t; + typedef typename Bin::VectorBin<Storage> bin_t; private: bin_t *bin; @@ -1226,36 +1174,36 @@ class VectorProxy void *stat; private: - mutable rvec_t *vec; + mutable VResult *vec; - storage_t *data(int index) { + Storage *data(int index) { assert(index < len); return bin->data(offset + index, *params); } - const storage_t *data(int index) const { + const Storage *data(int index) const { bin_t *_bin = const_cast<bin_t *>(bin); params_t *_params = const_cast<params_t *>(params); return _bin->data(offset + index, *_params); } public: - const rvec_t &val() const { + const VResult &result() const { if (vec) vec->resize(size()); else - vec = new rvec_t(size()); + vec = new VResult(size()); for (int i = 0; i < size(); ++i) - (*vec)[i] = data(i)->val(*params); + (*vec)[i] = data(i)->result(*params); return *vec; } - result_t total() const { - result_t total = 0.0; + Result total() const { + Result total = 0.0; for (int i = 0; i < size(); ++i) - total += data(i)->val(*params); + total += data(i)->result(*params); return total; } @@ -1290,11 +1238,10 @@ class VectorProxy return *this; } - ScalarProxy<T, Storage, Bin> operator[](int index) + ScalarProxy<Storage, Bin> operator[](int index) { assert (index >= 0 && index < size()); - return ScalarProxy<T, Storage, Bin>(*bin, *params, offset + index, - stat); + return ScalarProxy<Storage, Bin>(*bin, *params, offset + index, stat); } size_t size() const { return len; } @@ -1311,13 +1258,13 @@ class VectorProxy void reset() { } }; -template <typename T, template <typename T> class Storage, class Bin> -inline VectorProxy<T, Storage, Bin> -Vector2dBase<T, Storage, Bin>::operator[](int index) +template <class Storage, class Bin> +inline VectorProxy<Storage, Bin> +Vector2dBase<Storage, Bin>::operator[](int index) { int offset = index * y; assert (index >= 0 && offset < size()); - return VectorProxy<T, Storage, Bin>(bin, params, offset, y, this); + return VectorProxy<Storage, Bin>(bin, params, offset, y, this); } ////////////////////////////////////////////////////////////////////// @@ -1329,7 +1276,6 @@ Vector2dBase<T, Storage, Bin>::operator[](int index) /** * Templatized storage and interface for a distrbution stat. */ -template <typename T> struct DistStor { public: @@ -1337,11 +1283,11 @@ struct DistStor struct Params { /** The minimum value to track. */ - int min; + Counter min; /** The maximum value to track. */ - int max; + Counter max; /** The number of entries in each bucket. */ - int bucket_size; + Counter bucket_size; /** The number of buckets. Equal to (max-min)/bucket_size. */ int size; }; @@ -1349,21 +1295,21 @@ struct DistStor private: /** The smallest value sampled. */ - T min_val; + Counter min_val; /** The largest value sampled. */ - T max_val; + Counter max_val; /** The number of values sampled less than min. */ - T underflow; + Counter underflow; /** The number of values sampled more than max. */ - T overflow; + Counter overflow; /** The current sum. */ - T sum; + Counter sum; /** The sum of squares. */ - T squares; + Counter squares; /** The number of samples. */ - int samples; + Counter samples; /** Counter for each bucket. */ - std::vector<T> vec; + VCounter cvec; public: /** @@ -1371,8 +1317,9 @@ struct DistStor * @param params The parameters. */ DistStor(const Params ¶ms) - : min_val(INT_MAX), max_val(INT_MIN), underflow(0), overflow(0), - sum(T()), squares(T()), samples(0), vec(params.size) + : min_val(INT_MAX), max_val(INT_MIN), underflow(Counter()), + overflow(Counter()), sum(Counter()), squares(Counter()), + samples(Counter()), cvec(params.size) { reset(); } @@ -1383,16 +1330,16 @@ struct DistStor * @param number The number of times to add the value. * @param params The paramters of the distribution. */ - void sample(T val, int number, const Params ¶ms) + void sample(Counter val, int number, const Params ¶ms) { if (val < params.min) underflow += number; else if (val > params.max) overflow += number; else { - int index = (val - params.min) / params.bucket_size; + int index = (int)floor((val - params.min) / params.bucket_size); assert(index < size(params)); - vec[index] += number; + cvec[index] += number; } if (val < min_val) @@ -1401,7 +1348,7 @@ struct DistStor if (val > max_val) max_val = val; - T sample = val * number; + Counter sample = val * number; sum += sample; squares += sample * sample; samples += number; @@ -1412,7 +1359,7 @@ struct DistStor * @return the number of buckets. * @todo Is it faster to return the size from the parameters? */ - size_t size(const Params &) const { return vec.size(); } + size_t size(const Params &) const { return cvec.size(); } /** * Returns true if any calls to sample have been made. @@ -1421,7 +1368,7 @@ struct DistStor */ bool zero(const Params ¶ms) const { - return samples == 0; + return samples == Counter(); } void update(DistDataData *data, const Params ¶ms) @@ -1435,9 +1382,9 @@ struct DistStor data->max_val = (max_val == INT_MIN) ? 0 : max_val; data->underflow = underflow; data->overflow = overflow; - data->vec.resize(params.size); + data->cvec.resize(params.size); for (int i = 0; i < params.size; ++i) - data->vec[i] = vec[i]; + data->cvec[i] = cvec[i]; data->sum = sum; data->squares = squares; @@ -1454,13 +1401,13 @@ struct DistStor underflow = 0; overflow = 0; - int size = vec.size(); + int size = cvec.size(); for (int i = 0; i < size; ++i) - vec[i] = T(); + cvec[i] = Counter(); - sum = T(); - squares = T(); - samples = T(); + sum = Counter(); + squares = Counter(); + samples = Counter(); } }; @@ -1468,7 +1415,6 @@ struct DistStor * Templatized storage and interface for a distribution that calculates mean * and variance. */ -template <typename T> struct FancyStor { public: @@ -1480,17 +1426,19 @@ struct FancyStor private: /** The current sum. */ - T sum; + Counter sum; /** The sum of squares. */ - T squares; + Counter squares; /** The number of samples. */ - int samples; + Counter samples; public: /** * Create and initialize this storage. */ - FancyStor(const Params &) : sum(T()), squares(T()), samples(0) {} + FancyStor(const Params &) + : sum(Counter()), squares(Counter()), samples(Counter()) + { } /** * Add a value the given number of times to this running average. @@ -1500,9 +1448,9 @@ struct FancyStor * @param number The number of times to add the value. * @param p The parameters of this stat. */ - void sample(T val, int number, const Params &p) + void sample(Counter val, int number, const Params &p) { - T value = val * number; + Counter value = val * number; sum += value; squares += value * value; samples += number; @@ -1525,16 +1473,16 @@ struct FancyStor * Return true if no samples have been added. * @return True if no samples have been added. */ - bool zero(const Params &) const { return samples == 0; } + bool zero(const Params &) const { return samples == Counter(); } /** * Reset stat value to default */ void reset() { - sum = T(); - squares = T(); - samples = 0; + sum = Counter(); + squares = Counter(); + samples = Counter(); } }; @@ -1542,7 +1490,6 @@ struct FancyStor * Templatized storage for distribution that calculates per cycle mean and * variance. */ -template <typename T> struct AvgFancy { public: @@ -1552,15 +1499,15 @@ struct AvgFancy private: /** Current total. */ - T sum; + Counter sum; /** Current sum of squares. */ - T squares; + Counter squares; public: /** * Create and initialize this storage. */ - AvgFancy(const Params &) : sum(T()), squares(T()) {} + AvgFancy(const Params &) : sum(Counter()), squares(Counter()) {} /** * Add a value to the distribution for the given number of times. @@ -1569,9 +1516,9 @@ struct AvgFancy * @param number The number of times to add the value. * @param p The paramters of the distribution. */ - void sample(T val, int number, const Params &p) + void sample(Counter val, int number, const Params &p) { - T value = val * number; + Counter value = val * number; sum += value; squares += value * value; } @@ -1592,14 +1539,14 @@ struct AvgFancy * Return true if no samples have been added. * @return True if the sum is zero. */ - bool zero(const Params ¶ms) const { return sum == 0; } + bool zero(const Params ¶ms) const { return sum == Counter(); } /** * Reset stat value to default */ void reset() { - sum = T(); - squares = T(); + sum = Counter(); + squares = Counter(); } }; @@ -1607,16 +1554,14 @@ struct AvgFancy * Implementation of a distribution stat. The type of distribution is * determined by the Storage template. @sa ScalarBase */ -template <typename T, template <typename T> class Storage, class Bin> +template <class Storage, class Bin> class DistBase : public DataAccess { public: - /** Define the type of the storage class. */ - typedef Storage<T> storage_t; /** Define the params of the storage class. */ - typedef typename storage_t::Params params_t; + typedef typename Storage::Params params_t; /** Define the bin type. */ - typedef typename Bin::Bin<storage_t> bin_t; + typedef typename Bin::Bin<Storage> bin_t; protected: /** The bin of this stat. */ @@ -1629,12 +1574,12 @@ class DistBase : public DataAccess * Retrieve the storage from the bin. * @return The storage object for this stat. */ - storage_t *data() { return bin.data(params); } + Storage *data() { return bin.data(params); } /** * Retrieve a const pointer to the storage from the bin. * @return A const pointer to the storage object for this stat. */ - const storage_t *data() const + const Storage *data() const { bin_t *_bin = const_cast<bin_t *>(&bin); params_t *_params = const_cast<params_t *>(¶ms); @@ -1671,9 +1616,9 @@ class DistBase : public DataAccess */ bool zero() const { return data()->zero(params); } - void update(DistDataBase *base) + void update(DistData *base) { - base->data.fancy = storage_t::fancy; + base->data.fancy = Storage::fancy; data()->update(&(base->data), params); } /** @@ -1691,24 +1636,23 @@ class DistBase : public DataAccess bool check() { return bin.initialized(); } }; -template <typename T, template <typename T> class Storage, class Bin> +template <class Storage, class Bin> class DistProxy; -template <typename T, template <typename T> class Storage, class Bin> +template <class Storage, class Bin> class VectorDistBase : public DataAccess { public: - typedef Storage<T> storage_t; - typedef typename storage_t::Params params_t; - typedef typename Bin::VectorBin<storage_t> bin_t; + typedef typename Storage::Params params_t; + typedef typename Bin::VectorBin<Storage> bin_t; protected: bin_t bin; params_t params; protected: - storage_t *data(int index) { return bin.data(index, params); } - const storage_t *data(int index) const + Storage *data(int index) { return bin.data(index, params); } + const Storage *data(int index) const { bin_t *_bin = const_cast<bin_t *>(&bin); params_t *_params = const_cast<params_t *>(¶ms); @@ -1723,9 +1667,9 @@ class VectorDistBase : public DataAccess public: VectorDistBase() {} - friend class DistProxy<T, Storage, Bin>; - DistProxy<T, Storage, Bin> operator[](int index); - const DistProxy<T, Storage, Bin> operator[](int index) const; + friend class DistProxy<Storage, Bin>; + DistProxy<Storage, Bin> operator[](int index); + const DistProxy<Storage, Bin> operator[](int index) const; size_t size() const { return bin.size(); } bool zero() const { return false; } @@ -1740,25 +1684,24 @@ class VectorDistBase : public DataAccess void reset() { bin.reset(); } bool check() { return bin.initialized(); } - void update(VectorDistDataBase *base) + void update(VectorDistData *base) { int size = this->size(); base->data.resize(size); for (int i = 0; i < size; ++i) { - base->data[i].fancy = storage_t::fancy; + base->data[i].fancy = Storage::fancy; data(i)->update(&(base->data[i]), params); } } }; -template <typename T, template <typename T> class Storage, class Bin> +template <class Storage, class Bin> class DistProxy { public: - typedef Storage<T> storage_t; - typedef typename storage_t::Params params_t; - typedef typename Bin::Bin<storage_t> bin_t; - typedef VectorDistBase<T, Storage, Bin> base_t; + typedef typename Storage::Params params_t; + typedef typename Bin::Bin<Storage> bin_t; + typedef VectorDistBase<Storage, Bin> base_t; private: union { @@ -1768,11 +1711,11 @@ class DistProxy int index; protected: - storage_t *data() { return stat->data(index); } - const storage_t *data() const { return cstat->data(index); } + Storage *data() { return stat->data(index); } + const Storage *data() const { return cstat->data(index); } public: - DistProxy(const VectorDistBase<T, Storage, Bin> &s, int i) + DistProxy(const VectorDistBase<Storage, Bin> &s, int i) : cstat(&s), index(i) {} DistProxy(const DistProxy &sp) : cstat(sp.cstat), index(sp.index) {} @@ -1797,30 +1740,30 @@ class DistProxy void reset() { } }; -template <typename T, template <typename T> class Storage, class Bin> -inline DistProxy<T, Storage, Bin> -VectorDistBase<T, Storage, Bin>::operator[](int index) +template <class Storage, class Bin> +inline DistProxy<Storage, Bin> +VectorDistBase<Storage, Bin>::operator[](int index) { assert (index >= 0 && index < size()); - return DistProxy<T, Storage, Bin>(*this, index); + return DistProxy<Storage, Bin>(*this, index); } -template <typename T, template <typename T> class Storage, class Bin> -inline const DistProxy<T, Storage, Bin> -VectorDistBase<T, Storage, Bin>::operator[](int index) const +template <class Storage, class Bin> +inline const DistProxy<Storage, Bin> +VectorDistBase<Storage, Bin>::operator[](int index) const { assert (index >= 0 && index < size()); - return DistProxy<T, Storage, Bin>(*this, index); + return DistProxy<Storage, Bin>(*this, index); } #if 0 -template <typename T, template <typename T> class Storage, class Bin> -result_t -VectorDistBase<T, Storage, Bin>::total(int index) const +template <class Storage, class Bin> +Result +VectorDistBase<Storage, Bin>::total(int index) const { int total = 0; for (int i=0; i < x_size(); ++i) { - total += data(i)->val(*params); + total += data(i)->result(*params); } } #endif @@ -1847,12 +1790,12 @@ class Node : public RefCounted * Return the result vector of this subtree. * @return The result vector of this subtree. */ - virtual const rvec_t &val() const = 0; + virtual const VResult &result() const = 0; /** * Return the total of the result vector. * @return The total of the result vector. */ - virtual result_t total() const = 0; + virtual Result total() const = 0; /** * Return true if stat is binned. *@return True is stat is binned. @@ -1871,17 +1814,17 @@ typedef RefCountingPtr<Node> NodePtr; class ScalarStatNode : public Node { private: - const ScalarDataBase *data; - mutable rvec_t result; + const ScalarData *data; + mutable VResult vresult; public: - ScalarStatNode(const ScalarDataBase *d) : data(d), result(1) {} - virtual const rvec_t &val() const + ScalarStatNode(const ScalarData *d) : data(d), vresult(1) {} + virtual const VResult &result() const { - result[0] = data->val(); - return result; + vresult[0] = data->result(); + return vresult; } - virtual result_t total() const { return data->val(); }; + virtual Result total() const { return data->result(); }; virtual size_t size() const { return 1; } /** @@ -1896,22 +1839,22 @@ class ScalarStatNode : public Node virtual std::string str() const { return data->name; } }; -template <typename T, template <typename T> class Storage, class Bin> +template <class Storage, class Bin> class ScalarProxyNode : public Node { private: - const ScalarProxy<T, Storage, Bin> proxy; - mutable rvec_t result; + const ScalarProxy<Storage, Bin> proxy; + mutable VResult vresult; public: - ScalarProxyNode(const ScalarProxy<T, Storage, Bin> &p) - : proxy(p), result(1) { } - virtual const rvec_t &val() const + ScalarProxyNode(const ScalarProxy<Storage, Bin> &p) + : proxy(p), vresult(1) { } + virtual const VResult &result() const { - result[0] = proxy.val(); - return result; + vresult[0] = proxy.result(); + return vresult; } - virtual result_t total() const { return proxy.val(); }; + virtual Result total() const { return proxy.result(); }; virtual size_t size() const { return 1; } /** @@ -1929,12 +1872,12 @@ class ScalarProxyNode : public Node class VectorStatNode : public Node { private: - const VectorDataBase *data; + const VectorData *data; public: - VectorStatNode(const VectorDataBase *d) : data(d) { } - virtual const rvec_t &val() const { return data->val(); } - virtual result_t total() const { return data->total(); }; + VectorStatNode(const VectorData *d) : data(d) { } + virtual const VResult &result() const { return data->result(); } + virtual Result total() const { return data->total(); }; virtual size_t size() const { return data->size(); } /** @@ -1946,41 +1889,42 @@ class VectorStatNode : public Node virtual std::string str() const { return data->name; } }; -template <typename T> +template <class T> class ConstNode : public Node { private: - rvec_t data; + VResult vresult; public: - ConstNode(T s) : data(1, (result_t)s) {} - const rvec_t &val() const { return data; } - virtual result_t total() const { return data[0]; }; - + ConstNode(T s) : vresult(1, (Result)s) {} + const VResult &result() const { return vresult; } + virtual Result total() const { return vresult[0]; }; virtual size_t size() const { return 1; } + /** * Return true if stat is binned. *@return False since constants aren't binned. */ virtual bool binned() const { return false; } - virtual std::string str() const { return to_string(data[0]); } + virtual std::string str() const { return to_string(vresult[0]); } }; -template <typename T> +template <class T> class FunctorNode : public Node { private: T &functor; - mutable rvec_t result; + mutable VResult vresult; public: - FunctorNode(T &f) : functor(f) { result.resize(1); } - const rvec_t &val() const { - result[0] = (result_t)functor(); - return result; + FunctorNode(T &f) : functor(f) { vresult.resize(1); } + const VResult &result() const + { + vresult[0] = (Result)functor(); + return vresult; } - virtual result_t total() const { return (result_t)functor(); }; + virtual Result total() const { return (Result)functor(); }; virtual size_t size() const { return 1; } /** @@ -1991,20 +1935,21 @@ class FunctorNode : public Node virtual std::string str() const { return to_string(functor()); } }; -template <typename T> +template <class T> class ScalarNode : public Node { private: T &scalar; - mutable rvec_t result; + mutable VResult vresult; public: - ScalarNode(T &s) : scalar(s) { result.resize(1); } - const rvec_t &val() const { - result[0] = (result_t)scalar; - return result; + ScalarNode(T &s) : scalar(s) { vresult.resize(1); } + const VResult &result() const + { + vresult[0] = (Result)scalar; + return vresult; } - virtual result_t total() const { return (result_t)scalar; }; + virtual Result total() const { return (Result)scalar; }; virtual size_t size() const { return 1; } /** @@ -2019,37 +1964,37 @@ template <class Op> struct OpString; template<> -struct OpString<std::plus<result_t> > +struct OpString<std::plus<Result> > { static std::string str() { return "+"; } }; template<> -struct OpString<std::minus<result_t> > +struct OpString<std::minus<Result> > { static std::string str() { return "-"; } }; template<> -struct OpString<std::multiplies<result_t> > +struct OpString<std::multiplies<Result> > { static std::string str() { return "*"; } }; template<> -struct OpString<std::divides<result_t> > +struct OpString<std::divides<Result> > { static std::string str() { return "/"; } }; template<> -struct OpString<std::modulus<result_t> > +struct OpString<std::modulus<Result> > { static std::string str() { return "%"; } }; template<> -struct OpString<std::negate<result_t> > +struct OpString<std::negate<Result> > { static std::string str() { return "-"; } }; @@ -2059,26 +2004,27 @@ class UnaryNode : public Node { public: NodePtr l; - mutable rvec_t result; + mutable VResult vresult; public: UnaryNode(NodePtr &p) : l(p) {} - const rvec_t &val() const { - const rvec_t &lvec = l->val(); + const VResult &result() const + { + const VResult &lvec = l->result(); int size = lvec.size(); assert(size > 0); - result.resize(size); + vresult.resize(size); Op op; for (int i = 0; i < size; ++i) - result[i] = op(lvec[i]); + vresult[i] = op(lvec[i]); - return result; + return vresult; } - result_t total() const { + Result total() const { Op op; return op(l->total()); } @@ -2102,42 +2048,43 @@ class BinaryNode : public Node public: NodePtr l; NodePtr r; - mutable rvec_t result; + mutable VResult vresult; public: BinaryNode(NodePtr &a, NodePtr &b) : l(a), r(b) {} - const rvec_t &val() const { + const VResult &result() const + { Op op; - const rvec_t &lvec = l->val(); - const rvec_t &rvec = r->val(); + const VResult &lvec = l->result(); + const VResult &rvec = r->result(); assert(lvec.size() > 0 && rvec.size() > 0); if (lvec.size() == 1 && rvec.size() == 1) { - result.resize(1); - result[0] = op(lvec[0], rvec[0]); + vresult.resize(1); + vresult[0] = op(lvec[0], rvec[0]); } else if (lvec.size() == 1) { int size = rvec.size(); - result.resize(size); + vresult.resize(size); for (int i = 0; i < size; ++i) - result[i] = op(lvec[0], rvec[i]); + vresult[i] = op(lvec[0], rvec[i]); } else if (rvec.size() == 1) { int size = lvec.size(); - result.resize(size); + vresult.resize(size); for (int i = 0; i < size; ++i) - result[i] = op(lvec[i], rvec[0]); + vresult[i] = op(lvec[i], rvec[0]); } else if (rvec.size() == lvec.size()) { int size = rvec.size(); - result.resize(size); + vresult.resize(size); for (int i = 0; i < size; ++i) - result[i] = op(lvec[i], rvec[i]); + vresult[i] = op(lvec[i], rvec[i]); } - return result; + return vresult; } - result_t total() const { + Result total() const { Op op; return op(l->total(), r->total()); } @@ -2171,37 +2118,39 @@ class SumNode : public Node { public: NodePtr l; - mutable rvec_t result; + mutable VResult vresult; public: - SumNode(NodePtr &p) : l(p), result(1) {} + SumNode(NodePtr &p) : l(p), vresult(1) {} - const rvec_t &val() const { - const rvec_t &lvec = l->val(); + const VResult &result() const + { + const VResult &lvec = l->result(); int size = lvec.size(); assert(size > 0); - result[0] = 0.0; + vresult[0] = 0.0; Op op; for (int i = 0; i < size; ++i) - result[0] = op(result[0], lvec[i]); + vresult[0] = op(vresult[0], lvec[i]); - return result; + return vresult; } - result_t total() const { - const rvec_t &lvec = l->val(); + Result total() const + { + const VResult &lvec = l->result(); int size = lvec.size(); assert(size > 0); - result_t result = 0.0; + Result vresult = 0.0; Op op; for (int i = 0; i < size; ++i) - result = op(result, lvec[i]); + vresult = op(vresult, lvec[i]); - return result; + return vresult; } virtual size_t size() const { return 1; } @@ -2217,268 +2166,6 @@ class SumNode : public Node } }; -////////////////////////////////////////////////////////////////////// -// -// Binning Interface -// -////////////////////////////////////////////////////////////////////// -struct MainBin -{ - class BinBase; - friend class MainBin::BinBase; - - private: - std::string _name; - char *mem; - - protected: - off_t memsize; - off_t size() const { return memsize; } - char *memory(off_t off); - - public: - static MainBin *&curBin() - { - static MainBin *current = NULL; - return current; - } - - static void setCurBin(MainBin *bin) { curBin() = bin; } - static MainBin *current() { assert(curBin()); return curBin(); } - - static off_t &offset() - { - static off_t offset = 0; - return offset; - } - - static off_t new_offset(size_t size) - { - size_t mask = sizeof(u_int64_t) - 1; - off_t off = offset(); - - // That one is for the last trailing flags byte. - offset() += (size + 1 + mask) & ~mask; - return off; - } - - public: - MainBin(const std::string &name); - ~MainBin(); - - const std::string & - name() const - { - return _name; - } - - void - activate() - { - setCurBin(this); - } - - class BinBase - { - private: - int offset; - - public: - BinBase() : offset(-1) {} - void allocate(size_t size) - { - offset = new_offset(size); - } - char *access() - { - assert(offset != -1); - return current()->memory(offset); - } - }; - - template <class Storage> - class Bin : public BinBase - { - public: - typedef typename Storage::Params Params; - - public: - enum { binned = true }; - Bin() { allocate(sizeof(Storage)); } - bool initialized() const { return true; } - void init(Params ¶ms) { } - - int size() const { return 1; } - - Storage * - data(Params ¶ms) - { - assert(initialized()); - char *ptr = access(); - char *flags = ptr + sizeof(Storage); - if (!(*flags & 0x1)) { - *flags |= 0x1; - new (ptr) Storage(params); - } - return reinterpret_cast<Storage *>(ptr); - } - - void - reset() - { - char *ptr = access(); - char *flags = ptr + size() * sizeof(Storage); - if (!(*flags & 0x1)) - return; - - Storage *s = reinterpret_cast<Storage *>(ptr); - s->reset(); - } - }; - - template <class Storage> - class VectorBin : public BinBase - { - public: - typedef typename Storage::Params Params; - - private: - int _size; - - public: - enum { binned = true }; - VectorBin() : _size(0) {} - - bool initialized() const { return _size > 0; } - void init(int s, Params ¶ms) - { - assert(!initialized()); - assert(s > 0); - _size = s; - allocate(_size * sizeof(Storage)); - } - - int size() const { return _size; } - - Storage *data(int index, Params ¶ms) - { - assert(initialized()); - assert(index >= 0 && index < size()); - char *ptr = access(); - char *flags = ptr + size() * sizeof(Storage); - if (!(*flags & 0x1)) { - *flags |= 0x1; - for (int i = 0; i < size(); ++i) - new (ptr + i * sizeof(Storage)) Storage(params); - } - return reinterpret_cast<Storage *>(ptr + index * sizeof(Storage)); - } - void reset() - { - char *ptr = access(); - char *flags = ptr + size() * sizeof(Storage); - if (!(*flags & 0x1)) - return; - - for (int i = 0; i < _size; ++i) { - char *p = ptr + i * sizeof(Storage); - Storage *s = reinterpret_cast<Storage *>(p); - s->reset(); - } - } - }; -}; - -struct NoBin -{ - template <class Storage> - struct Bin - { - public: - typedef typename Storage::Params Params; - enum { binned = false }; - - private: - char ptr[sizeof(Storage)]; - - public: - ~Bin() - { - reinterpret_cast<Storage *>(ptr)->~Storage(); - } - - bool initialized() const { return true; } - void init(Params ¶ms) - { - new (ptr) Storage(params); - } - int size() const{ return 1; } - Storage *data(Params ¶ms) - { - assert(initialized()); - return reinterpret_cast<Storage *>(ptr); - } - void reset() - { - Storage *s = reinterpret_cast<Storage *>(ptr); - s->reset(); - } - }; - - template <class Storage> - struct VectorBin - { - public: - typedef typename Storage::Params Params; - enum { binned = false }; - - private: - char *ptr; - int _size; - - public: - VectorBin() : ptr(NULL) { } - ~VectorBin() - { - if (!initialized()) - return; - - for (int i = 0; i < _size; ++i) { - char *p = ptr + i * sizeof(Storage); - reinterpret_cast<Storage *>(p)->~Storage(); - } - delete [] ptr; - } - - bool initialized() const { return ptr != NULL; } - void init(int s, Params ¶ms) - { - assert(s > 0 && "size must be positive!"); - assert(!initialized()); - _size = s; - ptr = new char[_size * sizeof(Storage)]; - for (int i = 0; i < _size; ++i) - new (ptr + i * sizeof(Storage)) Storage(params); - } - - int size() const { return _size; } - - Storage *data(int index, Params ¶ms) - { - assert(initialized()); - assert(index >= 0 && index < size()); - return reinterpret_cast<Storage *>(ptr + index * sizeof(Storage)); - } - void reset() - { - for (int i = 0; i < _size; ++i) { - char *p = ptr + i * sizeof(Storage); - Storage *s = reinterpret_cast<Storage *>(p); - s->reset(); - } - } - }; -}; ////////////////////////////////////////////////////////////////////// // @@ -2508,15 +2195,15 @@ typedef NoBin DefaultBin; * This is a simple scalar statistic, like a counter. * @sa Stat, ScalarBase, StatStor */ -template <typename T = Counter, class Bin = DefaultBin> +template <class Bin = DefaultBin> class Scalar - : public Wrap<Scalar<T, Bin>, - ScalarBase<T, StatStor, Bin>, - ScalarData> + : public Wrap<Scalar<Bin>, + ScalarBase<StatStor, Bin>, + ScalarStatData> { public: /** The base implementation. */ - typedef ScalarBase<T, StatStor, Bin> Base; + typedef ScalarBase<StatStor, Bin> Base; Scalar() { @@ -2536,15 +2223,15 @@ class Scalar * A stat that calculates the per cycle average of a value. * @sa Stat, ScalarBase, AvgStor */ -template <typename T = Counter, class Bin = DefaultBin> +template <class Bin = DefaultBin> class Average - : public Wrap<Average<T, Bin>, - ScalarBase<T, AvgStor, Bin>, - ScalarData> + : public Wrap<Average<Bin>, + ScalarBase<AvgStor, Bin>, + ScalarStatData> { public: /** The base implementation. */ - typedef ScalarBase<T, AvgStor, Bin> Base; + typedef ScalarBase<AvgStor, Bin> Base; Average() { @@ -2564,15 +2251,15 @@ class Average * A vector of scalar stats. * @sa Stat, VectorBase, StatStor */ -template <typename T = Counter, class Bin = DefaultBin> +template <class Bin = DefaultBin> class Vector - : public WrapVec<Vector<T, Bin>, - VectorBase<T, StatStor, Bin>, - VectorData> + : public WrapVec<Vector<Bin>, + VectorBase<StatStor, Bin>, + VectorStatData> { public: /** The base implementation. */ - typedef ScalarBase<T, StatStor, Bin> Base; + typedef ScalarBase<StatStor, Bin> Base; /** * Set this vector to have the given size. @@ -2591,11 +2278,11 @@ class Vector * A vector of Average stats. * @sa Stat, VectorBase, AvgStor */ -template <typename T = Counter, class Bin = DefaultBin> +template <class Bin = DefaultBin> class AverageVector - : public WrapVec<AverageVector<T, Bin>, - VectorBase<T, AvgStor, Bin>, - VectorData> + : public WrapVec<AverageVector<Bin>, + VectorBase<AvgStor, Bin>, + VectorStatData> { public: /** @@ -2615,11 +2302,11 @@ class AverageVector * A 2-Dimensional vecto of scalar stats. * @sa Stat, Vector2dBase, StatStor */ -template <typename T = Counter, class Bin = DefaultBin> +template <class Bin = DefaultBin> class Vector2d - : public WrapVec2d<Vector2d<T, Bin>, - Vector2dBase<T, StatStor, Bin>, - Vector2dData> + : public WrapVec2d<Vector2d<Bin>, + Vector2dBase<StatStor, Bin>, + Vector2dStatData> { public: Vector2d &init(size_t _x, size_t _y) { @@ -2636,17 +2323,17 @@ class Vector2d * A simple distribution stat. * @sa Stat, DistBase, DistStor */ -template <typename T = Counter, class Bin = DefaultBin> +template <class Bin = DefaultBin> class Distribution - : public Wrap<Distribution<T, Bin>, - DistBase<T, DistStor, Bin>, - DistData> + : public Wrap<Distribution<Bin>, + DistBase<DistStor, Bin>, + DistStatData> { public: /** Base implementation. */ - typedef DistBase<T, DistStor, Bin> Base; + typedef DistBase<DistStor, Bin> Base; /** The Parameter type. */ - typedef typename DistStor<T>::Params Params; + typedef typename DistStor::Params Params; public: /** @@ -2656,11 +2343,11 @@ class Distribution * @param bkt The number of values in each bucket. * @return A reference to this distribution. */ - Distribution &init(T min, T max, int bkt) { + Distribution &init(Counter min, Counter max, Counter bkt) { params.min = min; params.max = max; params.bucket_size = bkt; - params.size = (max - min) / bkt + 1; + params.size = (int)rint((max - min) / bkt + 1.0); bin.init(params); setInit(); @@ -2672,17 +2359,17 @@ class Distribution * Calculates the mean and variance of all the samples. * @sa Stat, DistBase, FancyStor */ -template <typename T = Counter, class Bin = DefaultBin> +template <class Bin = DefaultBin> class StandardDeviation - : public Wrap<StandardDeviation<T, Bin>, - DistBase<T, FancyStor, Bin>, - DistData> + : public Wrap<StandardDeviation<Bin>, + DistBase<FancyStor, Bin>, + DistStatData> { public: /** The base implementation */ - typedef DistBase<T, DistStor, Bin> Base; + typedef DistBase<DistStor, Bin> Base; /** The parameter type. */ - typedef typename DistStor<T>::Params Params; + typedef typename DistStor::Params Params; public: /** @@ -2698,17 +2385,17 @@ class StandardDeviation * Calculates the per cycle mean and variance of the samples. * @sa Stat, DistBase, AvgFancy */ -template <typename T = Counter, class Bin = DefaultBin> +template <class Bin = DefaultBin> class AverageDeviation - : public Wrap<AverageDeviation<T, Bin>, - DistBase<T, AvgFancy, Bin>, - DistData> + : public Wrap<AverageDeviation<Bin>, + DistBase<AvgFancy, Bin>, + DistStatData> { public: /** The base implementation */ - typedef DistBase<T, DistStor, Bin> Base; + typedef DistBase<DistStor, Bin> Base; /** The parameter type. */ - typedef typename DistStor<T>::Params Params; + typedef typename DistStor::Params Params; public: /** @@ -2725,17 +2412,17 @@ class AverageDeviation * A vector of distributions. * @sa Stat, VectorDistBase, DistStor */ -template <typename T = Counter, class Bin = DefaultBin> +template <class Bin = DefaultBin> class VectorDistribution - : public WrapVec<VectorDistribution<T, Bin>, - VectorDistBase<T, DistStor, Bin>, - VectorDistData> + : public WrapVec<VectorDistribution<Bin>, + VectorDistBase<DistStor, Bin>, + VectorDistStatData> { public: /** The base implementation */ - typedef VectorDistBase<T, DistStor, Bin> Base; + typedef VectorDistBase<DistStor, Bin> Base; /** The parameter type. */ - typedef typename DistStor<T>::Params Params; + typedef typename DistStor::Params Params; public: /** @@ -2746,11 +2433,11 @@ class VectorDistribution * @param bkt The number of values in each bucket. * @return A reference to this distribution. */ - VectorDistribution &init(int size, T min, T max, int bkt) { + VectorDistribution &init(int size, Counter min, Counter max, Counter bkt) { params.min = min; params.max = max; params.bucket_size = bkt; - params.size = (max - min) / bkt + 1; + params.size = (int)rint((max - min) / bkt + 1.0); bin.init(size, params); setInit(); @@ -2762,17 +2449,17 @@ class VectorDistribution * This is a vector of StandardDeviation stats. * @sa Stat, VectorDistBase, FancyStor */ -template <typename T = Counter, class Bin = DefaultBin> +template <class Bin = DefaultBin> class VectorStandardDeviation - : public WrapVec<VectorStandardDeviation<T, Bin>, - VectorDistBase<T, FancyStor, Bin>, - VectorDistData> + : public WrapVec<VectorStandardDeviation<Bin>, + VectorDistBase<FancyStor, Bin>, + VectorDistStatData> { public: /** The base implementation */ - typedef VectorDistBase<T, FancyStor, Bin> Base; + typedef VectorDistBase<FancyStor, Bin> Base; /** The parameter type. */ - typedef typename DistStor<T>::Params Params; + typedef typename DistStor::Params Params; public: /** @@ -2792,17 +2479,17 @@ class VectorStandardDeviation * This is a vector of AverageDeviation stats. * @sa Stat, VectorDistBase, AvgFancy */ -template <typename T = Counter, class Bin = DefaultBin> +template <class Bin = DefaultBin> class VectorAverageDeviation - : public WrapVec<VectorAverageDeviation<T, Bin>, - VectorDistBase<T, AvgFancy, Bin>, - VectorDistData> + : public WrapVec<VectorAverageDeviation<Bin>, + VectorDistBase<AvgFancy, Bin>, + VectorDistStatData> { public: /** The base implementation */ - typedef VectorDistBase<T, AvgFancy, Bin> Base; + typedef VectorDistBase<AvgFancy, Bin> Base; /** The parameter type. */ - typedef typename DistStor<T>::Params Params; + typedef typename DistStor::Params Params; public: /** @@ -2838,7 +2525,7 @@ class FormulaBase : public DataAccess * be x[0]/y, x[1]/y, x[2]/y, respectively. * @return The result vector. */ - void val(rvec_t &vec) const; + void result(VResult &vec) const; /** * Return the total Formula result. If there is a Vector @@ -2847,10 +2534,10 @@ class FormulaBase : public DataAccess * components of the Vector. For example, if Formula is x/y where * x is size 3, then total() will return (x[1]+x[2]+x[3])/y. If * there is no Vector component, total() returns the same value as - * the first entry in the rvec_t val() returns. + * the first entry in the VResult val() returns. * @return The total of the result vector. */ - result_t total() const; + Result total() const; /** * Return the number of elements in the tree. @@ -2884,39 +2571,41 @@ class FormulaBase : public DataAccess std::string str() const; }; -class FormulaDataBase : public VectorDataBase +class FormulaData : public VectorData { public: virtual std::string str() const = 0; virtual bool check() const { return true; } - virtual void python(Python &py) const; }; -template <class T> -class FormulaData : public FormulaDataBase +template <class Stat> +class FormulaStatData : public FormulaData { protected: - T &s; - mutable rvec_t vec; + Stat &s; + mutable VResult vec; + mutable VCounter cvec; public: - FormulaData(T &stat) : s(stat) {} + FormulaStatData(Stat &stat) : s(stat) {} virtual bool binned() const { return s.binned(); } virtual bool zero() const { return s.zero(); } virtual void reset() { s.reset(); } virtual size_t size() const { return s.size(); } - virtual const rvec_t &val() const + virtual const VResult &result() const { - s.val(vec); + s.result(vec); return vec; } - virtual result_t total() const { return s.total(); } - virtual void update() + virtual Result total() const { return s.total(); } + virtual VCounter &value() const { return cvec; } + virtual void visit(Visit &visitor) { - VectorDataBase::update(); + update(); s.update(this); + visitor.visit(*this); } virtual std::string str() const { return s.str(); } }; @@ -2925,7 +2614,7 @@ class Temp; class Formula : public WrapVec<Formula, FormulaBase, - FormulaData> + FormulaStatData> { public: /** @@ -2959,14 +2648,14 @@ class FormulaNode : public Node { private: const Formula &formula; - mutable rvec_t vec; + mutable VResult vec; public: FormulaNode(const Formula &f) : formula(f) {} virtual size_t size() const { return formula.size(); } - virtual const rvec_t &val() const { formula.val(vec); return vec; } - virtual result_t total() const { return formula.total(); } + virtual const VResult &result() const { formula.result(vec); return vec; } + virtual Result total() const { return formula.total(); } virtual bool binned() const { return formula.binned(); } virtual std::string str() const { return formula.str(); } @@ -3001,24 +2690,24 @@ class Temp * Create a new ScalarStatNode. * @param s The ScalarStat to place in a node. */ - template <typename T, class Bin> - Temp(const Scalar<T, Bin> &s) + template <class Bin> + Temp(const Scalar<Bin> &s) : node(new ScalarStatNode(s.statData())) { } /** * Create a new ScalarStatNode. * @param s The ScalarStat to place in a node. */ - template <typename T, class Bin> - Temp(const Average<T, Bin> &s) + template <class Bin> + Temp(const Average<Bin> &s) : node(new ScalarStatNode(s.statData())) { } /** * Create a new VectorStatNode. * @param s The VectorStat to place in a node. */ - template <typename T, class Bin> - Temp(const Vector<T, Bin> &s) + template <class Bin> + Temp(const Vector<Bin> &s) : node(new VectorStatNode(s.statData())) { } /** @@ -3031,9 +2720,9 @@ class Temp * Create a new ScalarProxyNode. * @param p The ScalarProxy to place in a node. */ - template <typename T, template <typename T> class Storage, class Bin> - Temp(const ScalarProxy<T, Storage, Bin> &p) - : node(new ScalarProxyNode<T, Storage, Bin>(p)) { } + template <class Storage, class Bin> + Temp(const ScalarProxy<Storage, Bin> &p) + : node(new ScalarProxyNode<Storage, Bin>(p)) { } /** * Create a ConstNode @@ -3126,46 +2815,43 @@ class Temp */ void check(); -void dump(std::ostream &stream, DisplayMode mode = DefaultMode); -void python_start(const std::string &file); -void python_dump(const std::string &name, const std::string &subname); void reset(); void registerResetCallback(Callback *cb); inline Temp operator+(Temp l, Temp r) { - return NodePtr(new BinaryNode<std::plus<result_t> >(l, r)); + return NodePtr(new BinaryNode<std::plus<Result> >(l, r)); } inline Temp operator-(Temp l, Temp r) { - return NodePtr(new BinaryNode<std::minus<result_t> >(l, r)); + return NodePtr(new BinaryNode<std::minus<Result> >(l, r)); } inline Temp operator*(Temp l, Temp r) { - return NodePtr(new BinaryNode<std::multiplies<result_t> >(l, r)); + return NodePtr(new BinaryNode<std::multiplies<Result> >(l, r)); } inline Temp operator/(Temp l, Temp r) { - return NodePtr(new BinaryNode<std::divides<result_t> >(l, r)); + return NodePtr(new BinaryNode<std::divides<Result> >(l, r)); } inline Temp operator%(Temp l, Temp r) { - return NodePtr(new BinaryNode<std::modulus<result_t> >(l, r)); + return NodePtr(new BinaryNode<std::modulus<Result> >(l, r)); } inline Temp operator-(Temp l) { - return NodePtr(new UnaryNode<std::negate<result_t> >(l)); + return NodePtr(new UnaryNode<std::negate<Result> >(l)); } template <typename T> @@ -3192,10 +2878,9 @@ scalar(T &val) inline Temp sum(Temp val) { - return NodePtr(new SumNode<std::plus<result_t> >(val)); + return NodePtr(new SumNode<std::plus<Result> >(val)); } -extern bool PrintDescriptions; -} // namespace statistics +/* namespace Statistics */ } -#endif // __STATISTICS_HH__ +#endif // __BASE_STATISTICS_HH__ diff --git a/base/stats/flags.hh b/base/stats/flags.hh new file mode 100644 index 000000000..2303de172 --- /dev/null +++ b/base/stats/flags.hh @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2003-2004 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. + */ + +#ifndef __BASE_STATS_FLAGS_HH__ +#define __BASE_STATS_FLAGS_HH__ +namespace Statistics { + +/** + * Define the storage for format flags. + * @todo Can probably shrink this. + */ +typedef u_int32_t StatFlags; + +/** Nothing extra to print. */ +const StatFlags none = 0x00000000; +/** This Stat is Initialized */ +const StatFlags init = 0x00000001; +/** Print this stat. */ +const StatFlags print = 0x00000002; +/** Print the total. */ +const StatFlags total = 0x00000010; +/** Print the percent of the total that this entry represents. */ +const StatFlags pdf = 0x00000020; +/** Print the cumulative percentage of total upto this entry. */ +const StatFlags cdf = 0x00000040; +/** Print the distribution. */ +const StatFlags dist = 0x00000080; +/** Don't print if this is zero. */ +const StatFlags nozero = 0x00000100; +/** Don't print if this is NAN */ +const StatFlags nonan = 0x00000200; +/** Used for SS compatability. */ +const StatFlags __substat = 0x80000000; + +/** Mask of flags that can't be set directly */ +const StatFlags __reserved = init | print | __substat; + +enum DisplayMode +{ + mode_m5, + mode_simplescalar +}; + +extern DisplayMode DefaultMode; + +/* namespace Statistics */ } + +#endif // __BASE_STATS_FLAGS_HH__ diff --git a/base/stats/mysql.cc b/base/stats/mysql.cc new file mode 100644 index 000000000..676bc555c --- /dev/null +++ b/base/stats/mysql.cc @@ -0,0 +1,844 @@ +/* + * Copyright (c) 2003-2004 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. + */ + +#include <cassert> +#include <map> +#include <sstream> +#include <string> +#include <vector> + +#include "base/misc.hh" +#include "base/mysql.hh" +#include "base/statistics.hh" +#include "base/stats/flags.hh" +#include "base/stats/mysql.hh" +#include "base/stats/statdb.hh" +#include "base/stats/types.hh" +#include "base/str.hh" +#include "sim/host.hh" + +using namespace std; + +namespace Statistics { + +struct MySqlData +{ + map<int, int> idmap; + MySQL::Connection conn; +}; + +int +SetupRun(MySqlData *data, const string &name, const string &user, + const string &project) +{ + MySQL::Connection &mysql = data->conn; + assert(mysql.connected()); + + stringstream insert; + ccprintf(insert, + "INSERT INTO " + "runs(rn_name, rn_user, rn_project, rn_date, rn_expire)" + "values(\"%s\", \"%s\", \"%s\", NOW()," + "DATE_ADD(CURDATE(), INTERVAL 31 DAY))", + name, user, project); + + mysql.query(insert); + if (mysql.error) + panic("could not get a run\n%s\n", mysql.error); + + return mysql.insert_id(); +} + +void +DeleteRun(MySqlData *data, const string &name) +{ + MySQL::Connection &mysql = data->conn; + assert(mysql.connected()); + stringstream sql; + ccprintf(sql, "DELETE FROM runs WHERE rn_name=\"%s\"", name); + mysql.query(sql); +} + +void +Cleanup(MySqlData *data) +{ + MySQL::Connection &mysql = data->conn; + assert(mysql.connected()); + + mysql.query("DELETE data " + "FROM data " + "LEFT JOIN runs ON dt_run=rn_id " + "WHERE rn_id IS NULL"); + + mysql.query("DELETE formula_ref " + "FROM formula_ref " + "LEFT JOIN runs ON fr_run=rn_id " + "WHERE rn_id IS NULL"); + + mysql.query("DELETE formulas " + "FROM formulas " + "LEFT JOIN formula_ref ON fm_stat=fr_stat " + "WHERE fr_stat IS NULL"); + + mysql.query("DELETE stats " + "FROM stats " + "LEFT JOIN data ON st_id=dt_stat " + "WHERE dt_stat IS NULL"); + + mysql.query("DELETE subdata " + "FROM subdata " + "LEFT JOIN data ON sd_stat=dt_stat " + "WHERE dt_stat IS NULL"); + + mysql.query("DELETE bins " + "FROM bins " + "LEFT JOIN data ON bn_id=dt_bin " + "WHERE dt_bin IS NULL"); +} + +void +SetupStat::init() +{ + name = ""; + descr = ""; + type = ""; + print = false; + prereq = 0; + prec = -1; + nozero = false; + nonan = false; + total = false; + pdf = false; + cdf = false; + min = 0; + max = 0; + bktsize = 0; + size = 0; +} + +unsigned +SetupStat::operator()(MySqlData *data) +{ + MySQL::Connection &mysql = data->conn; + + stringstream insert; + ccprintf(insert, + "INSERT INTO " + "stats(st_name, st_descr, st_type, st_print, st_prereq, " + "st_prec, st_nozero, st_nonan, st_total, st_pdf, st_cdf, " + "st_min, st_max, st_bktsize, st_size)" + "values(\"%s\",\"%s\",\"%s\"," + " %d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d)", + name, descr, type, print, prereq, (int)prec, nozero, nonan, + total, pdf, cdf, + min, max, bktsize, size); + + mysql.query(insert); + if (!mysql.error) + return mysql.insert_id(); + + stringstream select; + ccprintf(select, "SELECT * FROM stats WHERE st_name=\"%s\"", name); + + mysql.query(select); + MySQL::Result result = mysql.store_result(); + if (!result) + panic("could not get a run\n%s\n", mysql.error); + + + assert(result.num_fields() == 16); + MySQL::Row row = result.fetch_row(); + if (!row) + panic("could not get a run\n%s\n", mysql.error); + + bool tb; + int8_t ti8; + uint16_t tu16; + int64_t ti64; + uint64_t tu64; + + if (name != (char *)row[1]) + panic("failed stat check on %s:name. %s != %s\n", + name, name, row[1]); + + if (descr != (char *)row[2]) + panic("failed stat check on %s:descr. %s != %s\n", + name, descr, row[2]); + + if (type != (char *)row[3]) + panic("failed stat check on %s:type. %s != %s\n", + name, type, row[3]); + + if (!to_number(row[4], tb) || print != tb) + panic("failed stat check on %s:print. %d != %d\n", + name, print, tb); + + if (!to_number(row[6], ti8) || prec != ti8) + panic("failed stat check on %s:prec. %d != %d\n", + name, prec, ti8); + + if (!to_number(row[7], tb) || nozero != tb) + panic("failed stat check on %s:nozero. %d != %d\n", + name, nozero, tb); + + if (!to_number(row[8], tb) || nonan != tb) + panic("failed stat check on %s:nonan. %d != %d\n", + name, nonan, tb); + + if (!to_number(row[9], tb) || total != tb) + panic("failed stat check on %s:total. %d != %d\n", + name, total, tb); + + if (!to_number(row[10], tb) || pdf != tb) + panic("failed stat check on %s:pdf. %d != %d\n", + name, pdf, tb); + + if (!to_number(row[11], tb) || cdf != tb) + panic("failed stat check on %s:cdf. %d != %d\n", + name, cdf, tb); + + if (!to_number(row[12], ti64) || min != ti64) + panic("failed stat check on %s:min. %d != %d\n", + name, min, ti64); + + if (!to_number(row[13], ti64) || max != ti64) + panic("failed stat check on %s:max. %d != %d\n", + name, max, ti64); + + if (!to_number(row[14], tu64) || bktsize != tu64) + panic("failed stat check on %s:bktsize. %d != %d\n", + name, bktsize, tu64); + + if (!to_number(row[15], tu16) || size != tu16) + panic("failed stat check on %s:size. %d != %d\n", + name, size, tu16); + + to_number(row[5], prereq); + uint16_t statid; + to_number(row[0], statid); + return statid; +} + +unsigned +SetupBin(MySqlData *data, const string &bin) +{ + MySQL::Connection &mysql = data->conn; + assert(mysql.connected()); + + using namespace MySQL; + stringstream select; + ccprintf(select, "SELECT bn_id FROM bins WHERE bn_name=\"%s\"", bin); + + mysql.query(select); + MySQL::Result result = mysql.store_result(); + if (result) { + assert(result.num_fields() == 1); + Row row = result.fetch_row(); + if (row) { + uint16_t bin_id; + to_number(row[0], bin_id); + return bin_id; + } + } + + stringstream insert; + ccprintf(insert, "INSERT INTO bins(bn_name) values(\"%s\")", bin); + + mysql.query(insert); + if (mysql.error) + panic("could not get a run\n%s\n", mysql.error); + + return mysql.insert_id(); +} + +InsertData::InsertData() +{ + query = new char[maxsize + 1]; + size = 0; + flush(); +} + +InsertData::~InsertData() +{ + delete [] query; +} + +void +InsertData::flush() +{ + if (size) { + assert(mysql && mysql->connected()); + mysql->query(query); + } + + query[0] = '\0'; + size = 0; + first = true; + strcpy(query, "INSERT INTO " + "data(dt_stat,dt_x,dt_y,dt_run,dt_sample,dt_bin,dt_data) " + "values"); + size = strlen(query); +} + +void +InsertData::insert() +{ + if (size + 1024 > maxsize) + flush(); + + if (!first) { + query[size++] = ','; + query[size] = '\0'; + } + + first = false; + + size += sprintf(query + size, "(%u,%d,%d,%u,%llu,%u,\"%f\")", + stat, x, y, run, (unsigned long long)sample, bin, data); +} + +struct InsertSubData +{ + uint16_t stat; + int16_t x; + int16_t y; + string name; + string descr; + + void operator()(MySqlData *data); +}; + +void +InsertSubData::operator()(MySqlData *data) +{ + MySQL::Connection &mysql = data->conn; + assert(mysql.connected()); + stringstream insert; + ccprintf(insert, + "INSERT INTO subdata(sd_stat,sd_x,sd_y,sd_name,sd_descr) " + "values(%d,%d,%d,\"%s\",\"%s\")", + stat, x, y, name, descr); + + mysql.query(insert); +} + +void +InsertFormula(MySqlData *data, uint16_t stat, uint16_t run, + const string &formula) +{ + MySQL::Connection &mysql = data->conn; + assert(mysql.connected()); + stringstream insert_formula; + ccprintf(insert_formula, + "INSERT INTO formulas(fm_stat,fm_formula) values(%d, \"%s\")", + stat, formula); + + mysql.query(insert_formula); + + stringstream insert_ref; + ccprintf(insert_ref, + "INSERT INTO formula_ref(fr_stat,fr_run) values(%d, %d)", + stat, run); + + mysql.query(insert_ref); +} + +void +UpdatePrereq(MySqlData *data, uint16_t stat, uint16_t prereq) +{ + MySQL::Connection &mysql = data->conn; + assert(mysql.connected()); + stringstream update; + ccprintf(update, "UPDATE stats SET st_prereq=%d WHERE st_id=%d", + prereq, stat); + mysql.query(update); +} + +#if 0 +class InsertData +{ + private: + MySQL::Connection &mysql; + MySQL::Statement stmt; + + public: + InsertData(MySqlData *data) + : mysql(data->conn) + { + stmt.prepare("INSERT INTO " + "data(dt_stat,dt_x,dt_y,dt_run,dt_sample,dt_bin,dt_data) " + "values(?,?,?,?,?,?,?)"); + assert(stmt.count() == 7 && "param count invalid"); + + stmt[0].buffer = stat; + stmt[1].buffer = x; + stmt[2].buffer = y; + stmt[3].buffer = run; + stmt[4].buffer = sample; + stmt[5].buffer = bin; + stmt[6].buffer = data; + + stmt.bind(bind); + if (stmt.error) + panic("bind param failed\n%s\n", stmt.error); + } + + public: + uint64_t sample; + uint64_t data; + uint16_t stat; + uint16_t bin; + int16_t x; + int16_t y; + + void operator()(MySQL::Connection &mysql) + { + assert(mysql.connected()) + stmt(); + } +}; +#endif + + +MySql::MySql() + : mysql(NULL), configured(false) +{ +} + +MySql::~MySql() +{ + if (mysql) + delete mysql; +} + +void +MySql::insert(int sim_id, int db_id) +{ + mysql->idmap.insert(make_pair(sim_id, db_id)); +} + +int +MySql::find(int sim_id) +{ + map<int,int>::const_iterator i = mysql->idmap.find(sim_id); + assert(i != mysql->idmap.end()); + return (*i).second; +} + +bool +MySql::valid() const +{ + return mysql && mysql->conn.connected(); +} + +void +MySql::connect(const string &host, const string &user, const string &passwd, + const string &db, const string &name, const string &project) +{ + mysql = new MySqlData; + newdata.mysql = &mysql->conn; + mysql->conn.connect(host, user, passwd, db); + if (mysql->conn.error) + panic("could not connect to database server\n%s\n", mysql->conn.error); + + DeleteRun(mysql, name); + Cleanup(mysql); + run_id = SetupRun(mysql, name, user, project); +} + +void +MySql::configure() +{ + /* + * set up all stats! + */ + using namespace Database; + stat_list_t::const_iterator i, end = stats().end(); + for (i = stats().begin(); i != end; ++i) + (*i)->visit(*this); + + for (i = stats().begin(); i != end; ++i) { + StatData *data = *i; + if (data->prereq) { + uint16_t stat_id = find(data->id); + uint16_t prereq_id = find(data->prereq->id); + assert(stat_id && prereq_id); + + UpdatePrereq(mysql, stat_id, prereq_id); + } + } + + configured = true; +} + + +void +MySql::configure(const StatData &data, string type) +{ + stat.init(); + stat.name = data.name; + stat.descr = data.desc; + stat.type = type; + stat.print = data.flags & print; + stat.prec = data.precision; + stat.nozero = data.flags & nozero; + stat.nonan = data.flags & nonan; + stat.total = data.flags & total; + stat.pdf = data.flags & pdf; + stat.cdf = data.flags & cdf; +} + +void +MySql::configure(const ScalarData &data) +{ + configure(data, "SCALAR"); + insert(data.id, stat(mysql)); +} + +void +MySql::configure(const VectorData &data) +{ + configure(data, "VECTOR"); + uint16_t statid = stat(mysql); + + if (!data.subnames.empty()) { + InsertSubData subdata; + subdata.stat = statid; + subdata.y = 0; + for (int i = 0; i < data.subnames.size(); ++i) { + subdata.x = i; + subdata.name = data.subnames[i]; + subdata.descr = data.subdescs.empty() ? "" : data.subdescs[i]; + + if (!subdata.name.empty() || !subdata.descr.empty()) + subdata(mysql); + } + } + + insert(data.id, statid); +} + +void +MySql::configure(const DistData &data) +{ + configure(data, "DIST"); + if (!data.data.fancy) { + stat.size = data.data.size; + stat.min = data.data.min; + stat.max = data.data.max; + stat.bktsize = data.data.bucket_size; + } + insert(data.id, stat(mysql)); +} + +void +MySql::configure(const VectorDistData &data) +{ + configure(data, "VECTORDIST"); + + if (!data.data[0].fancy) { + stat.size = data.data[0].size; + stat.min = data.data[0].min; + stat.max = data.data[0].max; + stat.bktsize = data.data[0].bucket_size; + } + + uint16_t statid = stat(mysql); + + if (!data.subnames.empty()) { + InsertSubData subdata; + subdata.stat = statid; + subdata.y = 0; + for (int i = 0; i < data.subnames.size(); ++i) { + subdata.x = i; + subdata.name = data.subnames[i]; + subdata.descr = data.subdescs.empty() ? "" : data.subdescs[i]; + if (!subdata.name.empty() || !subdata.descr.empty()) + subdata(mysql); + } + } + + insert(data.id, statid); +} + +void +MySql::configure(const Vector2dData &data) +{ + configure(data, "VECTOR2D"); + uint16_t statid = stat(mysql); + + if (!data.subnames.empty()) { + InsertSubData subdata; + subdata.stat = statid; + subdata.y = 0; + for (int i = 0; i < data.subnames.size(); ++i) { + subdata.x = i; + subdata.name = data.subnames[i]; + subdata.descr = data.subdescs.empty() ? "" : data.subdescs[i]; + if (!subdata.name.empty() || !subdata.descr.empty()) + subdata(mysql); + } + } + + if (!data.y_subnames.empty()) { + InsertSubData subdata; + subdata.stat = statid; + subdata.x = 0; + subdata.descr = ""; + for (int i = 0; i < data.y_subnames.size(); ++i) { + subdata.y = i; + subdata.name = data.y_subnames[i]; + if (!subdata.name.empty()) + subdata(mysql); + } + } + + insert(data.id, statid); +} + +void +MySql::configure(const FormulaData &data) +{ + configure(data, "FORMULA"); + insert(data.id, stat(mysql)); +} + +void +MySql::output(const string &bin) +{ + // set up new bin in database if there is a bin name + newdata.bin = bin.empty() ? 0 : SetupBin(mysql, bin); + + Database::stat_list_t::const_iterator i, end = Database::stats().end(); + for (i = Database::stats().begin(); i != end; ++i) + (*i)->visit(*this); +} + +void +MySql::output() +{ + using namespace Database; + assert(valid()); + + if (!configured) + configure(); + + // store sample # + newdata.run = run_id; + newdata.sample = curTick; + + if (bins().empty()) { + output(string("")); + } else { + bin_list_t::iterator i, end = bins().end(); + for (i = bins().begin(); i != end; ++i) { + MainBin *bin = *i; + bin->activate(); + output(bin->name()); + } + } + + newdata.flush(); +} + +void +MySql::output(const ScalarData &data) +{ + newdata.stat = find(data.id); + newdata.x = 0; + newdata.y = 0; + newdata.data = data.value(); + + newdata.insert(); +} + +void +MySql::output(const VectorData &data) +{ + newdata.stat = find(data.id); + newdata.y = 0; + + const VCounter &cvec = data.value(); + int size = data.size(); + for (int x = 0; x < size; x++) { + newdata.x = x; + newdata.data = cvec[x]; + newdata.insert(); + } +} + +void +MySql::output(const DistDataData &data) +{ + const int db_sum = -1; + const int db_squares = -2; + const int db_samples = -3; + const int db_min_val = -4; + const int db_max_val = -5; + const int db_underflow = -6; + const int db_overflow = -7; + + newdata.x = db_sum; + newdata.data = data.sum; + newdata.insert(); + + newdata.x = db_squares; + newdata.data = data.squares; + newdata.insert(); + + newdata.x = db_samples; + newdata.data = data.samples; + newdata.insert(); + + if (data.samples && !data.fancy) { + newdata.x = db_min_val; + newdata.data = data.min_val; + newdata.insert(); + + newdata.x = db_max_val; + newdata.data = data.max_val; + newdata.insert(); + + newdata.x = db_underflow; + newdata.data = data.underflow; + newdata.insert(); + + newdata.x = db_overflow; + newdata.data = data.overflow; + newdata.insert(); + + int size = data.cvec.size(); + for (int x = 0; x < size; x++) { + newdata.x = x; + newdata.data = data.cvec[x]; + newdata.insert(); + } + } +} + + +void +MySql::output(const DistData &data) +{ + newdata.stat = find(data.id); + newdata.y = 0; + output(data.data); +} + +void +MySql::output(const VectorDistData &data) +{ + newdata.stat = find(data.id); + + int size = data.data.size(); + for (int y = 0; y < size; ++y) { + newdata.y = y; + output(data.data[y]); + } +} + +void +MySql::output(const Vector2dData &data) +{ + newdata.stat = find(data.id); + + int index = 0; + for (int x = 0; x < data.x; x++) { + newdata.x = x; + for (int y = 0; y < data.y; y++) { + newdata.y = y; + newdata.data = data.cvec[index++]; + newdata.insert(); + } + } +} + +void +MySql::output(const FormulaData &data) +{ + InsertFormula(mysql, find(data.id), run_id, data.str()); +} + +/* + * Implement the visitor + */ +void +MySql::visit(const ScalarData &data) +{ + if (!configured) + configure(data); + else + output(data); +} + +void +MySql::visit(const VectorData &data) +{ + if (!configured) + configure(data); + else + output(data); +} + +void +MySql::visit(const DistData &data) +{ + if (!configured) + configure(data); + else + output(data); +} + +void +MySql::visit(const VectorDistData &data) +{ + if (!configured) + configure(data); + else + output(data); +} + +void +MySql::visit(const Vector2dData &data) +{ + if (!configured) + configure(data); + else + output(data); +} + +void +MySql::visit(const FormulaData &data) +{ + if (!configured) + configure(data); + else + output(data); +} + +/* namespace Statistics */ } diff --git a/base/stats/mysql.hh b/base/stats/mysql.hh new file mode 100644 index 000000000..4ff474752 --- /dev/null +++ b/base/stats/mysql.hh @@ -0,0 +1,149 @@ +/* + * Copyright (c) 2003-2004 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. + */ + +#ifndef __BASE_STATS_MYSQL_HH__ +#define __BASE_STATS_MYSQL_HH__ + +#include <string> + +#include "base/stats/output.hh" + +namespace MySQL { class Connection; } +namespace Statistics { + +class DistDataData; +class MySqlData; + +struct SetupStat +{ + std::string name; + std::string descr; + std::string type; + bool print; + uint16_t prereq; + int8_t prec; + bool nozero; + bool nonan; + bool total; + bool pdf; + bool cdf; + double min; + double max; + double bktsize; + uint16_t size; + + void init(); + unsigned operator()(MySqlData *data); +}; + +class InsertData +{ + private: + char *query; + int size; + bool first; + static const int maxsize = 1024*1024; + + public: + MySQL::Connection *mysql; + + public: + uint64_t sample; + double data; + uint16_t stat; + uint16_t bin; + uint16_t run; + int16_t x; + int16_t y; + + public: + InsertData(); + ~InsertData(); + + void flush(); + void insert(); +}; + +class MySql : public Output +{ + protected: + std::list<FormulaData *> formulas; + MySqlData *mysql; + bool configured; + uint16_t run_id; + + SetupStat stat; + InsertData newdata; + + void insert(int sim_id, int db_id); + int find(int sim_id); + + 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 &project); + + // Implement Visit + virtual void visit(const ScalarData &data); + virtual void visit(const VectorData &data); + virtual void visit(const DistData &data); + virtual void visit(const VectorDistData &data); + virtual void visit(const Vector2dData &data); + virtual void visit(const FormulaData &data); + + // Implement Output + virtual bool valid() const; + virtual void output(); + + protected: + // Output helper + void output(const std::string &bin); + void output(const DistDataData &data); + void output(const ScalarData &data); + void output(const VectorData &data); + void output(const DistData &data); + void output(const VectorDistData &data); + void output(const Vector2dData &data); + void output(const FormulaData &data); + + void configure(); + void configure(const StatData &data, std::string type); + void configure(const ScalarData &data); + void configure(const VectorData &data); + void configure(const DistData &data); + void configure(const VectorDistData &data); + void configure(const Vector2dData &data); + void configure(const FormulaData &data); +}; + +/* namespace Statistics */ } + +#endif // __BASE_STATS_MYSQL_HH__ diff --git a/base/stats/output.hh b/base/stats/output.hh new file mode 100644 index 000000000..9f1fbf415 --- /dev/null +++ b/base/stats/output.hh @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2003-2004 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. + */ + +#ifndef __BASE_STATS_OUTPUT_HH__ +#define __BASE_STATS_OUTPUT_HH__ + +#include <string> + +#include "base/stats/visit.hh" + +namespace Statistics { + +struct Output : public Visit +{ + inline void operator()() { output(); } + virtual void output() = 0; + virtual bool valid() const = 0; +}; + +/* namespace Statistics */ } + +#endif // __BASE_STATS_OUTPUT_HH__ diff --git a/base/stats/statdb.cc b/base/stats/statdb.cc new file mode 100644 index 000000000..f54272a50 --- /dev/null +++ b/base/stats/statdb.cc @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2003-2004 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. + */ + +#include "base/misc.hh" +#include "base/trace.hh" +#include "base/statistics.hh" +#include "base/stats/bin.hh" +#include "base/stats/statdb.hh" + +using namespace std; + +namespace Statistics { +namespace Database { + +StatData * +find(void *stat) +{ + stat_map_t::const_iterator i = map().find(stat); + + if (i == map().end()) + return NULL; + + return (*i).second; +} + +void +regBin(MainBin *bin, const std::string &_name) +{ + bins().push_back(bin); + DPRINTF(Stats, "registering %s\n", _name); +} + +void +regStat(void *stat, StatData *data) +{ + if (map().find(stat) != map().end()) + panic("shouldn't register stat twice!"); + + stats().push_back(data); + +#ifndef NDEBUG + pair<stat_map_t::iterator, bool> result = +#endif + map().insert(make_pair(stat, data)); + assert(result.second && "this should never fail"); + assert(map().find(stat) != map().end()); +} + +void +regPrint(void *stat) +{ + StatData *data = find(stat); + assert(data); + data->flags |= print; +} + +TheDatabase &db() +{ + static TheDatabase db; + return db; +} + +/* namespace Database */ } +/* namespace Statistics */ } diff --git a/base/stats/statdb.hh b/base/stats/statdb.hh new file mode 100644 index 000000000..fb672e1dc --- /dev/null +++ b/base/stats/statdb.hh @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2003-2004 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. + */ + +#ifndef __BASE_STATS_STATDB_HH__ +#define __BASE_STATS_STATDB_HH__ + +#include <iosfwd> +#include <list> +#include <map> +#include <string> + +class Python; + +namespace Statistics { + +class MainBin; +class StatData; + +namespace Database { + +typedef std::map<void *, StatData *> stat_map_t; +typedef std::list<StatData *> stat_list_t; +typedef std::list<MainBin *> bin_list_t; + +// We wrap the database in a struct to make sure it is built in time. +struct TheDatabase +{ + stat_map_t map; + stat_list_t stats; + bin_list_t bins; + +}; + +TheDatabase &db(); +inline stat_map_t &map() { return db().map; } +inline stat_list_t &stats() { return db().stats; } +inline bin_list_t &bins() { return db().bins; } + +StatData *find(void *stat); +void regBin(MainBin *bin, const std::string &name); +void regStat(void *stat, StatData *data); +void regPrint(void *stat); + +inline std::string name() { return "Statistics Database"; } + +/* namespace Database */ } +/* namespace Statistics */ } + +#endif // __BASE_STATS_STATDB_HH__ diff --git a/base/stats/text.cc b/base/stats/text.cc new file mode 100644 index 000000000..0f43a1772 --- /dev/null +++ b/base/stats/text.cc @@ -0,0 +1,731 @@ +/* + * Copyright (c) 2003-2004 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. + */ + +#include <iostream> +#include <fstream> +#include <string> + +#include "base/misc.hh" +#include "base/statistics.hh" +#include "base/stats/statdb.hh" +#include "base/stats/text.hh" +#include "base/stats/visit.hh" + +using namespace std; + +#ifndef NAN +float __nan(); +/** Define Not a number. */ +#define NAN (__nan()) +/** Need to define __nan() */ +#define __M5_NAN +#endif + +#ifdef __M5_NAN +float +__nan() +{ + union { + uint32_t ui; + float f; + } nan; + + nan.ui = 0x7fc00000; + return nan.f; +} +#endif + +namespace Statistics { + +Text::Text() + : mystream(false), stream(NULL), compat(false), descriptions(false) +{ +} + +Text::Text(std::ostream &stream) + : mystream(false), stream(NULL), compat(false), descriptions(false) +{ + open(stream); +} + +Text::Text(const std::string &file) + : mystream(false), stream(NULL), compat(false), descriptions(false) +{ + open(file); +} + + +Text::~Text() +{ + if (mystream) { + assert(stream); + delete stream; + } +} + +void +Text::open(std::ostream &_stream) +{ + if (stream) + panic("stream already set!"); + + mystream = false; + stream = &_stream; + assert(valid()); +} + +void +Text::open(const std::string &file) +{ + if (stream) + panic("stream already set!"); + + mystream = true; + stream = new ofstream(file.c_str(), ios::trunc); + assert(valid()); +} + +bool +Text::valid() const +{ + return stream != NULL; +} + +void +Text::output() +{ + using namespace Database; + + ccprintf(*stream, "\n---------- Begin Simulation Statistics ----------\n"); + if (bins().empty()) { + stat_list_t::const_iterator i, end = stats().end(); + for (i = stats().begin(); i != end; ++i) + (*i)->visit(*this); + } else { + ccprintf(*stream, "PRINTING BINNED STATS\n"); + bin_list_t::iterator i, end = bins().end(); + for (i = bins().begin(); i != end; ++i) { + MainBin *bin = *i; + bin->activate(); + ccprintf(*stream,"---%s Bin------------\n", bin); + stat_list_t::const_iterator i, end = stats().end(); + for (i = stats().begin(); i != end; ++i) + (*i)->visit(*this); + ccprintf(*stream, "---------------------------------\n"); + } + } + ccprintf(*stream, "\n---------- End Simulation Statistics ----------\n"); + stream->flush(); +} + +bool +Text::noOutput(const StatData &data) +{ + if (!(data.flags & print)) + return true; + + if (data.prereq && data.prereq->zero()) + return true; + + return false; +} + +string +ValueToString(Result value, int precision, bool compat) +{ + stringstream val; + + if (!isnan(value)) { + if (precision != -1) + val.precision(precision); + else if (value == rint(value)) + val.precision(0); + + val.unsetf(ios::showpoint); + val.setf(ios::fixed); + val << value; + } else { + val << (compat ? "<err: div-0>" : "no value"); + } + + return val.str(); +} + +struct ScalarPrint +{ + Result value; + string name; + string desc; + StatFlags flags; + bool compat; + bool descriptions; + int precision; + Result pdf; + Result cdf; + + void operator()(ostream &stream) const; +}; + +void +ScalarPrint::operator()(ostream &stream) const +{ + if (flags & nozero && value == 0.0 || + flags & nonan && isnan(value)) + return; + + stringstream pdfstr, cdfstr; + + if (!isnan(pdf)) + ccprintf(pdfstr, "%.2f%%", pdf * 100.0); + + if (!isnan(cdf)) + ccprintf(cdfstr, "%.2f%%", cdf * 100.0); + + if (compat && flags & __substat) { + ccprintf(stream, "%32s %12s %10s %10s", name, + ValueToString(value, precision, compat), pdfstr, cdfstr); + } else { + ccprintf(stream, "%-40s %12s %10s %10s", name, + ValueToString(value, precision, compat), pdfstr, cdfstr); + } + + if (descriptions) { + if (!desc.empty()) + ccprintf(stream, " # %s", desc); + } + stream << endl; +} + +struct VectorPrint +{ + string name; + string desc; + vector<string> subnames; + vector<string> subdescs; + StatFlags flags; + bool compat; + bool descriptions; + int precision; + VResult vec; + Result total; + + void operator()(ostream &stream) const; +}; + +void +VectorPrint::operator()(std::ostream &stream) const +{ + int _size = vec.size(); + Result _total = 0.0; + + if (flags & (pdf | cdf)) { + for (int i = 0; i < _size; ++i) { + _total += vec[i]; + } + } + + string base = name + (compat ? "_" : "::"); + + ScalarPrint print; + print.name = name; + print.desc = desc; + print.precision = precision; + print.descriptions = descriptions; + print.flags = flags; + print.pdf = NAN; + print.cdf = NAN; + + bool havesub = !subnames.empty(); + + if (_size == 1) { + print.value = vec[0]; + print(stream); + } else if (!compat) { + for (int i = 0; i < _size; ++i) { + if (havesub && (i >= subnames.size() || subnames[i].empty())) + continue; + + print.name = base + (havesub ? subnames[i] : to_string(i)); + print.desc = subdescs.empty() ? desc : subdescs[i]; + print.value = vec[i]; + + if (_total && (flags & pdf)) { + print.pdf = vec[i] / _total; + print.cdf += print.pdf; + } + + print(stream); + } + + if (flags & ::Statistics::total) { + print.name = base + "total"; + print.desc = desc; + print.value = total; + print(stream); + } + } else { + if (flags & ::Statistics::total) { + print.value = total; + print(stream); + } + + Result _pdf = 0.0; + Result _cdf = 0.0; + if (flags & dist) { + ccprintf(stream, "%s.start_dist\n", name); + for (int i = 0; i < _size; ++i) { + print.name = havesub ? subnames[i] : to_string(i); + print.desc = subdescs.empty() ? desc : subdescs[i]; + print.flags |= __substat; + print.value = vec[i]; + + if (_total) { + _pdf = vec[i] / _total; + _cdf += _pdf; + } + + if (flags & pdf) + print.pdf = _pdf; + if (flags & cdf) + print.cdf = _cdf; + + print(stream); + } + ccprintf(stream, "%s.end_dist\n", name); + } else { + for (int i = 0; i < _size; ++i) { + if (havesub && subnames[i].empty()) + continue; + + print.name = base; + print.name += havesub ? subnames[i] : to_string(i); + print.desc = subdescs.empty() ? desc : subdescs[i]; + print.value = vec[i]; + + if (_total) { + _pdf = vec[i] / _total; + _cdf += _pdf; + } else { + _pdf = _cdf = NAN; + } + + if (flags & pdf) { + print.pdf = _pdf; + print.cdf = _cdf; + } + + print(stream); + } + } + } +} + +struct DistPrint +{ + string name; + string desc; + StatFlags flags; + bool compat; + bool descriptions; + int precision; + + Result min_val; + Result max_val; + Result underflow; + Result overflow; + VResult vec; + Result sum; + Result squares; + Result samples; + + Counter min; + Counter max; + Counter bucket_size; + int size; + bool fancy; + + void operator()(ostream &stream) const; +}; + +void +DistPrint::operator()(ostream &stream) const +{ + if (fancy) { + ScalarPrint print; + string base = name + (compat ? "_" : "::"); + + print.precision = precision; + print.flags = flags; + print.compat = compat; + print.descriptions = descriptions; + print.desc = desc; + print.pdf = NAN; + print.cdf = NAN; + + print.name = base + "mean"; + print.value = samples ? sum / samples : NAN; + print(stream); + + print.name = base + "stdev"; + print.value = samples ? sqrt((samples * squares - sum * sum) / + (samples * (samples - 1.0))) : NAN; + print(stream); + + print.name = "**Ignore: " + base + "TOT"; + print.value = samples; + print(stream); + return; + } + + assert(size == vec.size()); + + Result total = 0.0; + + total += underflow; + for (int i = 0; i < size; ++i) + total += vec[i]; + total += overflow; + + string base = name + (compat ? "." : "::"); + + ScalarPrint print; + print.desc = compat ? "" : desc; + print.flags = flags; + print.compat = compat; + print.descriptions = descriptions; + print.precision = precision; + print.pdf = NAN; + print.cdf = NAN; + + if (compat) { + ccprintf(stream, "%-42s", base + "start_dist"); + if (descriptions && !desc.empty()) + ccprintf(stream, " # %s", desc); + stream << endl; + } + + print.name = base + "samples"; + print.value = samples; + print(stream); + + print.name = base + "min_value"; + print.value = min_val; + print(stream); + + if (!compat || underflow > 0.0) { + print.name = base + "underflows"; + print.value = underflow; + if (!compat && total) { + print.pdf = underflow / total; + print.cdf += print.pdf; + } + print(stream); + } + + + if (!compat) { + for (int i = 0; i < size; ++i) { + stringstream namestr; + namestr << name; + + Counter low = i * bucket_size + min; + Counter high = ::min(low + bucket_size, max); + namestr << low; + if (low < high) + namestr << "-" << high; + + print.name = namestr.str(); + print.value = vec[i]; + if (total) { + print.pdf = vec[i] / total; + print.cdf += print.pdf; + } + print(stream); + } + + } else { + Counter _min; + Result _pdf; + Result _cdf = 0.0; + + print.flags = flags | __substat; + + for (int i = 0; i < size; ++i) { + if (flags & nozero && vec[i] == 0.0 || + flags & nonan && isnan(vec[i])) + continue; + + _min = i * bucket_size + min; + _pdf = vec[i] / total * 100.0; + _cdf += _pdf; + + + print.name = ValueToString(_min, 0, compat); + print.value = vec[i]; + print.pdf = (flags & pdf) ? _pdf : NAN; + print.cdf = (flags & cdf) ? _cdf : NAN; + print(stream); + } + + print.flags = flags; + } + + if (!compat || overflow > 0.0) { + print.name = base + "overflows"; + print.value = overflow; + if (!compat && total) { + print.pdf = overflow / total; + print.cdf += print.pdf; + } else { + print.pdf = NAN; + print.cdf = NAN; + } + print(stream); + } + + print.pdf = NAN; + print.cdf = NAN; + + if (!compat) { + print.name = base + "total"; + print.value = total; + print(stream); + } + + print.name = base + "max_value"; + print.value = max_val; + print(stream); + + if (!compat && samples != 0) { + print.name = base + "mean"; + print.value = sum / samples; + print(stream); + + print.name = base + "stdev"; + print.value = sqrt((samples * squares - sum * sum) / + (samples * (samples - 1.0))); + print(stream); + } + + if (compat) + ccprintf(stream, "%send_dist\n\n", base); +} + +void +Text::visit(const ScalarData &data) +{ + if (noOutput(data)) + return; + + ScalarPrint print; + print.value = data.result(); + print.name = data.name; + print.desc = data.desc; + print.flags = data.flags; + print.compat = compat; + print.descriptions = descriptions; + print.precision = data.precision; + print.pdf = NAN; + print.cdf = NAN; + + print(*stream); +} + +void +Text::visit(const VectorData &data) +{ + if (noOutput(data)) + return; + + int size = data.size(); + VectorPrint print; + + print.name = data.name; + print.desc = data.desc; + print.flags = data.flags; + print.compat = compat; + print.descriptions = descriptions; + print.precision = data.precision; + print.vec = data.result(); + print.total = data.total(); + + if (!data.subnames.empty()) { + for (int i = 0; i < size; ++i) { + if (!data.subnames[i].empty()) { + print.subnames = data.subnames; + print.subnames.resize(size); + for (int i = 0; i < size; ++i) { + if (!data.subnames[i].empty() && + !data.subdescs[i].empty()) { + print.subdescs = data.subdescs; + print.subdescs.resize(size); + break; + } + } + break; + } + } + } + + print(*stream); +} + +void +Text::visit(const Vector2dData &data) +{ + if (noOutput(data)) + return; + + bool havesub = false; + VectorPrint print; + + print.subnames = data.y_subnames; + print.flags = data.flags; + print.compat = compat; + print.descriptions = descriptions; + print.precision = data.precision; + + if (!data.subnames.empty()) { + for (int i = 0; i < data.x; ++i) + if (!data.subnames[i].empty()) + havesub = true; + } + + VResult tot_vec(data.y); + Result super_total = 0.0; + for (int i = 0; i < data.x; ++i) { + if (havesub && (i >= data.subnames.size() || data.subnames[i].empty())) + continue; + + int iy = i * data.y; + VResult yvec(data.y); + + Result total = 0.0; + for (int j = 0; j < data.y; ++j) { + yvec[j] = data.cvec[iy + j]; + tot_vec[j] += yvec[j]; + total += yvec[j]; + super_total += yvec[j]; + } + + print.name = data.name + "_" + (havesub ? data.subnames[i] : to_string(i)); + print.desc = data.desc; + print.vec = yvec; + print.total = total; + print(*stream); + } + + if ((data.flags & ::Statistics::total) && (data.x > 1)) { + print.name = data.name; + print.desc = data.desc; + print.vec = tot_vec; + print.total = super_total; + print(*stream); + } +} + +void +Text::visit(const DistData &data) +{ + if (noOutput(data)) + return; + + DistPrint print; + + print.name = data.name; + print.desc = data.desc; + print.flags = data.flags; + print.compat = compat; + print.descriptions = descriptions; + print.precision = data.precision; + + print.min_val = data.data.min_val; + print.max_val = data.data.max_val; + print.underflow = data.data.underflow; + print.overflow = data.data.overflow; + print.vec.resize(data.data.cvec.size()); + for (int i = 0; i < print.vec.size(); ++i) + print.vec[i] = (Result)data.data.cvec[i]; + print.sum = data.data.sum; + print.squares = data.data.squares; + print.samples = data.data.samples; + + print.min = data.data.min; + print.max = data.data.max; + print.bucket_size = data.data.bucket_size; + print.size = data.data.size; + print.fancy = data.data.fancy; + + print(*stream); +} + +void +Text::visit(const VectorDistData &data) +{ + if (noOutput(data)) + return; + + for (int i = 0; i < data.size(); ++i) { + DistPrint print; + + print.name = data.name + + (data.subnames[i].empty() ? ("_" + to_string(i)) : data.subnames[i]); + print.desc = data.subdescs[i].empty() ? data.desc : data.subdescs[i]; + print.flags = data.flags; + print.compat = compat; + print.descriptions = descriptions; + print.precision = data.precision; + + print.min_val = data.data[i].min_val; + print.max_val = data.data[i].max_val; + print.underflow = data.data[i].underflow; + print.overflow = data.data[i].overflow; + print.vec.resize(data.data[i].cvec.size()); + for (int j = 0; j < print.vec.size(); ++j) + print.vec[j] = (Result)data.data[i].cvec[j]; + print.sum = data.data[i].sum; + print.squares = data.data[i].squares; + print.samples = data.data[i].samples; + + print.min = data.data[i].min; + print.max = data.data[i].max; + print.bucket_size = data.data[i].bucket_size; + print.size = data.data[i].size; + print.fancy = data.data[i].fancy; + + print(*stream); + } +} + +void +Text::visit(const FormulaData &data) +{ + visit((const VectorData &)data); +} + +/* namespace Statistics */ } diff --git a/base/stats/text.hh b/base/stats/text.hh new file mode 100644 index 000000000..89bddf0cb --- /dev/null +++ b/base/stats/text.hh @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2003-2004 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. + */ + +#ifndef __BASE_STATS_TEXT_HH__ +#define __BASE_STATS_TEXT_HH__ + +#include <iosfwd> +#include <string> + +#include "base/stats/output.hh" + +namespace Statistics { + +class Text : public Output +{ + protected: + bool mystream; + std::ostream *stream; + + protected: + bool noOutput(const StatData &data); + void binout(); + + public: + bool compat; + bool descriptions; + + public: + Text(); + Text(std::ostream &stream); + Text(const std::string &file); + ~Text(); + + void open(std::ostream &stream); + void open(const std::string &file); + + // Implement Visit + virtual void visit(const ScalarData &data); + virtual void visit(const VectorData &data); + virtual void visit(const DistData &data); + virtual void visit(const VectorDistData &data); + virtual void visit(const Vector2dData &data); + virtual void visit(const FormulaData &data); + + // Implement Output + virtual bool valid() const; + virtual void output(); +}; + +/* namespace Statistics */ } + +#endif // __BASE_STATS_TEXT_HH__ diff --git a/base/stats/types.hh b/base/stats/types.hh new file mode 100644 index 000000000..4451c4e6e --- /dev/null +++ b/base/stats/types.hh @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2003-2004 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. + */ + +#ifndef __BASE_STATS_TYPES_HH__ +#define __BASE_STATS_TYPES_HH__ + +#include <vector> +#include <inttypes.h> + +namespace Statistics { + +/** All counters are of 64-bit values. */ +typedef double Counter; +/** vector of counters. */ +typedef std::vector<Counter> VCounter; + +/** All results are doubles. */ +typedef double Result; +/** vector of results. */ +typedef std::vector<Result> VResult; + +/* namespace Statistics */ } + +#endif // __BASE_STATS_TYPES_HH__ diff --git a/base/stats/visit.cc b/base/stats/visit.cc new file mode 100644 index 000000000..fec11b262 --- /dev/null +++ b/base/stats/visit.cc @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2003-2004 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. + */ + +#include "base/stats/visit.hh" + +namespace Statistics { +namespace Detail { + +Visit::Visit() +{} + +Visit::~Visit() +{} + +/* namespace Detail */ } +/* namespace Statistics */ } diff --git a/base/stats/visit.hh b/base/stats/visit.hh new file mode 100644 index 000000000..a03842c52 --- /dev/null +++ b/base/stats/visit.hh @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2003-2004 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. + */ + +#ifndef __BASE_STATS_VISIT_HH__ +#define __BASE_STATS_VISIT_HH__ + +#include <string> + +#include "base/time.hh" +#include "sim/host.hh" + +namespace Statistics { + +class StatData; +class ScalarData; +class VectorData; +class DistDataData; +class DistData; +class VectorDistData; +class Vector2dData; +class FormulaData; + +struct Visit +{ + Visit(); + virtual ~Visit(); + + virtual void visit(const ScalarData &data) = 0; + virtual void visit(const VectorData &data) = 0; + virtual void visit(const DistData &data) = 0; + virtual void visit(const VectorDistData &data) = 0; + virtual void visit(const Vector2dData &data) = 0; + virtual void visit(const FormulaData &data) = 0; +}; + +/* namespace Statistics */ } + +#endif // __BASE_STATS_VISIT_HH__ diff --git a/base/time.cc b/base/time.cc index d2e8f60a5..9a484a883 100644 --- a/base/time.cc +++ b/base/time.cc @@ -47,10 +47,11 @@ convert(const timeval &tv) return (double)tv.tv_sec + (double)tv.tv_usec / 1000000.0; } -Time::Time() +Time::Time(bool set_now) { time = new _timeval; - ::gettimeofday(&time->tv, NULL); + if (set_now) + set(); } Time::Time(const timeval &val) @@ -77,15 +78,15 @@ Time::get() const } void -Time::set(const timeval &tv) +Time::set() { - memcpy(&time->tv, &tv, sizeof(timeval)); + ::gettimeofday(&time->tv, NULL); } void -Time::reset() +Time::set(const timeval &tv) { - ::gettimeofday(&time->tv, NULL); + memcpy(&time->tv, &tv, sizeof(timeval)); } double @@ -127,4 +128,4 @@ operator-(const Time &l, const Time &r) return tv; } -const Time Time::start; +const Time Time::start(true); diff --git a/base/time.hh b/base/time.hh index 64da52e1d..1f8c7e747 100644 --- a/base/time.hh +++ b/base/time.hh @@ -42,15 +42,15 @@ class Time mutable _timeval *time; public: - Time(); + explicit Time(bool set_now = false); Time(const timeval &val); Time(const Time &val); ~Time(); + void set(); const timeval &get() const; void set(const timeval &val); - void reset(); double operator()() const; std::string date(std::string format = "") const; diff --git a/base/trace.hh b/base/trace.hh index e49d7aa61..948bff548 100644 --- a/base/trace.hh +++ b/base/trace.hh @@ -43,7 +43,7 @@ #endif #endif -#include "base/trace_flags.hh" +#include "base/traceflags.hh" namespace Trace { diff --git a/base/traceflags.py b/base/traceflags.py new file mode 100644 index 000000000..b7b7fa777 --- /dev/null +++ b/base/traceflags.py @@ -0,0 +1,336 @@ +#!/usr/bin/env python + +# Copyright (c) 2004 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. + +# +# This file generates the header and source files for the flags +# that control the tracing facility. +# +hhfilename="traceflags.hh" +ccfilename="traceflags.cc" + +# +# The list of trace flags that can be used to condition DPRINTFs etc. +# To define a new flag, simply add it to this list. +# +baseFlags = [ + 'TCPIP', + 'Bus', + 'ScsiDisk', + 'ScsiCtrl', + 'ScsiNone', + 'DMA', + 'DMAReadVerbose', + 'DMAWriteVerbose', + 'TLB', + 'SimpleDisk', + 'SimpleDiskData', + 'Clock', + 'Regs', + 'MC146818', + 'IPI', + 'Timer', + 'Mbox', + 'PCIA', + 'PCIDEV', + 'ISP', + 'BADADDR', + 'Console', + 'ConsolePoll', + 'ConsoleVerbose', + 'TlaserUart', + 'AlphaConsole', + 'Flow', + 'Interrupt', + 'Cycle', + 'Loader', + 'MMU', + 'Ethernet', + 'EthernetPIO', + 'EthernetDMA', + 'EthernetData', + 'GDBMisc', + 'GDBAcc', + 'GDBRead', + 'GDBWrite', + 'GDBSend', + 'GDBRecv', + 'GDBExtra', + 'VtoPhys', + 'Printf', + 'DebugPrintf', + 'Serialize', + 'Event', + 'PCEvent', + 'SyscallWarnings', + 'SyscallVerbose', + 'DiskImage', + 'DiskImageRead', + 'DiskImageWrite', + 'InstExec', + 'BPredRAS', + 'Cache', + 'IIC', + 'IICMore', + 'MSHR', + 'Chains', + 'Dispatch', + 'Stats', + 'Context', + 'Config', + 'Sampler', + 'WriteBarrier' + ] + +# +# "Compound" flags correspond to a set of base flags. These exist +# solely for convenience in setting them via the command line: if a +# compound flag is specified, all of the corresponding base flags are +# set. Compound flags cannot be used directly in DPRINTFs etc. +# To define a new compound flag, add a new entry to this hash +# 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' ] +} + +############################################################# +# +# 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, '''/* $Id $ */ + +/* + * Copyright (c) 2004 + * The Regents of The University of Michigan + * All Rights Reserved + * + * This code is part of the M5 simulator, developed by Nathan Binkert, + * Erik Hallnor, Steve Raasch, and Steve Reinhardt, with contributions + * from Ron Dreslinski, Dave Greene, and Lisa Hsu. + * + * Permission is granted to use, copy, create derivative works and + * redistribute this software and such derivative works for any + * purpose, so long as the copyright notice above, this grant of + * permission, and the disclaimer below appear in all copies made; and + * so long as the name of The University of Michigan is not used in + * any advertising or publicity pertaining to the use or distribution + * of this software without specific, written prior authorization. + * + * THIS SOFTWARE IS PROVIDED AS IS, WITHOUT REPRESENTATION FROM THE + * UNIVERSITY OF MICHIGAN AS TO ITS FITNESS FOR ANY PURPOSE, AND + * WITHOUT WARRANTY BY THE UNIVERSITY OF MICHIGAN OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE. THE REGENTS OF THE UNIVERSITY OF MICHIGAN SHALL NOT BE + * LIABLE FOR ANY DAMAGES, INCLUDING DIRECT, SPECIAL, INDIRECT, + * INCIDENTAL, OR CONSEQUENTIAL DAMAGES, WITH RESPECT TO ANY CLAIM + * ARISING OUT OF OR IN CONNECTION WITH THE USE OF THE SOFTWARE, EVEN + * IF IT HAS BEEN OR IS HEREAFTER ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGES. + */ + +/* + * 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 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. +# +# +try: + ccfile = file(ccfilename, 'w') +except OSError, e: + sys.exit("can't open %s: %s" % (ccfilename, e)) + +# file header +print >>ccfile, '''\ +/* $Id $ */ + +/* + * Copyright (c) 2004 + * The Regents of The University of Michigan + * All Rights Reserved + * + * This code is part of the M5 simulator, developed by Nathan Binkert, + * Erik Hallnor, Steve Raasch, and Steve Reinhardt, with contributions + * from Ron Dreslinski, Dave Greene, and Lisa Hsu. + * + * Permission is granted to use, copy, create derivative works and + * redistribute this software and such derivative works for any + * purpose, so long as the copyright notice above, this grant of + * permission, and the disclaimer below appear in all copies made; and + * so long as the name of The University of Michigan is not used in + * any advertising or publicity pertaining to the use or distribution + * of this software without specific, written prior authorization. + * + * THIS SOFTWARE IS PROVIDED AS IS, WITHOUT REPRESENTATION FROM THE + * UNIVERSITY OF MICHIGAN AS TO ITS FITNESS FOR ANY PURPOSE, AND + * WITHOUT WARRANTY BY THE UNIVERSITY OF MICHIGAN OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE. THE REGENTS OF THE UNIVERSITY OF MICHIGAN SHALL NOT BE + * LIABLE FOR ANY DAMAGES, INCLUDING DIRECT, SPECIAL, INDIRECT, + * INCIDENTAL, OR CONSEQUENTIAL DAMAGES, WITH RESPECT TO ANY CLAIM + * ARISING OUT OF OR IN CONNECTION WITH THE USE OF THE SOFTWARE, EVEN + * IF IT HAS BEEN OR IS HEREAFTER ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGES. + */ + +/* + * DO NOT EDIT THIS FILE! + * + * Automatically generated from traceflags.pl. + */ + +#include "base/traceflags.hh" + +using namespace Trace; + +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 + +for flag in compoundFlags: + print >>ccfile, ' "%s",' % flag + +print >>ccfile, '};\n' + +numFlagStrings = len(baseFlags) + len(compoundFlags); + +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. +# + +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, '{' + +for flag in compoundFlags: + print >>ccfile, ' %sMap,' % flag + +# file trailer +print >>ccfile, '};' + +ccfile.close() + diff --git a/base/userinfo.cc b/base/userinfo.cc new file mode 100644 index 000000000..a729dfdf4 --- /dev/null +++ b/base/userinfo.cc @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2004 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. + */ + +#include <sys/types.h> +#include <pwd.h> +#include <unistd.h> + +#include <string> + +std::string +username() +{ + struct passwd *pwd = getpwuid(getuid()); + + return pwd->pw_name; +} diff --git a/base/userinfo.hh b/base/userinfo.hh new file mode 100644 index 000000000..14e704ec4 --- /dev/null +++ b/base/userinfo.hh @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2004 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. + */ + +#ifndef __BASE_USERINFO_HH__ +#define __BASE_USERINFO_HH__ + +#include <string> + +std::string username(); + +#endif // __BASE_USERINFO_HH__ diff --git a/cpu/base_cpu.cc b/cpu/base_cpu.cc index 73fb3e7fa..c6cff814d 100644 --- a/cpu/base_cpu.cc +++ b/cpu/base_cpu.cc @@ -237,10 +237,4 @@ BaseCPU::clear_interrupts() #endif // FULL_SYSTEM -// -// This declaration is not needed now that SamplingCPU provides a -// BaseCPUBuilder object. -// -#if 0 DEFINE_SIM_OBJECT_CLASS_NAME("BaseCPU", BaseCPU) -#endif diff --git a/cpu/exec_context.cc b/cpu/exec_context.cc index eedd8b8a8..a89cf4bb5 100644 --- a/cpu/exec_context.cc +++ b/cpu/exec_context.cc @@ -42,7 +42,7 @@ using namespace std; // constructor #ifdef FULL_SYSTEM ExecContext::ExecContext(BaseCPU *_cpu, int _thread_num, System *_sys, - AlphaItb *_itb, AlphaDtb *_dtb, + AlphaITB *_itb, AlphaDTB *_dtb, FunctionalMemory *_mem) : _status(ExecContext::Unallocated), kernelStats(this, _cpu), cpu(_cpu), thread_num(_thread_num), @@ -60,6 +60,7 @@ ExecContext::ExecContext(BaseCPU *_cpu, int _thread_num, process(_process), mem(process->getMemory()), asid(_asid), func_exe_inst(0), storeCondFailures(0) { + memset(®s, 0, sizeof(RegFile)); } ExecContext::ExecContext(BaseCPU *_cpu, int _thread_num, @@ -67,6 +68,7 @@ ExecContext::ExecContext(BaseCPU *_cpu, int _thread_num, : cpu(_cpu), thread_num(_thread_num), process(0), mem(_mem), asid(_asid), func_exe_inst(0), storeCondFailures(0) { + memset(®s, 0, sizeof(RegFile)); } #endif diff --git a/cpu/exec_context.hh b/cpu/exec_context.hh index a72516ac7..7be83539a 100644 --- a/cpu/exec_context.hh +++ b/cpu/exec_context.hh @@ -124,8 +124,8 @@ class ExecContext #ifdef FULL_SYSTEM FunctionalMemory *mem; - AlphaItb *itb; - AlphaDtb *dtb; + AlphaITB *itb; + AlphaDTB *dtb; System *system; // the following two fields are redundant, since we can always @@ -174,7 +174,7 @@ class ExecContext // constructor: initialize context from given process structure #ifdef FULL_SYSTEM ExecContext(BaseCPU *_cpu, int _thread_num, System *_system, - AlphaItb *_itb, AlphaDtb *_dtb, FunctionalMemory *_dem); + AlphaITB *_itb, AlphaDTB *_dtb, FunctionalMemory *_dem); #else ExecContext(BaseCPU *_cpu, int _thread_num, Process *_process, int _asid); ExecContext(BaseCPU *_cpu, int _thread_num, FunctionalMemory *_mem, @@ -387,7 +387,10 @@ class ExecContext #ifdef FULL_SYSTEM uint64_t readIpr(int idx, Fault &fault); Fault setIpr(int idx, uint64_t val); + int readIntrFlag() { return regs.intrflag; } + void setIntrFlag(int val) { regs.intrflag = val; } Fault hwrei(); + bool inPalMode() { return PC_PAL(regs.pc); } void ev5_trap(Fault fault); bool simPalCheck(int palFunc); #endif diff --git a/cpu/memtest/memtest.cc b/cpu/memtest/memtest.cc index 051d9623a..5d608976d 100644 --- a/cpu/memtest/memtest.cc +++ b/cpu/memtest/memtest.cc @@ -40,7 +40,7 @@ #include "mem/functional_mem/main_memory.hh" #include "sim/builder.hh" #include "sim/sim_events.hh" -#include "sim/sim_stats.hh" +#include "sim/stats.hh" using namespace std; @@ -109,7 +109,6 @@ MemTest::MemTest(const string &name, // set up counters noResponseCycles = 0; numReads = 0; - numWrites = 0; tickEvent.schedule(0); } @@ -142,21 +141,23 @@ MemTest::completeRequest(MemReqPtr &req, uint8_t *data) } numReads++; + numReadsStat++; - if (numReads.value() == nextProgressMessage) { - cerr << name() << ": completed " << numReads.value() - << " read accesses @ " << curTick << endl; + if (numReads == nextProgressMessage) { + ccprintf(cerr, "%s: completed %d read accesses @%d\n", + name(), numReads, curTick); nextProgressMessage += progressInterval; } - comLoadEventQueue[0]->serviceEvents(numReads.value()); + comLoadEventQueue[0]->serviceEvents(numReads); break; case Write: - numWrites++; + numWritesStat++; break; case Copy: + numCopiesStat++; break; default: @@ -187,17 +188,18 @@ MemTest::regStats() { using namespace Statistics; - numReads + + numReadsStat .name(name() + ".num_reads") .desc("number of read accesses completed") ; - numWrites + numWritesStat .name(name() + ".num_writes") .desc("number of write accesses completed") ; - numCopies + numCopiesStat .name(name() + ".num_copies") .desc("number of copy accesses completed") ; diff --git a/cpu/memtest/memtest.hh b/cpu/memtest/memtest.hh index da6e180a0..f2409d54c 100644 --- a/cpu/memtest/memtest.hh +++ b/cpu/memtest/memtest.hh @@ -36,7 +36,7 @@ #include "cpu/exec_context.hh" #include "base/statistics.hh" -#include "sim/sim_stats.hh" +#include "sim/stats.hh" class MemTest : public BaseCPU { @@ -110,9 +110,10 @@ class MemTest : public BaseCPU Tick noResponseCycles; - Statistics::Scalar<> numReads; - Statistics::Scalar<> numWrites; - Statistics::Scalar<> numCopies; + uint64_t numReads; + Statistics::Scalar<> numReadsStat; + Statistics::Scalar<> numWritesStat; + Statistics::Scalar<> numCopiesStat; // called by MemCompleteEvent::process() void completeRequest(MemReqPtr &req, uint8_t *data); diff --git a/cpu/simple_cpu/simple_cpu.cc b/cpu/simple_cpu/simple_cpu.cc index c2796efd0..065140883 100644 --- a/cpu/simple_cpu/simple_cpu.cc +++ b/cpu/simple_cpu/simple_cpu.cc @@ -56,7 +56,7 @@ #include "sim/host.hh" #include "sim/sim_events.hh" #include "sim/sim_object.hh" -#include "sim/sim_stats.hh" +#include "sim/stats.hh" #ifdef FULL_SYSTEM #include "base/remote_gdb.hh" @@ -116,7 +116,7 @@ SimpleCPU::SimpleCPU(const string &_name, Counter max_insts_all_threads, Counter max_loads_any_thread, Counter max_loads_all_threads, - AlphaItb *itb, AlphaDtb *dtb, + AlphaITB *itb, AlphaDTB *dtb, FunctionalMemory *mem, MemInterface *icache_interface, MemInterface *dcache_interface, @@ -714,7 +714,7 @@ SimpleCPU::tick() xc->func_exe_inst++; - fault = si->execute(this, xc, traceData); + fault = si->execute(this, traceData); #ifdef FULL_SYSTEM SWContext *ctx = xc->swCtx; @@ -778,8 +778,8 @@ BEGIN_DECLARE_SIM_OBJECT_PARAMS(SimpleCPU) Param<Counter> max_loads_all_threads; #ifdef FULL_SYSTEM - SimObjectParam<AlphaItb *> itb; - SimObjectParam<AlphaDtb *> dtb; + SimObjectParam<AlphaITB *> itb; + SimObjectParam<AlphaDTB *> dtb; SimObjectParam<FunctionalMemory *> mem; SimObjectParam<System *> system; Param<int> mult; @@ -852,11 +852,7 @@ CREATE_SIM_OBJECT(SimpleCPU) defer_registration); #endif // FULL_SYSTEM -#if 0 - if (!defer_registration) { - cpu->registerExecContexts(); - } -#endif + return cpu; } diff --git a/cpu/simple_cpu/simple_cpu.hh b/cpu/simple_cpu/simple_cpu.hh index 9edd66ab4..4977e6992 100644 --- a/cpu/simple_cpu/simple_cpu.hh +++ b/cpu/simple_cpu/simple_cpu.hh @@ -40,8 +40,8 @@ #ifdef FULL_SYSTEM class Processor; class Kernel; -class AlphaItb; -class AlphaDtb; +class AlphaITB; +class AlphaDTB; class PhysicalMemory; class RemoteGDB; @@ -131,7 +131,7 @@ class SimpleCPU : public BaseCPU System *_system, Counter max_insts_any_thread, Counter max_insts_all_threads, Counter max_loads_any_thread, Counter max_loads_all_threads, - AlphaItb *itb, AlphaDtb *dtb, FunctionalMemory *mem, + AlphaITB *itb, AlphaDTB *dtb, FunctionalMemory *mem, MemInterface *icache_interface, MemInterface *dcache_interface, bool _def_reg, Tick freq); @@ -250,6 +250,56 @@ class SimpleCPU : public BaseCPU Fault copySrcTranslate(Addr src); Fault copy(Addr dest); + + uint64_t readIntReg(int reg_idx) { return xc->readIntReg(reg_idx); } + + float readFloatRegSingle(int reg_idx) + { return xc->readFloatRegSingle(reg_idx); } + + double readFloatRegDouble(int reg_idx) + { return xc->readFloatRegDouble(reg_idx); } + + uint64_t readFloatRegInt(int reg_idx) + { return xc->readFloatRegInt(reg_idx); } + + void setIntReg(int reg_idx, uint64_t val) + { return xc->setIntReg(reg_idx, val); } + + void setFloatRegSingle(int reg_idx, float val) + { return xc->setFloatRegSingle(reg_idx, val); } + + void setFloatRegDouble(int reg_idx, double val) + { return xc->setFloatRegDouble(reg_idx, val); } + + void setFloatRegInt(int reg_idx, uint64_t val) + { return xc->setFloatRegInt(reg_idx, val); } + + uint64_t readPC() { return xc->readPC(); } + void setNextPC(uint64_t val) { return xc->setNextPC(val); } + + uint64_t readUniq() { return xc->readUniq(); } + void setUniq(uint64_t val) { return xc->setUniq(val); } + + uint64_t readFpcr() { return xc->readFpcr(); } + void setFpcr(uint64_t val) { return xc->setFpcr(val); } + +#ifdef FULL_SYSTEM + uint64_t readIpr(int idx, Fault &fault) { return xc->readIpr(idx, fault); } + Fault setIpr(int idx, uint64_t val) { return xc->setIpr(idx, val); } + Fault hwrei() { return xc->hwrei(); } + int readIntrFlag() { return xc->readIntrFlag(); } + void setIntrFlag(int val) { xc->setIntrFlag(val); } + bool inPalMode() { return xc->inPalMode(); } + void ev5_trap(Fault fault) { return xc->ev5_trap(fault); } + bool simPalCheck(int palFunc) { return xc->simPalCheck(palFunc); } +#else + void syscall() { xc->syscall(); } +#endif + + bool misspeculating() { return xc->misspeculating(); } + ExecContext *xcBase() { return xc; } }; +typedef SimpleCPU SimpleCPUExecContext; + #endif // __SIMPLE_CPU_HH__ diff --git a/cpu/static_inst.hh b/cpu/static_inst.hh index cdf9aefa0..57208f8e6 100644 --- a/cpu/static_inst.hh +++ b/cpu/static_inst.hh @@ -41,10 +41,10 @@ // forward declarations class ExecContext; -class SpecExecContext; -class SimpleCPU; -class FullCPU; class DynInst; +typedef DynInst FullCPUExecContext; +class SimpleCPU; +typedef SimpleCPU SimpleCPUExecContext; class SymbolTable; namespace Trace { @@ -307,13 +307,13 @@ class StaticInst : public StaticInstBase /** * Execute this instruction under SimpleCPU model. */ - virtual Fault execute(SimpleCPU *cpu, ExecContext *xc, + virtual Fault execute(SimpleCPUExecContext *xc, Trace::InstRecord *traceData) = 0; /** * Execute this instruction under detailed FullCPU model. */ - virtual Fault execute(FullCPU *cpu, SpecExecContext *xc, DynInst *dynInst, + virtual Fault execute(FullCPUExecContext *xc, Trace::InstRecord *traceData) = 0; /** diff --git a/dev/ethertap.cc b/dev/ethertap.cc index 960d21d73..db1b3660f 100644 --- a/dev/ethertap.cc +++ b/dev/ethertap.cc @@ -313,8 +313,8 @@ BEGIN_DECLARE_SIM_OBJECT_PARAMS(EtherTap) SimObjectParam<EtherInt *> peer; SimObjectParam<EtherDump *> packet_dump; - Param<uint16_t> port; - Param<uint16_t> bufsz; + Param<unsigned> port; + Param<unsigned> bufsz; END_DECLARE_SIM_OBJECT_PARAMS(EtherTap) diff --git a/dev/io_device.cc b/dev/io_device.cc index 4f53ba48d..910b889d8 100644 --- a/dev/io_device.cc +++ b/dev/io_device.cc @@ -29,6 +29,7 @@ #include "dev/io_device.hh" #include "mem/bus/base_interface.hh" #include "mem/bus/dma_interface.hh" +#include "sim/builder.hh" PioDevice::PioDevice(const std::string &name) : FunctionalMemory(name), pioInterface(NULL) @@ -40,6 +41,8 @@ PioDevice::~PioDevice() delete pioInterface; } +DEFINE_SIM_OBJECT_CLASS_NAME("PioDevice", PioDevice) + DmaDevice::DmaDevice(const std::string &name) : PioDevice(name), dmaInterface(NULL) {} @@ -50,3 +53,5 @@ DmaDevice::~DmaDevice() delete dmaInterface; } +DEFINE_SIM_OBJECT_CLASS_NAME("DmaDevice", DmaDevice) + diff --git a/kern/tru64/tru64_events.cc b/kern/tru64/tru64_events.cc index a57c01841..17a5e406a 100644 --- a/kern/tru64/tru64_events.cc +++ b/kern/tru64/tru64_events.cc @@ -159,6 +159,6 @@ FnEvent::process(ExecContext *xc) myBin->activate(); xc->system->fnCalls++; DPRINTF(TCPIP, "fnCalls for %s is %d\n", description, - xc->system->fnCalls.val()); + xc->system->fnCalls.value()); xc->system->dumpState(xc); } diff --git a/kern/tru64/tru64_system.cc b/kern/tru64/tru64_system.cc index f8dda6f84..905ff5df6 100644 --- a/kern/tru64/tru64_system.cc +++ b/kern/tru64/tru64_system.cc @@ -318,7 +318,7 @@ BEGIN_DECLARE_SIM_OBJECT_PARAMS(Tru64System) Param<bool> bin; SimObjectParam<MemoryController *> mem_ctl; SimObjectParam<PhysicalMemory *> physmem; - Param<uint64_t> init_param; + Param<unsigned int> init_param; Param<string> kernel_code; Param<string> console_code; diff --git a/sim/builder.cc b/sim/builder.cc index e2345556e..110c42f25 100644 --- a/sim/builder.cc +++ b/sim/builder.cc @@ -32,6 +32,7 @@ #include "base/misc.hh" #include "sim/builder.hh" #include "sim/configfile.hh" +#include "sim/config_node.hh" #include "sim/host.hh" #include "sim/sim_object.hh" #include "sim/universe.hh" @@ -153,7 +154,7 @@ SimObjectClass::createObject(IniFile &configDB, // (specified by 'type=' parameter) string simObjClassName; - if (!configDB.findDefault(configClassName, "type", simObjClassName)) { + if (!configNode->find("type", simObjClassName)) { cerr << "Configuration class '" << configClassName << "' not found." << endl; abort(); diff --git a/sim/main.cc b/sim/main.cc index 48d64d4cd..8861f3ef0 100644 --- a/sim/main.cc +++ b/sim/main.cc @@ -53,7 +53,8 @@ #include "sim/sim_exit.hh" #include "sim/sim_init.hh" #include "sim/sim_object.hh" -#include "sim/sim_stats.hh" +#include "sim/stat_control.hh" +#include "sim/stats.hh" #include "sim/universe.hh" using namespace std; @@ -235,7 +236,7 @@ main(int argc, char **argv) sayHello(cerr); // Initialize statistics database - initBaseStats(); + Statistics::InitSimStats(); vector<char *> cppArgs; diff --git a/sim/param.cc b/sim/param.cc index 7affe4786..bb372f631 100644 --- a/sim/param.cc +++ b/sim/param.cc @@ -147,14 +147,14 @@ template <> bool parseParam(const string &s, bool &value) { - const string &lower = to_lower(s); + const string &ls = to_lower(s); - if (lower == "true" || lower == "t" || lower == "yes" || lower == "y") { + if (ls == "true" || ls == "t" || ls == "yes" || ls == "y" || ls == "1") { value = true; return true; } - if (lower == "false" || lower == "f" || lower == "no" || lower == "n") { + if (ls == "false" || ls == "f" || ls == "no" || ls == "n" || ls == "0") { value = false; return true; } diff --git a/sim/process.cc b/sim/process.cc index c5eee4527..c6b497343 100644 --- a/sim/process.cc +++ b/sim/process.cc @@ -43,7 +43,7 @@ #include "sim/builder.hh" #include "sim/fake_syscall.hh" #include "sim/process.hh" -#include "sim/sim_stats.hh" +#include "sim/stats.hh" #ifdef TARGET_ALPHA #include "arch/alpha/alpha_tru64_process.hh" @@ -75,6 +75,7 @@ Process::Process(const string &name, // allocate initial register file init_regs = new RegFile; + memset(init_regs, 0, sizeof(RegFile)); // initialize first 3 fds (stdin, stdout, stderr) fd_map[STDIN_FILENO] = stdin_fd; @@ -220,7 +221,7 @@ Process::sim_fd(int tgt_fd) // that can be constructed (i.e., no REGISTER_SIM_OBJECT() macro call, // which is where these get declared for concrete types). // -DEFINE_SIM_OBJECT_CLASS_NAME("Process object", Process) +DEFINE_SIM_OBJECT_CLASS_NAME("Process", Process) //////////////////////////////////////////////////////////////////////// diff --git a/sim/process.hh b/sim/process.hh index 5df5736ff..b23302b8f 100644 --- a/sim/process.hh +++ b/sim/process.hh @@ -40,7 +40,7 @@ #include "targetarch/isa_traits.hh" #include "sim/sim_object.hh" -#include "sim/sim_stats.hh" +#include "sim/stats.hh" #include "base/statistics.hh" class ExecContext; diff --git a/sim/sim_events.cc b/sim/sim_events.cc index f7b07359c..3530adedc 100644 --- a/sim/sim_events.cc +++ b/sim/sim_events.cc @@ -35,7 +35,7 @@ #include "sim/sim_events.hh" #include "sim/sim_exit.hh" #include "sim/sim_init.hh" -#include "sim/sim_stats.hh" +#include "sim/stats.hh" using namespace std; diff --git a/sim/sim_object.cc b/sim/sim_object.cc index 2ec588afa..5602a89a2 100644 --- a/sim/sim_object.cc +++ b/sim/sim_object.cc @@ -35,7 +35,7 @@ #include "sim/configfile.hh" #include "sim/host.hh" #include "sim/sim_object.hh" -#include "sim/sim_stats.hh" +#include "sim/stats.hh" #include "sim/param.hh" using namespace std; @@ -85,14 +85,6 @@ SimObject::resetStats() } // -// no default extra output -// -void -SimObject::printExtraOutput(ostream &os) -{ -} - -// // static function: // call regStats() on all SimObjects and then regFormulas() on all // SimObjects. @@ -163,21 +155,6 @@ SimObject::resetAllStats() } // -// static function: call printExtraOutput() on all SimObjects. -// -void -SimObject::printAllExtraOutput(ostream &os) -{ - SimObjectList::iterator i = simObjectList.begin(); - SimObjectList::iterator end = simObjectList.end(); - - for (; i != end; ++i) { - SimObject *obj = *i; - obj->printExtraOutput(os); - } -} - -// // static function: serialize all SimObjects. // void diff --git a/sim/sim_object.hh b/sim/sim_object.hh index aaaafc04b..b1dd19475 100644 --- a/sim/sim_object.hh +++ b/sim/sim_object.hh @@ -74,19 +74,12 @@ class SimObject : public Serializable virtual void regFormulas(); virtual void resetStats(); - // print extra results for this object not covered by registered - // statistics (called at end of simulation) - virtual void printExtraOutput(std::ostream&); - // static: call reg_stats on all SimObjects static void regAllStats(); // static: call resetStats on all SimObjects static void resetAllStats(); - // static: call printExtraOutput on all SimObjects - static void printAllExtraOutput(std::ostream&); - // static: call nameOut() & serialize() on all SimObjects static void serializeAll(std::ostream &); }; diff --git a/sim/stat_control.cc b/sim/stat_control.cc new file mode 100644 index 000000000..d6d7e2c91 --- /dev/null +++ b/sim/stat_control.cc @@ -0,0 +1,207 @@ +/* + * Copyright (c) 2003 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. + */ + +// This file will contain default statistics for the simulator that +// don't really belong to a specific simulator object + +#include <fstream> +#include <iostream> +#include <list> + +#include "base/callback.hh" +#include "base/hostinfo.hh" +#include "base/statistics.hh" +#include "base/str.hh" +#include "base/time.hh" +#include "base/stats/output.hh" +#include "sim/eventq.hh" +#include "sim/sim_object.hh" +#include "sim/stat_control.hh" +#include "sim/universe.hh" + +using namespace std; + +Statistics::Formula hostInstRate; +Statistics::Formula hostMemory; +Statistics::Formula hostSeconds; +Statistics::Formula hostTickRate; + +Statistics::Formula simInsts; +Statistics::Formula simSeconds; +Statistics::Formula simTicks; + +namespace Statistics { + +Time statTime(true); +Tick startTick; + +class SimTicksReset : public Callback +{ + public: + void process() + { + statTime.set(); + startTick = curTick; + } +}; + +double +statElapsedTime() +{ + Time now(true); + Time elapsed = now - statTime; + return elapsed(); +} + +SimTicksReset simTicksReset; + +void +InitSimStats() +{ + simInsts + .name("sim_insts") + .desc("Number of instructions simulated") + .precision(0) + .prereq(simInsts) + ; + + simSeconds + .name("sim_seconds") + .desc("Number of seconds simulated") + ; + + simTicks + .name("sim_ticks") + .desc("Number of ticks simulated") + ; + + hostInstRate + .name("host_inst_rate") + .desc("Simulator instruction rate (inst/s)") + .precision(0) + .prereq(simInsts) + ; + + hostMemory + .name("host_mem_usage") + .desc("Number of bytes of host memory used") + .prereq(hostMemory) + ; + + hostSeconds + .name("host_seconds") + .desc("Real time elapsed on the host") + .precision(2) + ; + + hostTickRate + .name("host_tick_rate") + .desc("Simulator tick rate (ticks/s)") + .precision(0) + ; + + simInsts = constant(0); + simTicks = scalar(curTick) - scalar(startTick); + simSeconds = simTicks / scalar(ticksPerSecond); + hostMemory = functor(memUsage); + hostSeconds = functor(statElapsedTime); + hostInstRate = simInsts / hostSeconds; + hostTickRate = simTicks / hostSeconds; + + registerResetCallback(&simTicksReset); +} + +class StatEvent : public Event +{ + protected: + int flags; + Tick repeat; + + public: + StatEvent(int _flags, Tick _when, Tick _repeat); + virtual void process(); + virtual const char *description(); +}; + +StatEvent::StatEvent(int _flags, Tick _when, Tick _repeat) + : Event(&mainEventQueue, Stat_Event_Pri), + flags(_flags), repeat(_repeat) +{ + setFlags(AutoDelete); + schedule(_when); +} + +const char * +StatEvent::description() +{ + return "Statistics dump and/or reset"; +} + +void +StatEvent::process() +{ + if (flags & Statistics::Dump) + DumpNow(); + + if (flags & Statistics::Reset) + reset(); + + if (repeat) + schedule(curTick + repeat); +} + +list<Output *> OutputList; + +void +DumpNow() +{ + 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(); + } +} + +void +SetupEvent(int flags, Tick when, Tick repeat) +{ + new StatEvent(flags, when, repeat); +} + +/* namespace Statistics */ } + +extern "C" void +debugDumpStats() +{ + Statistics::DumpNow(); +} + diff --git a/sim/stat_control.hh b/sim/stat_control.hh new file mode 100644 index 000000000..9a5e269e1 --- /dev/null +++ b/sim/stat_control.hh @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2003 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. + */ + +#ifndef __SIM_STAT_CONTROL_HH__ +#define __SIM_STAT_CONTROL_HH__ + +#include <fstream> +#include <list> + +namespace Statistics { + +enum { + Reset = 0x1, + Dump = 0x2 +}; + +class Output; +extern std::list<Output *> OutputList; + +void DumpNow(); +void SetupEvent(int flags, Tick when, Tick repeat = 0); + +void InitSimStats(); + +/* namespace Statistics */ } + +#endif // __SIM_STAT_CONTROL_HH__ diff --git a/sim/stats.hh b/sim/stats.hh new file mode 100644 index 000000000..b736850e7 --- /dev/null +++ b/sim/stats.hh @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2003 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. + */ + +#ifndef __SIM_STATS_HH__ +#define __SIM_STATS_HH__ + +#include "base/statistics.hh" + +extern Statistics::Formula simTicks; +extern Statistics::Formula simSeconds; +extern Statistics::Formula simInsts; +extern Statistics::Formula hostSeconds; +extern Statistics::Formula hostTickRate; +extern Statistics::Formula hostInstRate; + +#endif // __SIM_SIM_STATS_HH__ diff --git a/sim/system.hh b/sim/system.hh index 7b011aa8f..0fcdd77cc 100644 --- a/sim/system.hh +++ b/sim/system.hh @@ -54,7 +54,7 @@ class System : public SimObject std::map<const Addr, SWContext *> swCtxMap; public: - Statistics::Scalar<Counter> fnCalls; + Statistics::Scalar<> fnCalls; Statistics::MainBin *Kernel; Statistics::MainBin *User; diff --git a/test/Makefile b/test/Makefile index d62dba64a..bf4200ba3 100644 --- a/test/Makefile +++ b/test/Makefile @@ -5,81 +5,61 @@ CXX?= g++ CURDIR?= $(shell /bin/pwd) SRCDIR?= .. -TARGET?= alpha - -TEST_SRCDIR?= $(SRCDIR)/test -ARCH_SRCDIR?= $(SRCDIR)/arch/$(TARGET) -BASE_SRCDIR?= $(SRCDIR)/base -SIM_SRCDIR?= $(SRCDIR)/sim -CACHE_SRCDIR?= $(SRCDIR)/sim/cache -OLD_SRCDIR= $(SRCDIR)/old - -vpath % $(TEST_SRCDIR) -vpath % $(BASE_SRCDIR) -vpath % $(SIM_SRCDIR) -vpath % $(CACHE_SRCDIR) -vpath % $(OLD_SRCDIR) CCFLAGS= -g -O0 -MMD -I. -I$(SRCDIR) -I- -DTRACING_ON=0 +MYSQL= -I/usr/include/mysql -L/usr/lib/mysql -lmysqlclient + +VPATH=$(SRCDIR) default: @echo "You must specify a target" -targetarch: - ln -s ../arch/$(TARGET) targetarch - -bitvectest: bitvectest.o - $(CXX) $(LFLAGS) -o $@ $^ +bitvectest: test/bitvectest.cc + $(CXX) $(CCFLAGS) -o $@ $^ -circletest: circletest.o circlebuf.o - $(CXX) $(LFLAGS) -o $@ $^ +circletest: test/circletest.cc base/circlebuf.cc + $(CXX) $(CCFLAGS) -o $@ $^ -cprintftest: cprintftest.o cprintf.o - $(CXX) $(LFLAGS) -o $@ $^ +cprintftest: test/cprintftest.cc base/cprintf.cc + $(CXX) $(CCFLAGS) -o $@ $^ -initest: initest.o str.o inifile.o cprintf.o - $(CXX) $(LFLAGS) -o $@ $^ +initest: test/initest.cc base/str.cc base/inifile.cc base/cprintf.cc + $(CXX) $(CCFLAGS) -o $@ $^ -lrutest: lru_test.o - $(CXX) $(LFLAGS) -o $@ $^ +lrutest: test/lru_test.cc + $(CXX) $(CCFLAGS) -o $@ $^ -nmtest: nmtest.o object_file.o symtab.o misc.o str.o - $(CXX) $(LFLAGS) -o $@ $^ +nmtest: test/nmtest.cc base/object_file.cc base/symtab.cc base/misc.cc base/str.cc + $(CXX) $(CCFLAGS) -o $@ $^ -offtest: offtest.o - $(CXX) $(LFLAGS) -o $@ $^ +offtest: test/offtest.cc + $(CXX) $(CCFLAGS) -o $@ $^ -rangetest: rangetest.o range.o str.o - $(CXX) $(LFLAGS) -o $@ $^ +rangetest: test/rangetest.cc base/range.cc base/str.cc + $(CXX) $(CCFLAGS) -o $@ $^ -stattest: cprintf.o hostinfo.o misc.o python.o statistics.o stattest.o \ - str.o time.o - $(CXX) $(LFLAGS) -o $@ $^ +STATTEST+= base/cprintf.cc base/hostinfo.cc base/misc.cc base/mysql.cc +STATTEST+= base/python.cc base/str.cc base/time.cc +STATTEST+= base/statistics.cc base/stats/mysql.cc base/stats/python.cc +STATTEST+= base/stats/statdb.cc base/stats/text.cc base/stats/visit.cc +STATTEST+= test/stattest.cc +stattest: $(STATTEST) + $(CXX) $(CCFLAGS) $(MYSQL) -o $@ $^ -strnumtest: strnumtest.o str.o - $(CXX) $(LFLAGS) -o $@ $^ +strnumtest: test/strnumtest.cc base/str.cc + $(CXX) $(CCFLAGS) -o $@ $^ -symtest: misc.o symtest.o symtab.o str.o - $(CXX) $(LFLAGS) -o $@ $^ +symtest: test/symtest.cc base/misc.cc base/symtab.cc base/str.cc + $(CXX) $(CCFLAGS) -o $@ $^ -tokentest: tokentest.o str.o - $(CXX) $(LFLAGS) -o $@ $^ +tokentest: test/tokentest.cc base/str.cc + $(CXX) $(CCFLAGS) -o $@ $^ -tracetest: tracetest.o trace.o trace_flags.o cprintf.o str.o misc.o - $(CXX) $(LFLAGS) -o $@ $^ +TRACE+=test/tracetest.cc base/trace.cc base/trace_flags.cc base/cprintf.cc +TRACE+=base/str.cc base/misc.cc +tracetest: $(TRACE) + $(CXX) $(CCFLAGS) -o $@ $^ clean: - @rm -f *.o *.d *test *~ .#* *.core core + @rm -f *test *~ .#* *.core core .PHONY: clean - -# C++ Compilation -%.o: %.cc - @echo '$(CXX) $(CCFLAGS) -c $(notdir $<) -o $@' - @$(CXX) $(CCFLAGS) -c $< -o $@ - -# C Compilation -%.o: %.c - @echo '$(CC) $(CCFLAGS) -c $(notdir $<) -o $@' - @$(CC) $(CCFLAGS) -c $< -o $@ - --include *.d diff --git a/test/paramtest.cc b/test/paramtest.cc index d63a3aad4..2efe23c83 100644 --- a/test/paramtest.cc +++ b/test/paramtest.cc @@ -57,8 +57,8 @@ BEGIN_DECLARE_SIM_OBJECT_PARAMS(ParamTest) VectorParam<string> vecstring; Param<bool> boolparam; VectorParam<bool> vecbool; - SimObjectParam<mem_hierarchy_obj *> memobj; - SimObjectVectorParam<mem_hierarchy_obj *> vecmemobj; + SimObjectParam<BaseMemory *> memobj; + SimObjectVectorParam<BaseMemory *> vecmemobj; SimpleEnumParam<Enum1Type> enum1; MappedEnumParam<Enum2Type> enum2; SimpleEnumVectorParam<Enum1Type> vecenum1; @@ -76,7 +76,7 @@ const EnumParamMap enum2_map[] = { "ten", 10 }, { "twenty", 20 }, { "thirty", 30 }, - { "fourty", 40 } + { "forty", 40 } }; BEGIN_INIT_SIM_OBJECT_PARAMS(ParamTest) diff --git a/test/stattest.cc b/test/stattest.cc index 8dd8eeb8e..7bf355c0e 100644 --- a/test/stattest.cc +++ b/test/stattest.cc @@ -35,6 +35,9 @@ #include "base/cprintf.hh" #include "base/misc.hh" #include "base/statistics.hh" +#include "base/stats/text.hh" +#include "base/stats/python.hh" +#include "base/stats/mysql.hh" #include "sim/host.hh" using namespace std; @@ -46,14 +49,14 @@ Tick ticksPerSecond = ULL(2000000000); Scalar<> s1; Scalar<> s2; Average<> s3; -Scalar<Counter, MainBin> s4; -Vector<Counter, MainBin> s5; -Distribution<Counter, MainBin> s6; -Vector<Counter, MainBin> s7; +Scalar<MainBin> s4; +Vector<MainBin> s5; +Distribution<MainBin> s6; +Vector<MainBin> s7; AverageVector<> s8; StandardDeviation<> s9; AverageDeviation<> s10; -Scalar<Counter> s11; +Scalar<> s11; Distribution<> s12; VectorDistribution<> s13; VectorStandardDeviation<> s14; @@ -71,6 +74,8 @@ Formula f7; MainBin bin1("bin1"); MainBin bin2("bin2"); +ostream *outputStream = &cout; + double testfunc() { @@ -89,26 +94,57 @@ usage() { panic("incorrect usage.\n" "usage:\n" - "\t%s [-v]\n", progname); + "\t%s [-p <python file>] [-t [-c] [-d]]\n", progname); } int main(int argc, char *argv[]) { + bool descriptions = false; + bool compat = false; + bool text = false; + string pyfile; + string mysql_name; + string mysql_host; + string mysql_user = "binkertn"; + string mysql_passwd; + char c; progname = argv[0]; - PrintDescriptions = false; - while ((c = getopt(argc, argv, "v")) != -1) { - cprintf("c == %c\n", c); + while ((c = getopt(argc, argv, "cdh:P:p:s:tu:")) != -1) { switch (c) { - case 'v': - PrintDescriptions = true; + case 'c': + compat = true; + break; + case 'd': + descriptions = true; + break; + case 'h': + mysql_host = optarg; + break; + case 'P': + mysql_passwd = optarg; + break; + case 'p': + pyfile = optarg; + break; + case 's': + mysql_name = optarg; + break; + case 't': + text = true; + break; + case 'u': + mysql_user = optarg; break; default: usage(); } } + if (!text && (compat || descriptions)) + usage(); + s5.init(5); s6.init(1, 100, 13); s7.init(7); @@ -214,6 +250,8 @@ main(int argc, char *argv[]) .flags(total) .subname(0, "sub0") .subname(1, "sub1") + .ysubname(0, "y0") + .ysubname(1, "y1") ; f1 @@ -509,9 +547,24 @@ main(int argc, char *argv[]) s12.sample(100); -// dump(cout, mode_simplescalar); - python_start("/tmp/stats.py"); - python_dump("stattest", "all"); + if (text) { + Text out(cout); + out.descriptions = descriptions; + out.compat = compat; + out(); + } + + if (!pyfile.empty()) { + Python out(pyfile); + out(); + } + + if (!mysql_name.empty()) { + MySql out; + out.connect(mysql_host, mysql_user, mysql_passwd, "m5stats", + mysql_name, "test"); + out(); + } return 0; } diff --git a/util/config/m5config.py b/util/config/m5config.py new file mode 100644 index 000000000..9aa3e0387 --- /dev/null +++ b/util/config/m5config.py @@ -0,0 +1,804 @@ +from __future__ import generators + +import os +import re +import sys + +##################################################################### +# +# M5 Python Configuration Utility +# +# The basic idea is to write simple Python programs that build Python +# objects corresponding to M5 SimObjects for the deisred simulation +# configuration. For now, the Python emits a .ini file that can be +# parsed by M5. In the future, some tighter integration between M5 +# and the Python interpreter may allow bypassing the .ini file. +# +# Each SimObject class in M5 is represented by a Python class with the +# same name. The Python inheritance tree mirrors the M5 C++ tree +# (e.g., SimpleCPU derives from BaseCPU in both cases, and all +# SimObjects inherit from a single SimObject base class). To specify +# an instance of an M5 SimObject in a configuration, the user simply +# instantiates the corresponding Python object. The parameters for +# that SimObject are given by assigning to attributes of the Python +# object, either using keyword assignment in the constructor or in +# separate assignment statements. For example: +# +# cache = BaseCache('my_cache', root, size=64*K) +# cache.hit_latency = 3 +# cache.assoc = 8 +# +# (The first two constructor arguments specify the name of the created +# cache and its parent node in the hierarchy.) +# +# The magic lies in the mapping of the Python attributes for SimObject +# classes to the actual SimObject parameter specifications. This +# allows parameter validity checking in the Python code. Continuing +# the example above, the statements "cache.blurfl=3" or +# "cache.assoc='hello'" would both result in runtime errors in Python, +# since the BaseCache object has no 'blurfl' parameter and the 'assoc' +# parameter requires an integer, respectively. This magic is done +# primarily by overriding the special __setattr__ method that controls +# assignment to object attributes. +# +# The Python module provides another class, ConfigNode, which is a +# superclass of SimObject. ConfigNode implements the parent/child +# relationship for building the configuration hierarchy tree. +# Concrete instances of ConfigNode can be used to group objects in the +# hierarchy, but do not correspond to SimObjects themselves (like a +# .ini section with "children=" but no "type=". +# +# Once a set of Python objects have been instantiated in a hierarchy, +# calling 'instantiate(obj)' (where obj is the root of the hierarchy) +# will generate a .ini file. See simple-4cpu.py for an example +# (corresponding to m5-test/simple-4cpu.ini). +# +##################################################################### + +##################################################################### +# +# ConfigNode/SimObject classes +# +# The Python class hierarchy rooted by ConfigNode (which is the base +# class of SimObject, which in turn is the base class of all other M5 +# SimObject classes) has special attribute behavior. In general, an +# object in this hierarchy has three categories of attribute-like +# things: +# +# 1. Regular Python methods and variables. These must start with an +# underscore to be treated normally. +# +# 2. SimObject parameters. These values are stored as normal Python +# attributes, but all assignments to these attributes are checked +# against the pre-defined set of parameters stored in the class's +# _param_dict dictionary. Assignments to attributes that do not +# correspond to predefined parameters, or that are not of the correct +# type, incur runtime errors. +# +# 3. Hierarchy children. The child nodes of a ConfigNode are stored +# in the node's _children dictionary, but can be accessed using the +# Python attribute dot-notation (just as they are printed out by the +# simulator). Children cannot be created using attribute assigment; +# they must be added by specifying the parent node in the child's +# constructor or using the '+=' operator. + +# The SimObject parameters are the most complex, for a few reasons. +# First, both parameter descriptions and parameter values are +# inherited. Thus parameter description lookup must go up the +# inheritance chain like normal attribute lookup, but this behavior +# must be explicitly coded since the lookup occurs in each class's +# _param_dict attribute. Second, because parameter values can be set +# on SimObject classes (to implement default values), the parameter +# checking behavior must be enforced on class attribute assignments as +# well as instance attribute assignments. Finally, because we allow +# class specialization via inheritance (e.g., see the L1Cache class in +# the simple-4cpu.py example), we must do parameter checking even on +# class instantiation. To provide all these features, we use a +# metaclass to define most of the SimObject parameter behavior for +# this class hierarchy. +# +##################################################################### + +# The metaclass for ConfigNode (and thus for everything that derives +# from ConfigNode, including SimObject). This class controls how new +# classes that derive from ConfigNode are instantiated, and provides +# inherited class behavior (just like a class controls how instances +# of that class are instantiated, and provides inherited instance +# behavior). +class MetaConfigNode(type): + + # __new__ is called before __init__, and is where the statements + # in the body of the class definition get loaded into the class's + # __dict__. We intercept this to filter out parameter assignments + # and only allow "private" attributes to be passed to the base + # __new__ (starting with underscore). + def __new__(cls, name, bases, dict): + priv_keys = [k for k in dict.iterkeys() if k.startswith('_')] + priv_dict = {} + for k in priv_keys: priv_dict[k] = dict[k]; del dict[k] + # entries left in dict will get passed to __init__, where we'll + # deal with them as params. + return super(MetaConfigNode, cls).__new__(cls, name, bases, priv_dict) + + # initialization: start out with an empty param dict (makes life + # simpler if we can assume _param_dict is always valid). Also + # build inheritance list to simplify searching for inherited + # params. Finally set parameters specified in class definition + # (if any). + def __init__(cls, name, bases, dict): + super(MetaConfigNode, cls).__init__(cls, name, bases, {}) + # initialize _param_dict to empty + cls._param_dict = {} + # __mro__ is the ordered list of classes Python uses for + # method resolution. We want to pick out the ones that have a + # _param_dict attribute for doing parameter lookups. + cls._param_bases = \ + [c for c in cls.__mro__ if hasattr(c, '_param_dict')] + # initialize attributes with values from class definition + for (pname, value) in dict.items(): + try: + setattr(cls, pname, value) + except Exception, exc: + print "Error setting '%s' to '%s' on class '%s'\n" \ + % (pname, value, cls.__name__), exc + + # set the class's parameter dictionary (called when loading + # class descriptions) + def set_param_dict(cls, param_dict): + # should only be called once (current one should be empty one + # from __init__) + assert not cls._param_dict + cls._param_dict = param_dict + # initialize attributes with default values + for (pname, param) in param_dict.items(): + try: + setattr(cls, pname, param.default) + except Exception, exc: + print "Error setting '%s' default on class '%s'\n" \ + % (pname, cls.__name__), exc + + # Lookup a parameter description by name in the given class. Use + # the _param_bases list defined in __init__ to go up the + # inheritance hierarchy if necessary. + def lookup_param(cls, param_name): + for c in cls._param_bases: + param = c._param_dict.get(param_name) + if param: return param + return None + + # Set attribute (called on foo.attr_name = value when foo is an + # instance of class cls). + def __setattr__(cls, attr_name, value): + # normal processing for private attributes + if attr_name.startswith('_'): + object.__setattr__(cls, attr_name, value) + return + # no '_': must be SimObject param + param = cls.lookup_param(attr_name) + if not param: + raise AttributeError, \ + "Class %s has no parameter %s" % (cls.__name__, attr_name) + # It's ok: set attribute by delegating to 'object' class. + # Note the use of param.make_value() to verify/canonicalize + # the assigned value + object.__setattr__(cls, attr_name, param.make_value(value)) + + # generator that iterates across all parameters for this class and + # all classes it inherits from + def all_param_names(cls): + for c in cls._param_bases: + for p in c._param_dict.iterkeys(): + yield p + +# The ConfigNode class is the root of the special hierarchy. Most of +# the code in this class deals with the configuration hierarchy itself +# (parent/child node relationships). +class ConfigNode(object): + # Specify metaclass. Any class inheriting from ConfigNode will + # get this metaclass. + __metaclass__ = MetaConfigNode + + # Constructor. Since bare ConfigNodes don't have parameters, just + # worry about the name and the parent/child stuff. + def __init__(self, _name, _parent=None): + # Type-check _name + if type(_name) != str: + if isinstance(_name, ConfigNode): + # special case message for common error of trying to + # coerce a SimObject to the wrong type + raise TypeError, \ + "Attempt to coerce %s to %s" \ + % (_name.__class__.__name__, self.__class__.__name__) + else: + raise TypeError, \ + "%s name must be string (was %s, %s)" \ + % (self.__class__.__name__, _name, type(_name)) + # if specified, parent must be a subclass of ConfigNode + if _parent != None and not isinstance(_parent, ConfigNode): + raise TypeError, \ + "%s parent must be ConfigNode subclass (was %s, %s)" \ + % (self.__class__.__name__, _name, type(_name)) + self._name = _name + self._parent = _parent + self._children = {} + if (_parent): + _parent.__addChild(self) + # Set up absolute path from root. + if (_parent and _parent._path != 'Universe'): + self._path = _parent._path + '.' + self._name + else: + self._path = self._name + + # When printing (e.g. to .ini file), just give the name. + def __str__(self): + return self._name + + # Catch attribute accesses that could be requesting children, and + # satisfy them. Note that __getattr__ is called only if the + # regular attribute lookup fails, so private and parameter lookups + # will already be satisfied before we ever get here. + def __getattr__(self, name): + try: + return self._children[name] + except KeyError: + raise AttributeError, \ + "Node '%s' has no attribute or child '%s'" \ + % (self._name, name) + + # Set attribute. All attribute assignments go through here. Must + # be private attribute (starts with '_') or valid parameter entry. + # Basically identical to MetaConfigClass.__setattr__(), except + # this handles instances rather than class attributes. + def __setattr__(self, attr_name, value): + if attr_name.startswith('_'): + object.__setattr__(self, attr_name, value) + return + # not private; look up as param + param = self.__class__.lookup_param(attr_name) + if not param: + raise AttributeError, \ + "Class %s has no parameter %s" \ + % (self.__class__.__name__, attr_name) + # It's ok: set attribute by delegating to 'object' class. + # Note the use of param.make_value() to verify/canonicalize + # the assigned value + object.__setattr__(self, attr_name, param.make_value(value)) + + # Add a child to this node. + def __addChild(self, new_child): + # set child's parent before calling this function + assert new_child._parent == self + if not isinstance(new_child, ConfigNode): + raise TypeError, \ + "ConfigNode child must also be of class ConfigNode" + if new_child._name in self._children: + raise AttributeError, \ + "Node '%s' already has a child '%s'" \ + % (self._name, new_child._name) + self._children[new_child._name] = new_child + + # operator overload for '+='. You can say "node += child" to add + # a child that was created with parent=None. An early attempt + # at playing with syntax; turns out not to be that useful. + def __iadd__(self, new_child): + if new_child._parent != None: + raise AttributeError, \ + "Node '%s' already has a parent" % new_child._name + new_child._parent = self + self.__addChild(new_child) + return self + + # Print instance info to .ini file. + def _instantiate(self): + print '[' + self._path + ']' # .ini section header + if self._children: + # instantiate children in sorted order for backward + # compatibility (else we can end up with cpu1 before cpu0). + child_names = self._children.keys() + child_names.sort() + print 'children =', + for child_name in child_names: + print child_name, + print + self._instantiateParams() + print + # recursively dump out children + if self._children: + for child_name in child_names: + self._children[child_name]._instantiate() + + # ConfigNodes have no parameters. Overridden by SimObject. + def _instantiateParams(self): + pass + +# SimObject is a minimal extension of ConfigNode, implementing a +# hierarchy node that corresponds to an M5 SimObject. It prints out a +# "type=" line to indicate its SimObject class, prints out the +# assigned parameters corresponding to its class, and allows +# parameters to be set by keyword in the constructor. Note that most +# of the heavy lifting for the SimObject param handling is done in the +# MetaConfigNode metaclass. + +class SimObject(ConfigNode): + # initialization: like ConfigNode, but handle keyword-based + # parameter initializers. + def __init__(self, _name, _parent=None, **params): + ConfigNode.__init__(self, _name, _parent) + for param, value in params.items(): + setattr(self, param, value) + + # print type and parameter values to .ini file + def _instantiateParams(self): + print "type =", self.__class__._name + for pname in self.__class__.all_param_names(): + value = getattr(self, pname) + if value != None: + print pname, '=', value + + def _sim_code(cls): + name = cls.__name__ + param_names = cls._param_dict.keys() + param_names.sort() + code = "BEGIN_DECLARE_SIM_OBJECT_PARAMS(%s)\n" % name + decls = [" " + cls._param_dict[pname].sim_decl(pname) \ + for pname in param_names] + code += "\n".join(decls) + "\n" + code += "END_DECLARE_SIM_OBJECT_PARAMS(%s)\n\n" % name + code += "BEGIN_INIT_SIM_OBJECT_PARAMS(%s)\n" % name + inits = [" " + cls._param_dict[pname].sim_init(pname) \ + for pname in param_names] + code += ",\n".join(inits) + "\n" + code += "END_INIT_SIM_OBJECT_PARAMS(%s)\n\n" % name + return code + _sim_code = classmethod(_sim_code) + +##################################################################### +# +# Parameter description classes +# +# The _param_dict dictionary in each class maps parameter names to +# either a Param or a VectorParam object. These objects contain the +# parameter description string, the parameter type, and the default +# value (loaded from the PARAM section of the .odesc files). The +# make_value() method on these objects is used to force whatever value +# is assigned to the parameter to the appropriate type. +# +# Note that the default values are loaded into the class's attribute +# space when the parameter dictionary is initialized (in +# MetaConfigNode.set_param_dict()); after that point they aren't +# used. +# +##################################################################### + +def isNullPointer(value): + return isinstance(value, NullSimObject) + +def isSimObjectType(ptype): + return issubclass(ptype, SimObject) + +# Regular parameter. +class Param(object): + # Constructor. E.g., Param(Int, "number of widgets", 5) + def __init__(self, ptype, desc, default=None): + self.ptype = ptype + self.ptype_name = self.ptype.__name__ + self.desc = desc + self.default = default + + # Convert assigned value to appropriate type. Force parameter + # value (rhs of '=') to ptype (or None, which means not set). + def make_value(self, value): + # nothing to do if None or already correct type. Also allow NULL + # pointer to be assigned where a SimObject is expected. + if value == None or isinstance(value, self.ptype) or \ + isNullPointer(value) and isSimObjectType(self.ptype): + return value + # this type conversion will raise an exception if it's illegal + return self.ptype(value) + + def sim_decl(self, name): + return 'Param<%s> %s;' % (self.ptype_name, name) + + def sim_init(self, name): + if self.default == None: + return 'INIT_PARAM(%s, "%s")' % (name, self.desc) + else: + return 'INIT_PARAM_DFLT(%s, "%s", %s)' % \ + (name, self.desc, str(self.default)) + +# The _VectorParamValue class is a wrapper for vector-valued +# parameters. The leading underscore indicates that users shouldn't +# see this class; it's magically generated by VectorParam. The +# parameter values are stored in the 'value' field as a Python list of +# whatever type the parameter is supposed to be. The only purpose of +# storing these instead of a raw Python list is that we can override +# the __str__() method to not print out '[' and ']' in the .ini file. +class _VectorParamValue(object): + def __init__(self, list): + self.value = list + + def __str__(self): + return ' '.join(map(str, self.value)) + +# Vector-valued parameter description. Just like Param, except that +# the value is a vector (list) of the specified type instead of a +# single value. +class VectorParam(Param): + + # Inherit Param constructor. However, the resulting parameter + # will be a list of ptype rather than a single element of ptype. + def __init__(self, ptype, desc, default=None): + Param.__init__(self, ptype, desc, default) + + # Convert assigned value to appropriate type. If the RHS is not a + # list or tuple, it generates a single-element list. + def make_value(self, value): + if value == None: return value + if isinstance(value, list) or isinstance(value, tuple): + # list: coerce each element into new list + val_list = [Param.make_value(self, v) for v in iter(value)] + else: + # singleton: coerce & wrap in a list + val_list = [Param.make_value(self, value)] + # wrap list in _VectorParamValue (see above) + return _VectorParamValue(val_list) + + def sim_decl(self, name): + return 'VectorParam<%s> %s;' % (self.ptype_name, name) + + # sim_init inherited from Param + +##################################################################### +# +# Parameter Types +# +# Though native Python types could be used to specify parameter types +# (the 'ptype' field of the Param and VectorParam classes), it's more +# flexible to define our own set of types. This gives us more control +# over how Python expressions are converted to values (via the +# __init__() constructor) and how these values are printed out (via +# the __str__() conversion method). Eventually we'll need these types +# to correspond to distinct C++ types as well. +# +##################################################################### + +# Integer parameter type. +class Int(object): + # Constructor. Value must be Python int or long (long integer). + def __init__(self, value): + t = type(value) + if t == int or t == long: + self.value = value + else: + raise TypeError, "Int param got value %s %s" % (repr(value), t) + + # Use Python string conversion. Note that this puts an 'L' on the + # end of long integers; we can strip that off here if it gives us + # trouble. + def __str__(self): + return str(self.value) + +# Counter, Addr, and Tick are just aliases for Int for now. +class Counter(Int): + pass + +class Addr(Int): + pass + +class Tick(Int): + pass + +# Boolean parameter type. +class Bool(object): + + # Constructor. Typically the value will be one of the Python bool + # constants True or False (or the aliases true and false below). + # Also need to take integer 0 or 1 values since bool was not a + # distinct type in Python 2.2. Parse a bunch of boolean-sounding + # strings too just for kicks. + def __init__(self, value): + t = type(value) + if t == bool: + self.value = value + elif t == int or t == long: + if value == 1: + self.value = True + elif value == 0: + self.value = False + elif t == str: + v = value.lower() + if v == "true" or v == "t" or v == "yes" or v == "y": + self.value = True + elif v == "false" or v == "f" or v == "no" or v == "n": + self.value = False + # if we didn't set it yet, it must not be something we understand + if not hasattr(self, 'value'): + raise TypeError, "Bool param got value %s %s" % (repr(value), t) + + # Generate printable string version. + def __str__(self): + if self.value: return "true" + else: return "false" + +# String-valued parameter. +class String(object): + # Constructor. Value must be Python string. + def __init__(self, value): + t = type(value) + if t == str: + self.value = value + else: + raise TypeError, "String param got value %s %s" % (repr(value), t) + + # Generate printable string version. Not too tricky. + def __str__(self): + return self.value + +# Special class for NULL pointers. Note the special check in +# make_param_value() above that lets these be assigned where a +# SimObject is required. +class NullSimObject(object): + # Constructor. No parameters, nothing to do. + def __init__(self): + pass + + def __str__(self): + return "NULL" + +# The only instance you'll ever need... +NULL = NullSimObject() + +# Enumerated types are a little more complex. The user specifies the +# type as Enum(foo) where foo is either a list or dictionary of +# alternatives (typically strings, but not necessarily so). (In the +# long run, the integer value of the parameter will be the list index +# or the corresponding dictionary value. For now, since we only check +# that the alternative is valid and then spit it into a .ini file, +# there's not much point in using the dictionary.) + +# What Enum() must do is generate a new type encapsulating the +# provided list/dictionary so that specific values of the parameter +# can be instances of that type. We define two hidden internal +# classes (_ListEnum and _DictEnum) to serve as base classes, then +# derive the new type from the appropriate base class on the fly. + + +# Base class for list-based Enum types. +class _ListEnum(object): + # Constructor. Value must be a member of the type's map list. + def __init__(self, value): + if value in self.map: + self.value = value + self.index = self.map.index(value) + else: + raise TypeError, "Enum param got bad value '%s' (not in %s)" \ + % (value, self.map) + + # Generate printable string version of value. + def __str__(self): + return str(self.value) + +class _DictEnum(object): + # Constructor. Value must be a key in the type's map dictionary. + def __init__(self, value): + if value in self.map: + self.value = value + self.index = self.map[value] + else: + raise TypeError, "Enum param got bad value '%s' (not in %s)" \ + % (value, self.map.keys()) + + # Generate printable string version of value. + def __str__(self): + return str(self.value) + +# Enum metaclass... calling Enum(foo) generates a new type (class) +# that derives from _ListEnum or _DictEnum as appropriate. +class Enum(type): + # counter to generate unique names for generated classes + counter = 1 + + def __new__(cls, map): + if isinstance(map, dict): + base = _DictEnum + keys = map.keys() + elif isinstance(map, list): + base = _ListEnum + keys = map + else: + raise TypeError, "Enum map must be list or dict (got %s)" % map + classname = "Enum%04d" % Enum.counter + Enum.counter += 1 + # New class derives from selected base, and gets a 'map' + # attribute containing the specified list or dict. + return type.__new__(cls, classname, (base,), { 'map': map }) + + +# +# "Constants"... handy aliases for various values. +# + +# For compatibility with C++ bool constants. +false = False +true = True + +# Some memory range specifications use this as a default upper bound. +MAX_ADDR = 2 ** 63 + +# For power-of-two sizing, e.g. 64*K gives an integer value 65536. +K = 1024 +M = K*K +G = K*M + +##################################################################### +# +# Object description loading. +# +# The final step is to define the classes corresponding to M5 objects +# and their parameters. These classes are described in .odesc files +# in the source tree. This code walks the tree to find those files +# and loads up the descriptions (by evaluating them in pieces as +# Python code). +# +# +# Because SimObject classes inherit from other SimObject classes, and +# can use arbitrary other SimObject classes as parameter types, we +# have to do this in three steps: +# +# 1. Walk the tree to find all the .odesc files. Note that the base +# of the filename *must* match the class name. This step builds a +# mapping from class names to file paths. +# +# 2. Start generating empty class definitions (via def_class()) using +# the OBJECT field of the .odesc files to determine inheritance. +# def_class() recurses on demand to define needed base classes before +# derived classes. +# +# 3. Now that all of the classes are defined, go through the .odesc +# files one more time loading the parameter descriptions. +# +##################################################################### + +# dictionary: maps object names to file paths +odesc_file = {} + +# dictionary: maps object names to boolean flag indicating whether +# class definition was loaded yet. Since SimObject is defined in +# m5.config.py, count it as loaded. +odesc_loaded = { 'SimObject': True } + +# Find odesc files in namelist and initialize odesc_file and +# odesc_loaded dictionaries. Called via os.path.walk() (see below). +def find_odescs(process, dirpath, namelist): + # Prune out SCCS directories so we don't process s.*.odesc files. + i = 0 + while i < len(namelist): + if namelist[i] == "SCCS": + del namelist[i] + else: + i = i + 1 + # Find .odesc files and record them. + for name in namelist: + if name.endswith('.odesc'): + objname = name[:name.rindex('.odesc')] + path = os.path.join(dirpath, name) + if odesc_file.has_key(objname): + print "Warning: duplicate object names:", \ + odesc_file[objname], path + odesc_file[objname] = path + odesc_loaded[objname] = False + + +# Regular expression string for parsing .odesc files. +file_re_string = r''' +^OBJECT: \s* (\w+) \s* \( \s* (\w+) \s* \) +\s* +^PARAMS: \s*\n ( (\s+.*\n)* ) +''' + +# Compiled regular expression object. +file_re = re.compile(file_re_string, re.MULTILINE | re.VERBOSE) + +# .odesc file parsing function. Takes a filename and returns tuple of +# object name, object base, and parameter description section. +def parse_file(path): + f = open(path, 'r').read() + m = file_re.search(f) + if not m: + print "Can't parse", path + sys.exit(1) + return (m.group(1), m.group(2), m.group(3)) + +# Define SimObject class based on description in specified filename. +# Class itself is empty except for _name attribute; parameter +# descriptions will be loaded later. Will recurse to define base +# classes as needed before defining specified class. +def def_class(path): + # load & parse file + (obj, parent, params) = parse_file(path) + # check to see if base class is defined yet; define it if not + if not odesc_loaded.has_key(parent): + print "No .odesc file found for", parent + sys.exit(1) + if not odesc_loaded[parent]: + def_class(odesc_file[parent]) + # define the class. The _name attribute of the class lets us + # track the actual SimObject class name even when we derive new + # subclasses in scripts (to provide new parameter value settings). + s = "class %s(%s): _name = '%s'" % (obj, parent, obj) + try: + # execute in global namespace, so new class will be globally + # visible + exec s in globals() + except Exception, exc: + print "Object error in %s:" % path, exc + # mark this file as loaded + odesc_loaded[obj] = True + +# Munge an arbitrary Python code string to get it to execute (mostly +# dealing with indentation). Stolen from isa_parser.py... see +# comments there for a more detailed description. +def fixPythonIndentation(s): + # get rid of blank lines first + s = re.sub(r'(?m)^\s*\n', '', s); + if (s != '' and re.match(r'[ \t]', s[0])): + s = 'if 1:\n' + s + return s + +# Load parameter descriptions from .odesc file. Object class must +# already be defined. +def def_params(path): + # load & parse file + (obj_name, parent_name, param_code) = parse_file(path) + # initialize param dict + param_dict = {} + # execute parameter descriptions. + try: + # "in globals(), param_dict" makes exec use the current + # globals as the global namespace (so all of the Param + # etc. objects are visible) and param_dict as the local + # namespace (so the newly defined parameter variables will be + # entered into param_dict). + exec fixPythonIndentation(param_code) in globals(), param_dict + except Exception, exc: + print "Param error in %s:" % path, exc + return + # Convert object name string to Python class object + obj = eval(obj_name) + # Set the object's parameter description dictionary (see MetaConfigNode). + obj.set_param_dict(param_dict) + + +# Walk directory tree to find .odesc files. +# Someday we'll have to make the root path an argument instead of +# hard-coding it. For now the assumption is you're running this in +# util/config. +root = '../..' +os.path.walk(root, find_odescs, None) + +# Iterate through file dictionary and define classes. +for objname, path in odesc_file.iteritems(): + if not odesc_loaded[objname]: + def_class(path) + +sim_object_list = odesc_loaded.keys() +sim_object_list.sort() + +# Iterate through files again and load parameters. +for path in odesc_file.itervalues(): + def_params(path) + +##################################################################### + +# Hook to generate C++ parameter code. +def gen_sim_code(file): + for objname in sim_object_list: + print >> file, eval("%s._sim_code()" % objname) + +# The final hook to generate .ini files. Called from configuration +# script once config is built. +def instantiate(*objs): + for obj in objs: + obj._instantiate() + + diff --git a/util/emacs/m5-c-style.el b/util/emacs/m5-c-style.el index 7f25e9f5f..b9d16a4b1 100644 --- a/util/emacs/m5-c-style.el +++ b/util/emacs/m5-c-style.el @@ -1,4 +1,4 @@ -; Copyright (c) 2003 The Regents of The University of Michigan +; Copyright (c) 2003-2004 The Regents of The University of Michigan ; All rights reserved. ; ; Redistribution and use in source and binary forms, with or without @@ -28,12 +28,13 @@ ; Steve Reinhardt (c-add-style "m5" - '((c-basic-offset . 4) - (c-offsets-alist . ((substatement-open . 0) - (inline-open . 0) - (block-open . -4) - (case-label . 2) - (label . 2) - (statement-case-intro . 2) - (statement-case-open . 2) - (access-label . -2))))) + '((c-basic-offset . 4) + (c-offsets-alist . ((substatement-open . 0) + (inline-open . 0) + (block-open . -4) + (case-label . 2) + (label . 2) + (statement-case-intro . 2) + (statement-case-open . 2) + (access-label . -2) + (innamespace . 0))))) diff --git a/util/tracediff b/util/tracediff index 0aa579a7d..ed35d5dd7 100755 --- a/util/tracediff +++ b/util/tracediff @@ -41,8 +41,8 @@ $sim2 = shift; # be given to both invocations $simargs = '"' . join('" "', @ARGV) . '"'; -$cmd1 = "$sim1 $simargs --stats:file=tracediff-$$-1.stats 2>&1 |"; -$cmd2 = "$sim2 $simargs --stats:file=tracediff-$$-2.stats 2>&1 |"; +$cmd1 = "$sim1 $simargs --stats:text_file=tracediff-$$-1.stats 2>&1 |"; +$cmd2 = "$sim2 $simargs --stats:text_file=tracediff-$$-2.stats 2>&1 |"; # This only works if you have rundiff in your path. I just edit it # with an explicit path if necessary. |