From: Nathan Binkert Date: Mon, 12 Jun 2006 02:01:34 +0000 (-0400) Subject: Merge iceaxe.:/Volumes/work/research/m5/head X-Git-Tag: m5_2.0_beta1~66^2~2^2^2 X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=3c95f5958fd1a90cf83d85e1b24fb700c07bae91;p=gem5.git Merge iceaxe.:/Volumes/work/research/m5/head into iceaxe.:/Volumes/work/research/m5/merge src/cpu/simple/base.cc: src/kern/kernel_stats.cc: src/kern/kernel_stats.hh: src/kern/system_events.cc: src/kern/system_events.hh: src/python/m5/objects/System.py: src/sim/system.cc: src/sim/system.hh: hand merge --HG-- rename : build/SConstruct => SConstruct rename : SConscript => src/SConscript rename : arch/alpha/freebsd/system.cc => src/arch/alpha/freebsd/system.cc rename : arch/alpha/linux/system.cc => src/arch/alpha/linux/system.cc rename : arch/alpha/linux/system.hh => src/arch/alpha/linux/system.hh rename : arch/alpha/system.cc => src/arch/alpha/system.cc rename : arch/alpha/tru64/system.cc => src/arch/alpha/tru64/system.cc rename : base/statistics.cc => src/base/statistics.cc rename : base/statistics.hh => src/base/statistics.hh rename : base/stats/mysql.cc => src/base/stats/mysql.cc rename : base/stats/mysql.hh => src/base/stats/mysql.hh rename : base/stats/statdb.cc => src/base/stats/statdb.cc rename : base/stats/statdb.hh => src/base/stats/statdb.hh rename : base/stats/text.cc => src/base/stats/text.cc rename : base/stats/text.hh => src/base/stats/text.hh rename : cpu/simple/cpu.cc => src/cpu/simple/base.cc rename : kern/kernel_stats.cc => src/kern/kernel_stats.cc rename : kern/kernel_stats.hh => src/kern/kernel_stats.hh rename : kern/system_events.cc => src/kern/system_events.cc rename : kern/system_events.hh => src/kern/system_events.hh rename : python/m5/objects/System.py => src/python/m5/objects/System.py rename : sim/system.cc => src/sim/system.cc rename : sim/system.hh => src/sim/system.hh rename : test/stattest.cc => src/unittest/stattest.cc extra : convert_revision : 4bb576a2bf5e32784efc48030bd776c6c7c29a7c --- 3c95f5958fd1a90cf83d85e1b24fb700c07bae91 diff --cc SConstruct index fb6bc609e,000000000..0cf15b1f9 mode 100644,000000..100644 --- a/SConstruct +++ b/SConstruct @@@ -1,507 -1,0 +1,505 @@@ +# -*- mode:python -*- + +# Copyright (c) 2004-2005 The Regents of The University of Michigan +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer; +# redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution; +# neither the name of the copyright holders nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# Authors: Steve Reinhardt + +################################################### +# +# SCons top-level build description (SConstruct) file. +# +# While in this directory ('m5'), just type 'scons' to build the default +# configuration (see below), or type 'scons build//' +# to build some other configuration (e.g., 'build/ALPHA_FS/m5.opt' for +# the optimized full-system version). +# +# You can build M5 in a different directory as long as there is a +# 'build/' somewhere along the target path. The build system +# expdects that all configs under the same build directory are being +# built for the same host system. +# +# Examples: +# These two commands are equivalent. The '-u' option tells scons to +# search up the directory tree for this SConstruct file. +# % cd /m5 ; scons build/ALPHA_FS/m5.debug +# % cd /m5/build/ALPHA_FS; scons -u m5.debug +# These two commands are equivalent and demonstrate building in a +# directory outside of the source tree. The '-C' option tells scons +# to chdir to the specified directory to find this SConstruct file. +# % cd /m5 ; scons /local/foo/build/ALPHA_FS/m5.debug +# % cd /local/foo/build/ALPHA_FS; scons -C /m5 m5.debug +# +# You can use 'scons -H' to print scons options. If you're in this +# 'm5' directory (or use -u or -C to tell scons where to find this +# file), you can use 'scons -h' to print all the M5-specific build +# options as well. +# +################################################### + +# Python library imports +import sys +import os + +# Check for recent-enough Python and SCons versions. If your system's +# default installation of Python is not recent enough, you can use a +# non-default installation of the Python interpreter by either (1) +# rearranging your PATH so that scons finds the non-default 'python' +# first or (2) explicitly invoking an alternative interpreter on the +# scons script, e.g., "/usr/local/bin/python2.4 `which scons` [args]". +EnsurePythonVersion(2,4) + +# Ironically, SCons 0.96 dies if you give EnsureSconsVersion a +# 3-element version number. +min_scons_version = (0,96,91) +try: + EnsureSConsVersion(*min_scons_version) +except: + print "Error checking current SCons version." + print "SCons", ".".join(map(str,min_scons_version)), "or greater required." + Exit(2) + + +# The absolute path to the current directory (where this file lives). +ROOT = Dir('.').abspath + +# Paths to the M5 and external source trees. +SRCDIR = os.path.join(ROOT, 'src') + +# tell python where to find m5 python code +sys.path.append(os.path.join(ROOT, 'src/python')) + +################################################### +# +# Figure out which configurations to set up based on the path(s) of +# the target(s). +# +################################################### + +# Find default configuration & binary. +Default(os.environ.get('M5_DEFAULT_BINARY', 'build/ALPHA_SE/m5.debug')) + +# Ask SCons which directory it was invoked from. +launch_dir = GetLaunchDir() + +# Make targets relative to invocation directory +abs_targets = map(lambda x: os.path.normpath(os.path.join(launch_dir, str(x))), + BUILD_TARGETS) + +# helper function: find last occurrence of element in list +def rfind(l, elt, offs = -1): + for i in range(len(l)+offs, 0, -1): + if l[i] == elt: + return i + raise ValueError, "element not found" + +# Each target must have 'build' in the interior of the path; the +# directory below this will determine the build parameters. For +# example, for target 'foo/bar/build/ALPHA_SE/arch/alpha/blah.do' we +# recognize that ALPHA_SE specifies the configuration because it +# follow 'build' in the bulid path. + +# Generate a list of the unique build roots and configs that the +# collected targets reference. +build_paths = [] +build_root = None +for t in abs_targets: + path_dirs = t.split('/') + try: + build_top = rfind(path_dirs, 'build', -2) + except: + print "Error: no non-leaf 'build' dir found on target path", t + Exit(1) + this_build_root = os.path.join('/',*path_dirs[:build_top+1]) + if not build_root: + build_root = this_build_root + else: + if this_build_root != build_root: + print "Error: build targets not under same build root\n"\ + " %s\n %s" % (build_root, this_build_root) + Exit(1) + build_path = os.path.join('/',*path_dirs[:build_top+2]) + if build_path not in build_paths: + build_paths.append(build_path) + +################################################### +# +# Set up the default build environment. This environment is copied +# and modified according to each selected configuration. +# +################################################### + +env = Environment(ENV = os.environ, # inherit user's environment vars + ROOT = ROOT, + SRCDIR = SRCDIR) + +env.SConsignFile("sconsign") + +# Default duplicate option is to use hard links, but this messes up +# when you use emacs to edit a file in the target dir, as emacs moves +# file to file~ then copies to file, breaking the link. Symbolic +# (soft) links work better. +env.SetOption('duplicate', 'soft-copy') + +# I waffle on this setting... it does avoid a few painful but +# unnecessary builds, but it also seems to make trivial builds take +# noticeably longer. +if False: + env.TargetSignatures('content') + +# M5_PLY is used by isa_parser.py to find the PLY package. +env.Append(ENV = { 'M5_PLY' : Dir('ext/ply') }) + +# Set up default C++ compiler flags +env.Append(CCFLAGS='-pipe') +env.Append(CCFLAGS='-fno-strict-aliasing') +env.Append(CCFLAGS=Split('-Wall -Wno-sign-compare -Werror -Wundef')) +if sys.platform == 'cygwin': + # cygwin has some header file issues... + env.Append(CCFLAGS=Split("-Wno-uninitialized")) +env.Append(CPPPATH=[Dir('ext/dnet')]) + +# Find Python include and library directories for embedding the +# interpreter. For consistency, we will use the same Python +# installation used to run scons (and thus this script). If you want +# to link in an alternate version, see above for instructions on how +# to invoke scons with a different copy of the Python interpreter. + +# Get brief Python version name (e.g., "python2.4") for locating +# include & library files +py_version_name = 'python' + sys.version[:3] + +# include path, e.g. /usr/local/include/python2.4 +env.Append(CPPPATH = os.path.join(sys.exec_prefix, 'include', py_version_name)) +env.Append(LIBS = py_version_name) +# add library path too if it's not in the default place +if sys.exec_prefix != '/usr': + env.Append(LIBPATH = os.path.join(sys.exec_prefix, 'lib')) + +# Set up SWIG flags & scanner + +env.Append(SWIGFLAGS=Split('-c++ -python -modern $_CPPINCFLAGS')) + +import SCons.Scanner + +swig_inc_re = '^[ \t]*[%,#][ \t]*(?:include|import)[ \t]*(<|")([^>"]+)(>|")' + +swig_scanner = SCons.Scanner.ClassicCPP("SwigScan", ".i", "CPPPATH", + swig_inc_re) + +env.Append(SCANNERS = swig_scanner) + +# Other default libraries +env.Append(LIBS=['z']) + +# Platform-specific configuration. Note again that we assume that all +# builds under a given build root run on the same host platform. +conf = Configure(env, + conf_dir = os.path.join(build_root, '.scons_config'), + log_file = os.path.join(build_root, 'scons_config.log')) + +# Check for (C99 FP environment control) +have_fenv = conf.CheckHeader('fenv.h', '<>') +if not have_fenv: + print "Warning: Header file not found." + print " This host has no IEEE FP rounding mode control." + +# Check for mysql. +mysql_config = WhereIs('mysql_config') +have_mysql = mysql_config != None + +# Check MySQL version. +if have_mysql: + mysql_version = os.popen(mysql_config + ' --version').read() + mysql_version = mysql_version.split('.') + mysql_major = int(mysql_version[0]) + mysql_minor = int(mysql_version[1]) + # This version check is probably overly conservative, but it deals + # with the versions we have installed. + if mysql_major < 4 or (mysql_major == 4 and mysql_minor < 1): + print "Warning: MySQL v4.1 or newer required." + have_mysql = False + +# Set up mysql_config commands. +if have_mysql: + mysql_config_include = mysql_config + ' --include' + if os.system(mysql_config_include + ' > /dev/null') != 0: + # older mysql_config versions don't support --include, use + # --cflags instead + mysql_config_include = mysql_config + ' --cflags | sed s/\\\'//g' + # This seems to work in all versions + mysql_config_libs = mysql_config + ' --libs' + +env = conf.Finish() + +# Define the universe of supported ISAs +env['ALL_ISA_LIST'] = ['alpha', 'sparc', 'mips'] + +# Define the universe of supported CPU models +env['ALL_CPU_LIST'] = ['AtomicSimpleCPU', 'TimingSimpleCPU', + 'FullCPU', 'AlphaFullCPU', + 'OzoneSimpleCPU', 'OzoneCPU', 'CheckerCPU'] + +# Sticky options get saved in the options file so they persist from +# one invocation to the next (unless overridden, in which case the new +# value becomes sticky). +sticky_opts = Options(args=ARGUMENTS) +sticky_opts.AddOptions( + EnumOption('TARGET_ISA', 'Target ISA', 'alpha', env['ALL_ISA_LIST']), + BoolOption('FULL_SYSTEM', 'Full-system support', False), + # There's a bug in scons 0.96.1 that causes ListOptions with list + # values (more than one value) not to be able to be restored from + # a saved option file. If this causes trouble then upgrade to + # scons 0.96.90 or later. + ListOption('CPU_MODELS', 'CPU models', 'AtomicSimpleCPU,TimingSimpleCPU', + env['ALL_CPU_LIST']), + BoolOption('ALPHA_TLASER', + 'Model Alpha TurboLaser platform (vs. Tsunami)', False), + BoolOption('NO_FAST_ALLOC', 'Disable fast object allocator', False), + BoolOption('EFENCE', 'Link with Electric Fence malloc debugger', + False), + BoolOption('SS_COMPATIBLE_FP', + 'Make floating-point results compatible with SimpleScalar', + False), + BoolOption('USE_SSE2', + 'Compile for SSE2 (-msse2) to get IEEE FP on x86 hosts', + False), - BoolOption('STATS_BINNING', 'Bin statistics by CPU mode', have_mysql), + BoolOption('USE_MYSQL', 'Use MySQL for stats output', have_mysql), + BoolOption('USE_FENV', 'Use IEEE mode control', have_fenv), + ('CC', 'C compiler', os.environ.get('CC', env['CC'])), + ('CXX', 'C++ compiler', os.environ.get('CXX', env['CXX'])), + BoolOption('BATCH', 'Use batch pool for build and tests', False), + ('BATCH_CMD', 'Batch pool submission command name', 'qdo') + ) + +# Non-sticky options only apply to the current build. +nonsticky_opts = Options(args=ARGUMENTS) +nonsticky_opts.AddOptions( + BoolOption('update_ref', 'Update test reference outputs', False) + ) + +# These options get exported to #defines in config/*.hh (see m5/SConscript). +env.ExportOptions = ['FULL_SYSTEM', 'ALPHA_TLASER', 'USE_FENV', \ - 'USE_MYSQL', 'NO_FAST_ALLOC', 'SS_COMPATIBLE_FP', \ - 'STATS_BINNING'] ++ 'USE_MYSQL', 'NO_FAST_ALLOC', 'SS_COMPATIBLE_FP'] + +# Define a handy 'no-op' action +def no_action(target, source, env): + return 0 + +env.NoAction = Action(no_action, None) + +################################################### +# +# Define a SCons builder for configuration flag headers. +# +################################################### + +# This function generates a config header file that #defines the +# option symbol to the current option setting (0 or 1). The source +# operands are the name of the option and a Value node containing the +# value of the option. +def build_config_file(target, source, env): + (option, value) = [s.get_contents() for s in source] + f = file(str(target[0]), 'w') + print >> f, '#define', option, value + f.close() + return None + +# Generate the message to be printed when building the config file. +def build_config_file_string(target, source, env): + (option, value) = [s.get_contents() for s in source] + return "Defining %s as %s in %s." % (option, value, target[0]) + +# Combine the two functions into a scons Action object. +config_action = Action(build_config_file, build_config_file_string) + +# The emitter munges the source & target node lists to reflect what +# we're really doing. +def config_emitter(target, source, env): + # extract option name from Builder arg + option = str(target[0]) + # True target is config header file + target = os.path.join('config', option.lower() + '.hh') + # Force value to 0/1 even if it's a Python bool + val = int(eval(str(env[option]))) + # Sources are option name & value (packaged in SCons Value nodes) + return ([target], [Value(option), Value(val)]) + +config_builder = Builder(emitter = config_emitter, action = config_action) + +env.Append(BUILDERS = { 'ConfigFile' : config_builder }) + +################################################### +# +# Define a SCons builder for copying files. This is used by the +# Python zipfile code in src/python/SConscript, but is placed up here +# since it's potentially more generally applicable. +# +################################################### + +copy_builder = Builder(action = Copy("$TARGET", "$SOURCE")) + +env.Append(BUILDERS = { 'CopyFile' : copy_builder }) + +################################################### +# +# Define a simple SCons builder to concatenate files. +# +# Used to append the Python zip archive to the executable. +# +################################################### + +concat_builder = Builder(action = Action(['cat $SOURCES > $TARGET', + 'chmod +x $TARGET'])) + +env.Append(BUILDERS = { 'Concat' : concat_builder }) + + +# base help text +help_text = ''' +Usage: scons [scons options] [build options] [target(s)] + +''' + +# libelf build is shared across all configs in the build root. +env.SConscript('ext/libelf/SConscript', + build_dir = os.path.join(build_root, 'libelf'), + exports = 'env') + +################################################### +# +# Define build environments for selected configurations. +# +################################################### + +# rename base env +base_env = env + +for build_path in build_paths: + print "Building in", build_path + # build_dir is the tail component of build path, and is used to + # determine the build parameters (e.g., 'ALPHA_SE') + (build_root, build_dir) = os.path.split(build_path) + # Make a copy of the build-root environment to use for this config. + env = base_env.Copy() + + # Set env options according to the build directory config. + sticky_opts.files = [] + # Options for $BUILD_ROOT/$BUILD_DIR are stored in + # $BUILD_ROOT/options/$BUILD_DIR so you can nuke + # $BUILD_ROOT/$BUILD_DIR without losing your options settings. + current_opts_file = os.path.join(build_root, 'options', build_dir) + if os.path.isfile(current_opts_file): + sticky_opts.files.append(current_opts_file) + print "Using saved options file %s" % current_opts_file + else: + # Build dir-specific options file doesn't exist. + + # Make sure the directory is there so we can create it later + opt_dir = os.path.dirname(current_opts_file) + if not os.path.isdir(opt_dir): + os.mkdir(opt_dir) + + # Get default build options from source tree. Options are + # normally determined by name of $BUILD_DIR, but can be + # overriden by 'default=' arg on command line. + default_opts_file = os.path.join('build_opts', + ARGUMENTS.get('default', build_dir)) + if os.path.isfile(default_opts_file): + sticky_opts.files.append(default_opts_file) + print "Options file %s not found,\n using defaults in %s" \ + % (current_opts_file, default_opts_file) + else: + print "Error: cannot find options file %s or %s" \ + % (current_opts_file, default_opts_file) + Exit(1) + + # Apply current option settings to env + sticky_opts.Update(env) + nonsticky_opts.Update(env) + + help_text += "Sticky options for %s:\n" % build_dir \ + + sticky_opts.GenerateHelpText(env) \ + + "\nNon-sticky options for %s:\n" % build_dir \ + + nonsticky_opts.GenerateHelpText(env) + + # Process option settings. + + if not have_fenv and env['USE_FENV']: + print "Warning: not available; " \ + "forcing USE_FENV to False in", build_dir + "." + env['USE_FENV'] = False + + if not env['USE_FENV']: + print "Warning: No IEEE FP rounding mode control in", build_dir + "." + print " FP results may deviate slightly from other platforms." + + if env['EFENCE']: + env.Append(LIBS=['efence']) + + if env['USE_MYSQL']: + if not have_mysql: + print "Warning: MySQL not available; " \ + "forcing USE_MYSQL to False in", build_dir + "." + env['USE_MYSQL'] = False + else: + print "Compiling in", build_dir, "with MySQL support." + env.ParseConfig(mysql_config_libs) + env.ParseConfig(mysql_config_include) + + # Save sticky option settings back to current options file + sticky_opts.Save(current_opts_file, env) + + # Do this after we save setting back, or else we'll tack on an + # extra 'qdo' every time we run scons. + if env['BATCH']: + env['CC'] = env['BATCH_CMD'] + ' ' + env['CC'] + env['CXX'] = env['BATCH_CMD'] + ' ' + env['CXX'] + + if env['USE_SSE2']: + env.Append(CCFLAGS='-msse2') + + # The m5/SConscript file sets up the build rules in 'env' according + # to the configured options. It returns a list of environments, + # one for each variant build (debug, opt, etc.) + envList = SConscript('src/SConscript', build_dir = build_path, + exports = 'env') + + # Set up the regression tests for each build. +# for e in envList: +# SConscript('m5-test/SConscript', +# build_dir = os.path.join(build_dir, 'test', e.Label), +# exports = { 'env' : e }, duplicate = False) + +Help(help_text) + +################################################### +# +# Let SCons do its thing. At this point SCons will use the defined +# build environments to build the requested targets. +# +################################################### + diff --cc src/SConscript index b166720a1,000000000..a1c18711c mode 100644,000000..100644 --- a/src/SConscript +++ b/src/SConscript @@@ -1,399 -1,0 +1,398 @@@ +# -*- mode:python -*- + +# Copyright (c) 2004-2005 The Regents of The University of Michigan +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer; +# redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution; +# neither the name of the copyright holders nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# Authors: Steve Reinhardt + +import os +import sys +from os.path import isdir + +# This file defines how to build a particular configuration of M5 +# based on variable settings in the 'env' build environment. + +# Import build environment variable from SConstruct. +Import('env') + +################################################### +# +# Define needed sources. +# +################################################### + +# Base sources used by all configurations. + +base_sources = Split(''' + base/circlebuf.cc + base/cprintf.cc + base/fast_alloc.cc + base/fifo_buffer.cc + base/hostinfo.cc + base/hybrid_pred.cc + base/inifile.cc + base/intmath.cc + base/match.cc + base/misc.cc + base/output.cc + base/pollevent.cc + base/range.cc + base/random.cc + base/sat_counter.cc + base/serializer.cc + base/socket.cc + base/statistics.cc + base/str.cc + base/time.cc + base/trace.cc + base/traceflags.cc + base/userinfo.cc + base/compression/lzss_compression.cc + base/loader/aout_object.cc + base/loader/ecoff_object.cc + base/loader/elf_object.cc + base/loader/object_file.cc + base/loader/symtab.cc + base/stats/events.cc + base/stats/statdb.cc + base/stats/visit.cc + base/stats/text.cc + + cpu/activity.cc + cpu/base.cc + cpu/cpuevent.cc + cpu/exetrace.cc + cpu/op_class.cc + cpu/pc_event.cc + cpu/quiesce_event.cc + cpu/static_inst.cc + cpu/sampler/sampler.cc + cpu/simple_thread.cc + cpu/thread_state.cc + + encumbered/cpu/full/fu_pool.cc + + mem/bridge.cc + mem/bus.cc + mem/connector.cc + mem/mem_object.cc + mem/packet.cc + mem/physical.cc + mem/port.cc + + sim/builder.cc + sim/configfile.cc + sim/debug.cc + sim/eventq.cc + sim/faults.cc + sim/main.cc + python/swig/main_wrap.cc + sim/param.cc + sim/profile.cc + sim/root.cc + sim/serialize.cc + sim/sim_events.cc + sim/sim_object.cc + sim/startup.cc + sim/stat_context.cc + sim/stat_control.cc + sim/system.cc + sim/trace_context.cc + ''') + +# Old FullCPU sources +full_cpu_sources = Split(''' + encumbered/cpu/full/bpred.cc + encumbered/cpu/full/commit.cc + encumbered/cpu/full/cpu.cc + encumbered/cpu/full/create_vector.cc + encumbered/cpu/full/cv_spec_state.cc + encumbered/cpu/full/dd_queue.cc + encumbered/cpu/full/dep_link.cc + encumbered/cpu/full/dispatch.cc + encumbered/cpu/full/dyn_inst.cc + encumbered/cpu/full/execute.cc + encumbered/cpu/full/fetch.cc + encumbered/cpu/full/floss_reasons.cc + encumbered/cpu/full/fu_pool.cc + encumbered/cpu/full/inst_fifo.cc + encumbered/cpu/full/instpipe.cc + encumbered/cpu/full/issue.cc + encumbered/cpu/full/ls_queue.cc + encumbered/cpu/full/machine_queue.cc + encumbered/cpu/full/pipetrace.cc + encumbered/cpu/full/readyq.cc + encumbered/cpu/full/reg_info.cc + encumbered/cpu/full/rob_station.cc + encumbered/cpu/full/spec_memory.cc + encumbered/cpu/full/spec_state.cc + encumbered/cpu/full/storebuffer.cc + encumbered/cpu/full/writeback.cc + encumbered/cpu/full/iq/iq_station.cc + encumbered/cpu/full/iq/iqueue.cc + encumbered/cpu/full/iq/segmented/chain_info.cc + encumbered/cpu/full/iq/segmented/chain_wire.cc + encumbered/cpu/full/iq/segmented/iq_seg.cc + encumbered/cpu/full/iq/segmented/iq_segmented.cc + encumbered/cpu/full/iq/segmented/seg_chain.cc + encumbered/cpu/full/iq/seznec/iq_seznec.cc + encumbered/cpu/full/iq/standard/iq_standard.cc + ''') + +trace_reader_sources = Split(''' + cpu/trace/reader/mem_trace_reader.cc + cpu/trace/reader/ibm_reader.cc + cpu/trace/reader/itx_reader.cc + cpu/trace/reader/m5_reader.cc + cpu/trace/opt_cpu.cc + cpu/trace/trace_cpu.cc + ''') + + + +# MySql sources +mysql_sources = Split(''' + base/mysql.cc + base/stats/mysql.cc + ''') + +# Full-system sources +full_system_sources = Split(''' + base/crc.cc + base/inet.cc + base/remote_gdb.cc + + cpu/intr_control.cc + cpu/profile.cc + + dev/alpha_console.cc + dev/baddev.cc + dev/disk_image.cc + dev/etherbus.cc + dev/etherdump.cc + dev/etherint.cc + dev/etherlink.cc + dev/etherpkt.cc + dev/ethertap.cc + dev/ide_ctrl.cc + dev/ide_disk.cc + dev/io_device.cc + dev/isa_fake.cc + dev/ns_gige.cc + dev/pciconfigall.cc + dev/pcidev.cc + dev/pcifake.cc + dev/pktfifo.cc + dev/platform.cc + dev/simconsole.cc + dev/simple_disk.cc + dev/sinic.cc + dev/tsunami.cc + dev/tsunami_cchip.cc + dev/tsunami_io.cc + dev/tsunami_fake.cc + dev/tsunami_pchip.cc + + dev/uart.cc + dev/uart8250.cc + - kern/kernel_binning.cc + kern/kernel_stats.cc + kern/system_events.cc + kern/linux/events.cc + kern/linux/linux_syscalls.cc + kern/linux/printk.cc + + mem/vport.cc + + sim/pseudo_inst.cc + ''') + + +if env['TARGET_ISA'] == 'alpha': + full_system_sources += Split(''' + kern/tru64/dump_mbuf.cc + kern/tru64/printf.cc + kern/tru64/tru64_events.cc + kern/tru64/tru64_syscalls.cc + ''') + +# turbolaser encumbered sources +turbolaser_sources = Split(''' + encumbered/dev/dma.cc + encumbered/dev/etherdev.cc + encumbered/dev/scsi.cc + encumbered/dev/scsi_ctrl.cc + encumbered/dev/scsi_disk.cc + encumbered/dev/scsi_none.cc + encumbered/dev/tlaser_clock.cc + encumbered/dev/tlaser_ipi.cc + encumbered/dev/tlaser_mbox.cc + encumbered/dev/tlaser_mc146818.cc + encumbered/dev/tlaser_node.cc + encumbered/dev/tlaser_pcia.cc + encumbered/dev/tlaser_pcidev.cc + encumbered/dev/tlaser_serial.cc + encumbered/dev/turbolaser.cc + encumbered/dev/uart8530.cc + ''') + +# Syscall emulation (non-full-system) sources +syscall_emulation_sources = Split(''' + mem/translating_port.cc + mem/page_table.cc + sim/process.cc + sim/syscall_emul.cc + ''') + +#if env['TARGET_ISA'] == 'alpha': +# syscall_emulation_sources += Split(''' +# kern/tru64/tru64.cc +# ''') + +alpha_eio_sources = Split(''' + encumbered/eio/exolex.cc + encumbered/eio/libexo.cc + encumbered/eio/eio.cc + ''') + +if env['TARGET_ISA'] == 'ALPHA_ISA': + syscall_emulation_sources += alpha_eio_sources + +memtest_sources = Split(''' + cpu/memtest/memtest.cc + ''') + +# Include file paths are rooted in this directory. SCons will +# automatically expand '.' to refer to both the source directory and +# the corresponding build directory to pick up generated include +# files. +env.Append(CPPPATH=Dir('.')) + +# Add a flag defining what THE_ISA should be for all compilation +env.Append(CPPDEFINES=[('THE_ISA','%s_ISA' % env['TARGET_ISA'].upper())]) + +arch_sources = SConscript('arch/SConscript', exports = 'env') + +cpu_sources = SConscript('cpu/SConscript', exports = 'env') + +# This is outside of cpu/SConscript since the source directory isn't +# underneath 'cpu'. +if 'FullCPU' in env['CPU_MODELS']: + cpu_sources += full_cpu_sources + +# Set up complete list of sources based on configuration. +sources = base_sources + arch_sources + cpu_sources + +if env['FULL_SYSTEM']: + sources += full_system_sources + if env['ALPHA_TLASER']: + sources += turbolaser_sources +else: + sources += syscall_emulation_sources + +if env['USE_MYSQL']: + sources += mysql_sources + +for opt in env.ExportOptions: + env.ConfigFile(opt) + +################################################### +# +# Special build rules. +# +################################################### + +# base/traceflags.{cc,hh} are generated from base/traceflags.py. +# $TARGET.base will expand to "/base/traceflags". +env.Command(Split('base/traceflags.hh base/traceflags.cc'), + 'base/traceflags.py', + 'python $SOURCE $TARGET.base') + +SConscript('python/SConscript', exports = ['env']) + +# This function adds the specified sources to the given build +# environment, and returns a list of all the corresponding SCons +# Object nodes (including an extra one for date.cc). We explicitly +# add the Object nodes so we can set up special dependencies for +# date.cc. +def make_objs(sources, env): + objs = [env.Object(s) for s in sources] + # make date.cc depend on all other objects so it always gets + # recompiled whenever anything else does + date_obj = env.Object('base/date.cc') + env.Depends(date_obj, objs) + objs.append(date_obj) + return objs + +################################################### +# +# Define binaries. Each different build type (debug, opt, etc.) gets +# a slightly different build environment. +# +################################################### + +# List of constructed environments to pass back to SConstruct +envList = [] + +# Function to create a new build environment as clone of current +# environment 'env' with modified object suffix and optional stripped +# binary. Additional keyword arguments are appended to corresponding +# build environment vars. +def makeEnv(label, objsfx, strip = False, **kwargs): + newEnv = env.Copy(OBJSUFFIX=objsfx) + newEnv.Label = label + newEnv.Append(**kwargs) + exe = 'm5.' + label # final executable + bin = exe + '.bin' # executable w/o appended Python zip archive + newEnv.Program(bin, make_objs(sources, newEnv)) + if strip: + stripped_bin = bin + '.stripped' + newEnv.Command(stripped_bin, bin, 'strip $SOURCE -o $TARGET') + bin = stripped_bin + targets = newEnv.Concat(exe, [bin, 'python/m5py.zip']) + newEnv.M5Binary = targets[0] + envList.append(newEnv) + +# Debug binary +makeEnv('debug', '.do', + CCFLAGS = Split('-g3 -gdwarf-2 -O0'), + CPPDEFINES = 'DEBUG') + +# Optimized binary +makeEnv('opt', '.o', + CCFLAGS = Split('-g -O3')) + +# "Fast" binary +makeEnv('fast', '.fo', strip = True, + CCFLAGS = Split('-O3'), + CPPDEFINES = 'NDEBUG') + +# Profiled binary +makeEnv('prof', '.po', + CCFLAGS = Split('-O3 -g -pg'), + LINKFLAGS = '-pg') + +Return('envList') diff --cc src/arch/alpha/freebsd/system.cc index 91f8b5af1,000000000..7cf68e0db mode 100644,000000..100644 --- a/src/arch/alpha/freebsd/system.cc +++ b/src/arch/alpha/freebsd/system.cc @@@ -1,158 -1,0 +1,148 @@@ +/* + * Copyright (c) 2004-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Ben Nash + */ + +/** + * @file + * Modifications for the FreeBSD kernel. + * Based on kern/linux/linux_system.cc. + * + */ + +#include "arch/alpha/system.hh" +#include "arch/alpha/freebsd/system.hh" +#include "base/loader/symtab.hh" +#include "cpu/thread_context.hh" +#include "mem/physical.hh" +#include "mem/port.hh" +#include "arch/isa_traits.hh" +#include "sim/builder.hh" +#include "sim/byteswap.hh" +#include "arch/vtophys.hh" + +#define TIMER_FREQUENCY 1193180 + +using namespace std; +using namespace AlphaISA; + +FreebsdAlphaSystem::FreebsdAlphaSystem(Params *p) + : AlphaSystem(p) +{ + /** + * Any time DELAY is called just skip the function. + * Shouldn't we actually emulate the delay? + */ + skipDelayEvent = addKernelFuncEvent("DELAY"); + skipCalibrateClocks = + addKernelFuncEvent("calibrate_clocks"); +} + + +FreebsdAlphaSystem::~FreebsdAlphaSystem() +{ + delete skipDelayEvent; + delete skipCalibrateClocks; +} + + +void +FreebsdAlphaSystem::doCalibrateClocks(ThreadContext *tc) +{ + Addr ppc_vaddr = 0; + Addr timer_vaddr = 0; + + ppc_vaddr = (Addr)tc->readIntReg(ArgumentReg1); + timer_vaddr = (Addr)tc->readIntReg(ArgumentReg2); + + virtPort.write(ppc_vaddr, (uint32_t)Clock::Frequency); + virtPort.write(timer_vaddr, (uint32_t)TIMER_FREQUENCY); +} + + +void +FreebsdAlphaSystem::SkipCalibrateClocksEvent::process(ThreadContext *tc) +{ + SkipFuncEvent::process(tc); + ((FreebsdAlphaSystem *)tc->getSystemPtr())->doCalibrateClocks(tc); +} + + +BEGIN_DECLARE_SIM_OBJECT_PARAMS(FreebsdAlphaSystem) + + Param boot_cpu_frequency; + SimObjectParam physmem; + + Param kernel; + Param console; + Param pal; + + Param boot_osflags; + Param readfile; + Param init_param; + + Param system_type; + Param system_rev; + - Param bin; - VectorParam binned_fns; - Param bin_int; - +END_DECLARE_SIM_OBJECT_PARAMS(FreebsdAlphaSystem) + +BEGIN_INIT_SIM_OBJECT_PARAMS(FreebsdAlphaSystem) + + INIT_PARAM(boot_cpu_frequency, "Frequency of the boot CPU"), + INIT_PARAM(physmem, "phsyical memory"), + INIT_PARAM(kernel, "file that contains the kernel code"), + INIT_PARAM(console, "file that contains the console code"), + INIT_PARAM(pal, "file that contains palcode"), + INIT_PARAM_DFLT(boot_osflags, "flags to pass to the kernel during boot", + "a"), + INIT_PARAM_DFLT(readfile, "file to read startup script from", ""), + INIT_PARAM_DFLT(init_param, "numerical value to pass into simulator", 0), + INIT_PARAM_DFLT(system_type, "Type of system we are emulating", 34), - INIT_PARAM_DFLT(system_rev, "Revision of system we are emulating", 1<<10), - INIT_PARAM_DFLT(bin, "is this system to be binned", false), - INIT_PARAM(binned_fns, "functions to be broken down and binned"), - INIT_PARAM_DFLT(bin_int, "is interrupt code binned seperately?", true) ++ INIT_PARAM_DFLT(system_rev, "Revision of system we are emulating", 1<<10) + +END_INIT_SIM_OBJECT_PARAMS(FreebsdAlphaSystem) + +CREATE_SIM_OBJECT(FreebsdAlphaSystem) +{ + AlphaSystem::Params *p = new AlphaSystem::Params; + p->name = getInstanceName(); + p->boot_cpu_frequency = boot_cpu_frequency; + p->physmem = physmem; + p->kernel_path = kernel; + p->console_path = console; + p->palcode = pal; + p->boot_osflags = boot_osflags; + p->init_param = init_param; + p->readfile = readfile; + p->system_type = system_type; + p->system_rev = system_rev; - p->bin = bin; - p->binned_fns = binned_fns; - p->bin_int = bin_int; + return new FreebsdAlphaSystem(p); +} + +REGISTER_SIM_OBJECT("FreebsdAlphaSystem", FreebsdAlphaSystem) + diff --cc src/arch/alpha/linux/system.cc index 3e061bba8,000000000..bb35f046d mode 100644,000000..100644 --- a/src/arch/alpha/linux/system.cc +++ b/src/arch/alpha/linux/system.cc @@@ -1,273 -1,0 +1,245 @@@ +/* + * Copyright (c) 2004-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Ali Saidi + * Lisa Hsu + * Nathan Binkert + * Steve Reinhardt + */ + +/** + * @file + * This code loads the linux kernel, console, pal and patches certain + * functions. The symbol tables are loaded so that traces can show + * the executing function and we can skip functions. Various delay + * loops are skipped and their final values manually computed to speed + * up boot time. + */ + +#include "arch/arguments.hh" +#include "arch/vtophys.hh" +#include "arch/alpha/linux/system.hh" +#include "arch/alpha/linux/threadinfo.hh" +#include "arch/alpha/system.hh" +#include "base/loader/symtab.hh" +#include "cpu/thread_context.hh" +#include "cpu/base.hh" +#include "dev/platform.hh" +#include "kern/linux/printk.hh" +#include "kern/linux/events.hh" +#include "mem/physical.hh" +#include "mem/port.hh" +#include "sim/builder.hh" +#include "sim/byteswap.hh" + +using namespace std; +using namespace AlphaISA; +using namespace Linux; + +LinuxAlphaSystem::LinuxAlphaSystem(Params *p) + : AlphaSystem(p) +{ + Addr addr = 0; + + /** + * The symbol swapper_pg_dir marks the beginning of the kernel and + * the location of bootloader passed arguments + */ + if (!kernelSymtab->findAddress("swapper_pg_dir", KernelStart)) { + panic("Could not determine start location of kernel"); + } + + /** + * Since we aren't using a bootloader, we have to copy the + * kernel arguments directly into the kernel's memory. + */ + virtPort.writeBlob(CommandLine(), (uint8_t*)params()->boot_osflags.c_str(), + params()->boot_osflags.length()+1); + + /** + * find the address of the est_cycle_freq variable and insert it + * so we don't through the lengthly process of trying to + * calculated it by using the PIT, RTC, etc. + */ + if (kernelSymtab->findAddress("est_cycle_freq", addr)) + virtPort.write(addr, (uint64_t)(Clock::Frequency / + p->boot_cpu_frequency)); + + + /** + * EV5 only supports 127 ASNs so we are going to tell the kernel that the + * paritiuclar EV6 we have only supports 127 asns. + * @todo At some point we should change ev5.hh and the palcode to support + * 255 ASNs. + */ + if (kernelSymtab->findAddress("dp264_mv", addr)) + virtPort.write(addr + 0x18, LittleEndianGuest::htog((uint32_t)127)); + else + panic("could not find dp264_mv\n"); + +#ifndef NDEBUG + kernelPanicEvent = addKernelFuncEvent("panic"); + if (!kernelPanicEvent) + panic("could not find kernel symbol \'panic\'"); + +#if 0 + kernelDieEvent = addKernelFuncEvent("die_if_kernel"); + if (!kernelDieEvent) + panic("could not find kernel symbol \'die_if_kernel\'"); +#endif + +#endif + + /** + * Any time ide_delay_50ms, calibarte_delay or + * determine_cpu_caches is called just skip the + * function. Currently determine_cpu_caches only is used put + * information in proc, however if that changes in the future we + * will have to fill in the cache size variables appropriately. + */ + + skipIdeDelay50msEvent = + addKernelFuncEvent("ide_delay_50ms"); + skipDelayLoopEvent = + addKernelFuncEvent("calibrate_delay"); + skipCacheProbeEvent = + addKernelFuncEvent("determine_cpu_caches"); + debugPrintkEvent = addKernelFuncEvent("dprintk"); + idleStartEvent = addKernelFuncEvent("cpu_idle"); + + if (kernelSymtab->findAddress("alpha_switch_to", addr) && DTRACE(Thread)) { + printThreadEvent = new PrintThreadInfo(&pcEventQueue, "threadinfo", + addr + sizeof(MachInst) * 6); + } else { + printThreadEvent = NULL; + } - - if (params()->bin_int) { - intStartEvent = addPalFuncEvent("sys_int_21"); - if (!intStartEvent) - panic("could not find symbol: sys_int_21\n"); - - intEndEvent = addPalFuncEvent("rti_to_kern"); - if (!intEndEvent) - panic("could not find symbol: rti_to_kern\n"); - - intEndEvent2 = addPalFuncEvent("rti_to_user"); - if (!intEndEvent2) - panic("could not find symbol: rti_to_user\n"); - - intEndEvent3 = addKernelFuncEvent("do_softirq"); - if (!intEndEvent3) - panic("could not find symbol: do_softirq\n"); - } +} + +LinuxAlphaSystem::~LinuxAlphaSystem() +{ +#ifndef NDEBUG + delete kernelPanicEvent; +#endif + delete skipIdeDelay50msEvent; + delete skipDelayLoopEvent; + delete skipCacheProbeEvent; + delete debugPrintkEvent; + delete idleStartEvent; + delete printThreadEvent; + delete intStartEvent; + delete intEndEvent; + delete intEndEvent2; +} + + +void +LinuxAlphaSystem::setDelayLoop(ThreadContext *tc) +{ + Addr addr = 0; + if (kernelSymtab->findAddress("loops_per_jiffy", addr)) { + Tick cpuFreq = tc->getCpuPtr()->frequency(); + Tick intrFreq = platform->intrFrequency(); + VirtualPort *vp; + + vp = tc->getVirtPort(); + vp->writeHtoG(addr, (uint32_t)((cpuFreq / intrFreq) * 0.9988)); + tc->delVirtPort(vp); + } +} + + +void +LinuxAlphaSystem::SkipDelayLoopEvent::process(ThreadContext *tc) +{ + SkipFuncEvent::process(tc); + // calculate and set loops_per_jiffy + ((LinuxAlphaSystem *)tc->getSystemPtr())->setDelayLoop(tc); +} + +void +LinuxAlphaSystem::PrintThreadInfo::process(ThreadContext *tc) +{ + Linux::ThreadInfo ti(tc); + + DPRINTF(Thread, "Currently Executing Thread %s, pid %d, started at: %d\n", + ti.curTaskName(), ti.curTaskPID(), ti.curTaskStart()); +} + + +BEGIN_DECLARE_SIM_OBJECT_PARAMS(LinuxAlphaSystem) + + Param boot_cpu_frequency; + SimObjectParam physmem; + + Param kernel; + Param console; + Param pal; + + Param boot_osflags; + Param readfile; + Param init_param; + + Param system_type; + Param system_rev; + - Param bin; - VectorParam binned_fns; - Param bin_int; - +END_DECLARE_SIM_OBJECT_PARAMS(LinuxAlphaSystem) + +BEGIN_INIT_SIM_OBJECT_PARAMS(LinuxAlphaSystem) + + INIT_PARAM(boot_cpu_frequency, "Frequency of the boot CPU"), + INIT_PARAM(physmem, "phsyical memory"), + INIT_PARAM(kernel, "file that contains the kernel code"), + INIT_PARAM(console, "file that contains the console code"), + INIT_PARAM(pal, "file that contains palcode"), + INIT_PARAM_DFLT(boot_osflags, "flags to pass to the kernel during boot", + "a"), + INIT_PARAM_DFLT(readfile, "file to read startup script from", ""), + INIT_PARAM_DFLT(init_param, "numerical value to pass into simulator", 0), + INIT_PARAM_DFLT(system_type, "Type of system we are emulating", 34), - INIT_PARAM_DFLT(system_rev, "Revision of system we are emulating", 1<<10), - INIT_PARAM_DFLT(bin, "is this system to be binned", false), - INIT_PARAM(binned_fns, "functions to be broken down and binned"), - INIT_PARAM_DFLT(bin_int, "is interrupt code binned seperately?", true) ++ INIT_PARAM_DFLT(system_rev, "Revision of system we are emulating", 1<<10) + +END_INIT_SIM_OBJECT_PARAMS(LinuxAlphaSystem) + +CREATE_SIM_OBJECT(LinuxAlphaSystem) +{ + AlphaSystem::Params *p = new AlphaSystem::Params; + p->name = getInstanceName(); + p->boot_cpu_frequency = boot_cpu_frequency; + p->physmem = physmem; + p->kernel_path = kernel; + p->console_path = console; + p->palcode = pal; + p->boot_osflags = boot_osflags; + p->init_param = init_param; + p->readfile = readfile; + p->system_type = system_type; + p->system_rev = system_rev; - p->bin = bin; - p->binned_fns = binned_fns; - p->bin_int = bin_int; + return new LinuxAlphaSystem(p); +} + +REGISTER_SIM_OBJECT("LinuxAlphaSystem", LinuxAlphaSystem) + diff --cc src/arch/alpha/linux/system.hh index c03586ac5,000000000..6921ba820 mode 100644,000000..100644 --- a/src/arch/alpha/linux/system.hh +++ b/src/arch/alpha/linux/system.hh @@@ -1,149 -1,0 +1,137 @@@ +/* + * Copyright (c) 2004-2006 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Ali Saidi + * Lisa Hsu + * Nathan Binkert + */ + +#ifndef __ARCH_ALPHA_LINUX_SYSTEM_HH__ +#define __ARCH_ALPHA_LINUX_SYSTEM_HH__ + +class ThreadContext; + +class BreakPCEvent; +class IdleStartEvent; + +#include "arch/alpha/system.hh" +#include "kern/linux/events.hh" + +using namespace AlphaISA; +using namespace Linux; + +/** - * This class contains linux specific system code (Loading, Events, Binning). ++ * This class contains linux specific system code (Loading, Events). + * It points to objects that are the system binaries to load and patches them + * appropriately to work in simulator. + */ +class LinuxAlphaSystem : public AlphaSystem +{ + private: + class SkipDelayLoopEvent : public SkipFuncEvent + { + public: + SkipDelayLoopEvent(PCEventQueue *q, const std::string &desc, Addr addr) + : SkipFuncEvent(q, desc, addr) {} + virtual void process(ThreadContext *tc); + }; + + class PrintThreadInfo : public PCEvent + { + public: + PrintThreadInfo(PCEventQueue *q, const std::string &desc, Addr addr) + : PCEvent(q, desc, addr) {} + virtual void process(ThreadContext *tc); + }; + + + /** + * Addresses defining where the kernel bootloader places various + * elements. Details found in include/asm-alpha/system.h + */ + Addr KernelStart; // Lookup the symbol swapper_pg_dir + + public: + Addr InitStack() const { return KernelStart + 0x02000; } + Addr EmptyPGT() const { return KernelStart + 0x04000; } + Addr EmptyPGE() const { return KernelStart + 0x08000; } + Addr ZeroPGE() const { return KernelStart + 0x0A000; } + Addr StartAddr() const { return KernelStart + 0x10000; } + + Addr Param() const { return ZeroPGE() + 0x0; } + Addr CommandLine() const { return Param() + 0x0; } + Addr InitrdStart() const { return Param() + 0x100; } + Addr InitrdSize() const { return Param() + 0x108; } + static const int CommandLineSize = 256; + + private: +#ifndef NDEBUG + /** Event to halt the simulator if the kernel calls panic() */ + BreakPCEvent *kernelPanicEvent; + + /** Event to halt the simulator if the kernel calls die_if_kernel */ + BreakPCEvent *kernelDieEvent; +#endif + + /** + * Event to skip determine_cpu_caches() because we don't support + * the IPRs that the code can access to figure out cache sizes + */ + SkipFuncEvent *skipCacheProbeEvent; + + /** PC based event to skip the ide_delay_50ms() call */ + SkipFuncEvent *skipIdeDelay50msEvent; + + /** + * PC based event to skip the dprink() call and emulate its + * functionality + */ + DebugPrintkEvent *debugPrintkEvent; + + /** + * Skip calculate_delay_loop() rather than waiting for this to be + * calculated + */ + SkipDelayLoopEvent *skipDelayLoopEvent; + + /** + * Event to print information about thread switches if the trace flag + * Thread is set + */ + PrintThreadInfo *printThreadEvent; + - /** - * Event to bin Interrupts seperately from kernel code - */ - InterruptStartEvent *intStartEvent; - - /** - * Event to bin Interrupts seperately from kernel code - */ - InterruptEndEvent *intEndEvent; - InterruptEndEvent *intEndEvent2; - InterruptEndEvent *intEndEvent3; - + /** Grab the PCBB of the idle process when it starts */ + IdleStartEvent *idleStartEvent; + + public: + LinuxAlphaSystem(Params *p); + ~LinuxAlphaSystem(); + + void setDelayLoop(ThreadContext *tc); +}; + +#endif // __ARCH_ALPHA_LINUX_SYSTEM_HH__ diff --cc src/arch/alpha/system.cc index a68e440b0,000000000..3aaba7d58 mode 100644,000000..100644 --- a/src/arch/alpha/system.cc +++ b/src/arch/alpha/system.cc @@@ -1,282 -1,0 +1,272 @@@ +/* + * Copyright (c) 2002-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Ali Saidi + */ + +#include "arch/alpha/ev5.hh" +#include "arch/alpha/system.hh" +#include "arch/vtophys.hh" +#include "base/remote_gdb.hh" +#include "base/loader/object_file.hh" +#include "base/loader/symtab.hh" +#include "base/trace.hh" +#include "mem/physical.hh" +#include "sim/byteswap.hh" +#include "sim/builder.hh" + + +using namespace LittleEndianGuest; + +AlphaSystem::AlphaSystem(Params *p) + : System(p) +{ + consoleSymtab = new SymbolTable; + palSymtab = new SymbolTable; + + + /** + * Load the pal, and console code into memory + */ + // Load Console Code + console = createObjectFile(params()->console_path); + if (console == NULL) + fatal("Could not load console file %s", params()->console_path); + + // Load pal file + pal = createObjectFile(params()->palcode); + if (pal == NULL) + fatal("Could not load PALcode file %s", params()->palcode); + + + // Load program sections into memory + pal->loadSections(&functionalPort, AlphaISA::LoadAddrMask); + console->loadSections(&functionalPort, AlphaISA::LoadAddrMask); + + // load symbols + if (!console->loadGlobalSymbols(consoleSymtab)) + panic("could not load console symbols\n"); + + if (!pal->loadGlobalSymbols(palSymtab)) + panic("could not load pal symbols\n"); + + if (!pal->loadLocalSymbols(palSymtab)) + panic("could not load pal symbols\n"); + + if (!console->loadGlobalSymbols(debugSymbolTable)) + panic("could not load console symbols\n"); + + if (!pal->loadGlobalSymbols(debugSymbolTable)) + panic("could not load pal symbols\n"); + + if (!pal->loadLocalSymbols(debugSymbolTable)) + panic("could not load pal symbols\n"); + + Addr addr = 0; +#ifndef NDEBUG + consolePanicEvent = addConsoleFuncEvent("panic"); +#endif + + /** + * Copy the osflags (kernel arguments) into the consoles + * memory. (Presently Linux does not use the console service + * routine to get these command line arguments, but Tru64 and + * others do.) + */ + if (consoleSymtab->findAddress("env_booted_osflags", addr)) { + virtPort.writeBlob(addr, (uint8_t*)params()->boot_osflags.c_str(), + strlen(params()->boot_osflags.c_str())); + } + + /** + * Set the hardware reset parameter block system type and revision + * information to Tsunami. + */ + if (consoleSymtab->findAddress("m5_rpb", addr)) { + uint64_t data; + data = htog(params()->system_type); + virtPort.write(addr+0x50, data); + data = htog(params()->system_rev); + virtPort.write(addr+0x58, data); + } else + panic("could not find hwrpb\n"); + +} + +AlphaSystem::~AlphaSystem() +{ + delete consoleSymtab; + delete console; + delete pal; +#ifdef DEBUG + delete consolePanicEvent; +#endif +} + +/** + * This function fixes up addresses that are used to match PCs for + * hooking simulator events on to target function executions. + * + * Alpha binaries may have multiple global offset table (GOT) + * sections. A function that uses the GOT starts with a + * two-instruction prolog which sets the global pointer (gp == r29) to + * the appropriate GOT section. The proper gp value is calculated + * based on the function address, which must be passed by the caller + * in the procedure value register (pv aka t12 == r27). This sequence + * looks like the following: + * + * opcode Ra Rb offset + * ldah gp,X(pv) 09 29 27 X + * lda gp,Y(gp) 08 29 29 Y + * + * for some constant offsets X and Y. The catch is that the linker + * (or maybe even the compiler, I'm not sure) may recognize that the + * caller and callee are using the same GOT section, making this + * prolog redundant, and modify the call target to skip these + * instructions. If we check for execution of the first instruction + * of a function (the one the symbol points to) to detect when to skip + * it, we'll miss all these modified calls. It might work to + * unconditionally check for the third instruction, but not all + * functions have this prolog, and there's some chance that those + * first two instructions could have undesired consequences. So we do + * the Right Thing and pattern-match the first two instructions of the + * function to decide where to patch. + * + * Eventually this code should be moved into an ISA-specific file. + */ +Addr +AlphaSystem::fixFuncEventAddr(Addr addr) +{ + // mask for just the opcode, Ra, and Rb fields (not the offset) + const uint32_t inst_mask = 0xffff0000; + // ldah gp,X(pv): opcode 9, Ra = 29, Rb = 27 + const uint32_t gp_ldah_pattern = (9 << 26) | (29 << 21) | (27 << 16); + // lda gp,Y(gp): opcode 8, Ra = 29, rb = 29 + const uint32_t gp_lda_pattern = (8 << 26) | (29 << 21) | (29 << 16); + + uint32_t i1 = virtPort.read(addr); + uint32_t i2 = virtPort.read(addr + sizeof(AlphaISA::MachInst)); + + if ((i1 & inst_mask) == gp_ldah_pattern && + (i2 & inst_mask) == gp_lda_pattern) { + Addr new_addr = addr + 2* sizeof(AlphaISA::MachInst); + DPRINTF(Loader, "fixFuncEventAddr: %p -> %p", addr, new_addr); + return new_addr; + } else { + return addr; + } +} + + +void +AlphaSystem::setAlphaAccess(Addr access) +{ + Addr addr = 0; + if (consoleSymtab->findAddress("m5AlphaAccess", addr)) { + virtPort.write(addr, htog(EV5::Phys2K0Seg(access))); + } else + panic("could not find m5AlphaAccess\n"); +} + +bool +AlphaSystem::breakpoint() +{ + return remoteGDB[0]->trap(ALPHA_KENTRY_INT); +} + +void +AlphaSystem::serialize(std::ostream &os) +{ + System::serialize(os); + consoleSymtab->serialize("console_symtab", os); + palSymtab->serialize("pal_symtab", os); +} + + +void +AlphaSystem::unserialize(Checkpoint *cp, const std::string §ion) +{ + System::unserialize(cp,section); + consoleSymtab->unserialize("console_symtab", cp, section); + palSymtab->unserialize("pal_symtab", cp, section); +} + + +BEGIN_DECLARE_SIM_OBJECT_PARAMS(AlphaSystem) + + Param boot_cpu_frequency; + SimObjectParam physmem; + + Param kernel; + Param console; + Param pal; + + Param boot_osflags; + Param readfile; + Param init_param; + + Param system_type; + Param system_rev; + - Param bin; - VectorParam binned_fns; - Param bin_int; - +END_DECLARE_SIM_OBJECT_PARAMS(AlphaSystem) + +BEGIN_INIT_SIM_OBJECT_PARAMS(AlphaSystem) + + INIT_PARAM(boot_cpu_frequency, "Frequency of the boot CPU"), + INIT_PARAM(physmem, "phsyical memory"), + INIT_PARAM(kernel, "file that contains the kernel code"), + INIT_PARAM(console, "file that contains the console code"), + INIT_PARAM(pal, "file that contains palcode"), + INIT_PARAM_DFLT(boot_osflags, "flags to pass to the kernel during boot", + "a"), + INIT_PARAM_DFLT(readfile, "file to read startup script from", ""), + INIT_PARAM_DFLT(init_param, "numerical value to pass into simulator", 0), + INIT_PARAM_DFLT(system_type, "Type of system we are emulating", 34), - INIT_PARAM_DFLT(system_rev, "Revision of system we are emulating", 1<<10), - INIT_PARAM_DFLT(bin, "is this system to be binned", false), - INIT_PARAM(binned_fns, "functions to be broken down and binned"), - INIT_PARAM_DFLT(bin_int, "is interrupt code binned seperately?", true) ++ INIT_PARAM_DFLT(system_rev, "Revision of system we are emulating", 1<<10) + +END_INIT_SIM_OBJECT_PARAMS(AlphaSystem) + +CREATE_SIM_OBJECT(AlphaSystem) +{ + AlphaSystem::Params *p = new AlphaSystem::Params; + p->name = getInstanceName(); + p->boot_cpu_frequency = boot_cpu_frequency; + p->physmem = physmem; + p->kernel_path = kernel; + p->console_path = console; + p->palcode = pal; + p->boot_osflags = boot_osflags; + p->init_param = init_param; + p->readfile = readfile; + p->system_type = system_type; + p->system_rev = system_rev; - p->bin = bin; - p->binned_fns = binned_fns; - p->bin_int = bin_int; + return new AlphaSystem(p); +} + +REGISTER_SIM_OBJECT("AlphaSystem", AlphaSystem) + + diff --cc src/arch/alpha/tru64/system.cc index 8d9a53273,000000000..6c0edc1ee mode 100644,000000..100644 --- a/src/arch/alpha/tru64/system.cc +++ b/src/arch/alpha/tru64/system.cc @@@ -1,154 -1,0 +1,146 @@@ +/* + * Copyright (c) 2003-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Nathan Binkert + * Lisa Hsu + */ + +#include "arch/alpha/tru64/system.hh" +#include "arch/isa_traits.hh" +#include "arch/vtophys.hh" +#include "base/loader/symtab.hh" +#include "base/trace.hh" +#include "cpu/base.hh" +#include "cpu/thread_context.hh" +#include "kern/tru64/tru64_events.hh" +#include "kern/system_events.hh" +#include "mem/physical.hh" +#include "mem/port.hh" +#include "sim/builder.hh" + +using namespace std; + +Tru64AlphaSystem::Tru64AlphaSystem(Tru64AlphaSystem::Params *p) + : AlphaSystem(p) +{ + Addr addr = 0; + if (kernelSymtab->findAddress("enable_async_printf", addr)) { + virtPort.write(addr, (uint32_t)0); + } + +#ifdef DEBUG + kernelPanicEvent = addKernelFuncEvent("panic"); + if (!kernelPanicEvent) + panic("could not find kernel symbol \'panic\'"); +#endif + + badaddrEvent = addKernelFuncEvent("badaddr"); + if (!badaddrEvent) + panic("could not find kernel symbol \'badaddr\'"); + + skipPowerStateEvent = + addKernelFuncEvent("tl_v48_capture_power_state"); + skipScavengeBootEvent = + addKernelFuncEvent("pmap_scavenge_boot"); + +#if TRACING_ON + printfEvent = addKernelFuncEvent("printf"); + debugPrintfEvent = addKernelFuncEvent("m5printf"); + debugPrintfrEvent = addKernelFuncEvent("m5printfr"); + dumpMbufEvent = addKernelFuncEvent("m5_dump_mbuf"); +#endif +} + +Tru64AlphaSystem::~Tru64AlphaSystem() +{ +#ifdef DEBUG + delete kernelPanicEvent; +#endif + delete badaddrEvent; + delete skipPowerStateEvent; + delete skipScavengeBootEvent; +#if TRACING_ON + delete printfEvent; + delete debugPrintfEvent; + delete debugPrintfrEvent; + delete dumpMbufEvent; +#endif +} + +BEGIN_DECLARE_SIM_OBJECT_PARAMS(Tru64AlphaSystem) + + Param boot_cpu_frequency; + SimObjectParam physmem; + + Param kernel; + Param console; + Param pal; + + Param boot_osflags; + Param readfile; + Param init_param; + + Param system_type; + Param system_rev; + - Param bin; - VectorParam binned_fns; - +END_DECLARE_SIM_OBJECT_PARAMS(Tru64AlphaSystem) + +BEGIN_INIT_SIM_OBJECT_PARAMS(Tru64AlphaSystem) + + INIT_PARAM(boot_cpu_frequency, "frequency of the boot cpu"), + INIT_PARAM(physmem, "phsyical memory"), + INIT_PARAM(kernel, "file that contains the kernel code"), + INIT_PARAM(console, "file that contains the console code"), + INIT_PARAM(pal, "file that contains palcode"), + INIT_PARAM_DFLT(boot_osflags, "flags to pass to the kernel during boot", + "a"), + INIT_PARAM_DFLT(readfile, "file to read startup script from", ""), + INIT_PARAM_DFLT(init_param, "numerical value to pass into simulator", 0), + INIT_PARAM_DFLT(system_type, "Type of system we are emulating", 12), - INIT_PARAM_DFLT(system_rev, "Revision of system we are emulating", 2<<1), - INIT_PARAM_DFLT(bin, "is this system to be binned", false), - INIT_PARAM(binned_fns, "functions to be broken down and binned") ++ INIT_PARAM_DFLT(system_rev, "Revision of system we are emulating", 2<<1) + +END_INIT_SIM_OBJECT_PARAMS(Tru64AlphaSystem) + +CREATE_SIM_OBJECT(Tru64AlphaSystem) +{ + AlphaSystem::Params *p = new AlphaSystem::Params; + p->name = getInstanceName(); + p->boot_cpu_frequency = boot_cpu_frequency; + p->physmem = physmem; + p->kernel_path = kernel; + p->console_path = console; + p->palcode = pal; + p->boot_osflags = boot_osflags; + p->init_param = init_param; + p->readfile = readfile; + p->system_type = system_type; + p->system_rev = system_rev; - p->bin = bin; - p->binned_fns = binned_fns; - p->bin_int = false; + + return new Tru64AlphaSystem(p); +} + +REGISTER_SIM_OBJECT("Tru64AlphaSystem", Tru64AlphaSystem) diff --cc src/base/statistics.cc index 03c6b5196,000000000..2acef83c5 mode 100644,000000..100644 --- a/src/base/statistics.cc +++ b/src/base/statistics.cc @@@ -1,358 -1,0 +1,292 @@@ +/* + * Copyright (c) 2003-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Nathan Binkert + */ + +#include +#include +#include +#include +#include + +#include "base/callback.hh" +#include "base/cprintf.hh" +#include "base/hostinfo.hh" +#include "base/misc.hh" +#include "base/statistics.hh" +#include "base/str.hh" +#include "base/time.hh" +#include "base/trace.hh" +#include "base/stats/statdb.hh" - #include "config/stats_binning.hh" + +using namespace std; + +namespace Stats { + +StatData * +DataAccess::find() const +{ + return Database::find(const_cast((const void *)this)); +} + +const StatData * +getStatData(const void *stat) +{ + return Database::find(const_cast(stat)); +} + +void +DataAccess::map(StatData *data) +{ + Database::regStat(this, data); +} + +StatData * +DataAccess::statData() +{ + StatData *ptr = find(); + assert(ptr); + return ptr; +} + +const StatData * +DataAccess::statData() const +{ + const StatData *ptr = find(); + assert(ptr); + return ptr; +} + +void +DataAccess::setInit() +{ + statData()->flags |= init; +} + +void +DataAccess::setPrint() +{ + Database::regPrint(this); +} + +StatData::StatData() + : flags(none), precision(-1), prereq(0) +{ + static int count = 0; + id = count++; +} + +StatData::~StatData() +{ +} + +bool +StatData::less(StatData *stat1, StatData *stat2) +{ + const string &name1 = stat1->name; + const string &name2 = stat2->name; + + vector v1; + vector v2; + + tokenize(v1, name1, '.'); + tokenize(v2, name2, '.'); + + int last = min(v1.size(), v2.size()) - 1; + for (int i = 0; i < last; ++i) + if (v1[i] != v2[i]) + return v1[i] < v2[i]; + + // Special compare for last element. + if (v1[last] == v2[last]) + return v1.size() < v2.size(); + else + return v1[last] < v2[last]; + + return false; +} + +bool +StatData::baseCheck() const +{ + if (!(flags & init)) { +#ifdef DEBUG + cprintf("this is stat number %d\n", id); +#endif + panic("Not all stats have been initialized"); + return false; + } + + if ((flags & print) && name.empty()) { + panic("all printable stats must be named"); + return false; + } + + return true; +} + + +void +FormulaBase::result(VResult &vec) const +{ + if (root) + vec = root->result(); +} + +Result +FormulaBase::total() const +{ + return root ? root->total() : 0.0; +} + +size_t +FormulaBase::size() const +{ + if (!root) + return 0; + else + return root->size(); +} + - bool - FormulaBase::binned() const - { - return root && root->binned(); - } - +void +FormulaBase::reset() +{ +} + +bool +FormulaBase::zero() const +{ + VResult vec; + result(vec); + for (int i = 0; i < vec.size(); ++i) + if (vec[i] != 0.0) + return false; + return true; +} + +void +FormulaBase::update(StatData *) +{ +} + +string +FormulaBase::str() const +{ + return root ? root->str() : ""; +} + +Formula::Formula() +{ + setInit(); +} + +Formula::Formula(Temp r) +{ + root = r; + assert(size()); +} + +const Formula & +Formula::operator=(Temp r) +{ + assert(!root && "Can't change formulas"); + root = r; + assert(size()); + return *this; +} + +const Formula & +Formula::operator+=(Temp r) +{ + if (root) + root = NodePtr(new BinaryNode >(root, r)); + else + root = r; + assert(size()); + return *this; +} + - MainBin::MainBin(const string &name) - : _name(name), mem(NULL), memsize(-1) - { - Database::regBin(this, name); - } - - MainBin::~MainBin() - { - if (mem) - delete [] mem; - } - - char * - MainBin::memory(off_t off) - { - if (memsize == -1) - memsize = ceilPow2((size_t) offset()); - - if (!mem) { - mem = new char[memsize]; - memset(mem, 0, memsize); - } - - assert(offset() <= size()); - return mem + off; - } - +void +check() +{ + typedef Database::stat_list_t::iterator iter_t; + + iter_t i, end = Database::stats().end(); + for (i = Database::stats().begin(); i != end; ++i) { + StatData *data = *i; + assert(data); + if (!data->check() || !data->baseCheck()) + panic("stat check failed for %s\n", data->name); + } + + int j = 0; + for (i = Database::stats().begin(); i != end; ++i) { + StatData *data = *i; + if (!(data->flags & print)) + data->name = "__Stat" + to_string(j++); + } + + Database::stats().sort(StatData::less); + - #if STATS_BINNING - if (MainBin::curBin() == NULL) { - static MainBin mainBin("main bin"); - mainBin.activate(); - } - #endif - + 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 +reset() +{ - // 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(); ++ 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 +registerResetCallback(Callback *cb) +{ + resetQueue.add(cb); +} + +/* namespace Stats */ } diff --cc src/base/statistics.hh index 84a323071,000000000..59f219c07 mode 100644,000000..100644 --- a/src/base/statistics.hh +++ b/src/base/statistics.hh @@@ -1,2899 -1,0 +1,2887 @@@ +/* + * Copyright (c) 2003-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Nathan Binkert + * Erik Hallnor + */ + +/** @file + * Declaration of Statistics objects. + */ + +/** +* @todo +* +* Generalized N-dimensinal vector +* documentation +* key stats +* interval stats +* -- these both can use the same function that prints out a +* specific set of stats +* VectorStandardDeviation totals +* Document Namespaces +*/ +#ifndef __BASE_STATISTICS_HH__ +#define __BASE_STATISTICS_HH__ + +#include +#include +#include +#include +#include +#include +#include + +#include "base/cprintf.hh" +#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 "config/stats_binning.hh" +#include "sim/host.hh" + +class Callback; + +/** The current simulated cycle. */ +extern Tick curTick; + +/* A namespace for all of the Statistics */ +namespace Stats { + +/* Contains the statistic implementation details */ +////////////////////////////////////////////////////////////////////// +// +// Statistics Framework Base classes +// +////////////////////////////////////////////////////////////////////// +struct StatData +{ + /** The name of the stat. */ + std::string name; + /** The description of the stat. */ + std::string desc; + /** The formatting flags. */ + 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(); + - /** - * @return true if the stat is binned. - */ - virtual bool binned() const = 0; - + /** + * Reset the corresponding stat to the default state. + */ + virtual void reset() = 0; + + /** + * @return true if this stat has a value and satisfies its + * requirement as a prereq + */ + virtual bool zero() const = 0; + + /** + * Check that this stat has been set up properly and is ready for + * use + * @return true for success + */ + virtual bool check() const = 0; + 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. + * @param stat1 The first stat. + * @param stat2 The second stat. + * @return stat1's name is alphabetically before stat2's + */ + static bool less(StatData *stat1, StatData *stat2); +}; + +class ScalarData : public StatData +{ + public: + virtual Counter value() const = 0; + virtual Result result() const = 0; + virtual Result total() const = 0; + virtual void visit(Visit &visitor) { visitor.visit(*this); } +}; + +template +class ScalarStatData : public ScalarData +{ + protected: + Stat &s; + + public: + ScalarStatData(Stat &stat) : s(stat) {} + - virtual bool binned() const { return s.binned(); } + virtual bool check() const { return s.check(); } + 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(); } +}; + +struct VectorData : public StatData +{ + /** Names and descriptions of subfields. */ + mutable std::vector subnames; + mutable std::vector subdescs; + + virtual size_t size() const = 0; + 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(); + if (subnames.size() < s) + subnames.resize(s); + + if (subdescs.size() < s) + subdescs.resize(s); + } + } +}; + +template +class VectorStatData : public VectorData +{ + protected: + Stat &s; + mutable VCounter cvec; + mutable VResult rvec; + + public: + VectorStatData(Stat &stat) : s(stat) {} + - virtual bool binned() const { return s.binned(); } + virtual bool check() const { return s.check(); } + virtual bool zero() const { return s.zero(); } + virtual void reset() { s.reset(); } + + virtual size_t size() const { return s.size(); } + virtual VCounter &value() const + { + s.value(cvec); + return cvec; + } + virtual const VResult &result() const + { + s.result(rvec); + return rvec; + } + virtual Result total() const { return s.total(); } + virtual void visit(Visit &visitor) + { + update(); + s.update(this); + visitor.visit(*this); + } +}; + +struct DistDataData +{ + 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; +}; + +struct DistData : public StatData +{ + /** Local storage for the entry values, used for printing. */ + DistDataData data; +}; + +template +class DistStatData : public DistData +{ + protected: + Stat &s; + + public: + 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 visit(Visit &visitor) + { + s.update(this); + visitor.visit(*this); + } +}; + +struct VectorDistData : public StatData +{ + std::vector data; + + /** Names and descriptions of subfields. */ + mutable std::vector subnames; + mutable std::vector subdescs; + + /** Local storage for the entry values, used for printing. */ + mutable VResult rvec; + + virtual size_t size() const = 0; + void update() + { + int s = size(); + if (subnames.size() < s) + subnames.resize(s); + + if (subdescs.size() < s) + subdescs.resize(s); + } +}; + +template +class VectorDistStatData : public VectorDistData +{ + protected: + Stat &s; - typedef typename Stat::bin_t bin_t; + + public: + 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 visit(Visit &visitor) + { + update(); + s.update(this); + visitor.visit(*this); + } +}; + +struct Vector2dData : public StatData +{ + /** Names and descriptions of subfields. */ + std::vector subnames; + std::vector subdescs; + std::vector y_subnames; + + /** Local storage for the entry values, used for printing. */ + mutable VCounter cvec; + mutable int x; + mutable int y; + + void update() + { + if (subnames.size() < x) + subnames.resize(x); + } +}; + +template +class Vector2dStatData : public Vector2dData +{ + protected: + Stat &s; - typedef typename Stat::bin_t bin_t; + + public: + 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 visit(Visit &visitor) + { + update(); + s.update(this); + visitor.visit(*this); + } +}; + - +class DataAccess +{ + protected: + StatData *find() const; + void map(StatData *data); + + StatData *statData(); + const StatData *statData() const; + + void setInit(); + void setPrint(); +}; + +template class Data> +class Wrap : public Child +{ + protected: + Parent &self() { return *reinterpret_cast(this); } + + protected: + Data *statData() + { + StatData *__data = DataAccess::statData(); + Data *ptr = dynamic_cast *>(__data); + assert(ptr); + return ptr; + } + + public: + const Data *statData() const + { + const StatData *__data = DataAccess::statData(); + const Data *ptr = dynamic_cast *>(__data); + assert(ptr); + return ptr; + } + + protected: + /** + * Copy constructor, copies are not allowed. + */ + Wrap(const Wrap &stat); + /** + * Can't copy stats. + */ + void operator=(const Wrap &); + + public: + Wrap() + { + map(new Data(*this)); + } + + /** + * Set the name and marks this stat to print at the end of simulation. + * @param name The new name. + * @return A reference to this stat. + */ + Parent &name(const std::string &_name) + { + Data *data = this->statData(); + data->name = _name; + this->setPrint(); + return this->self(); + } + + /** + * Set the description and marks this stat to print at the end of + * simulation. + * @param desc The new description. + * @return A reference to this stat. + */ + Parent &desc(const std::string &_desc) + { + this->statData()->desc = _desc; + return this->self(); + } + + /** + * Set the precision and marks this stat to print at the end of simulation. + * @param p The new precision + * @return A reference to this stat. + */ + Parent &precision(int _precision) + { + this->statData()->precision = _precision; + return this->self(); + } + + /** + * Set the flags and marks this stat to print at the end of simulation. + * @param f The new flags. + * @return A reference to this stat. + */ + Parent &flags(StatFlags _flags) + { + this->statData()->flags |= _flags; + return this->self(); + } + + /** + * Set the prerequisite stat and marks this stat to print at the end of + * simulation. + * @param prereq The prerequisite stat. + * @return A reference to this stat. + */ + template + Parent &prereq(const Stat &prereq) + { + this->statData()->prereq = prereq.statData(); + return this->self(); + } +}; + +template class Data> +class WrapVec : public Wrap +{ + public: + // The following functions are specific to vectors. If you use them + // in a non vector context, you will get a nice compiler error! + + /** + * Set the subfield name for the given index, and marks this stat to print + * at the end of simulation. + * @param index The subfield index. + * @param name The new name of the subfield. + * @return A reference to this stat. + */ + Parent &subname(int index, const std::string &name) + { + std::vector &subn = this->statData()->subnames; + if (subn.size() <= index) + subn.resize(index + 1); + subn[index] = name; + return this->self(); + } + + /** + * Set the subfield description for the given index and marks this stat to + * print at the end of simulation. + * @param index The subfield index. + * @param desc The new description of the subfield + * @return A reference to this stat. + */ + Parent &subdesc(int index, const std::string &desc) + { + std::vector &subd = this->statData()->subdescs; + if (subd.size() <= index) + subd.resize(index + 1); + subd[index] = desc; + + return this->self(); + } + +}; + +template class Data> +class WrapVec2d : public WrapVec +{ + public: + /** + * @warning This makes the assumption that if you're gonna subnames a 2d + * vector, you're subnaming across all y + */ + Parent &ysubnames(const char **names) + { + Data *data = this->statData(); + data->y_subnames.resize(this->y); + for (int i = 0; i < this->y; ++i) + data->y_subnames[i] = names[i]; + return this->self(); + } + Parent &ysubname(int index, const std::string subname) + { + Data *data = this->statData(); + assert(index < this->y); + data->y_subnames.resize(this->y); + data->y_subnames[index] = subname.c_str(); + return this->self(); + } +}; + +////////////////////////////////////////////////////////////////////// +// +// Simple Statistics +// +////////////////////////////////////////////////////////////////////// + +/** + * Templatized storage and interface for a simple scalar stat. + */ +struct StatStor +{ + public: + /** The paramaters for this storage type, none for a scalar. */ + struct Params { }; + + private: + /** The statistic value. */ + Counter data; + + public: + /** + * Builds this storage element and calls the base constructor of the + * datatype. + */ + 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(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(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(Counter val, const Params &p) { data -= val; } + /** + * Return the value of this stat as its base type. + * @param p The params of this storage type. + * @return The value of this stat. + */ + Counter value(const Params &p) const { return data; } + /** + * Return the value of this stat as a result type. + * @param p The parameters of this storage type. + * @return The value of this stat. + */ + Result result(const Params &p) const { return (Result)data; } + /** + * Reset stat value to default + */ + void reset() { data = Counter(); } + + /** + * @return true if zero value + */ + bool zero() const { return data == Counter(); } +}; + +/** + * Templatized storage and interface to a per-cycle average stat. This keeps + * a current count and updates a total (count * cycles) when this count + * changes. This allows the quick calculation of a per cycle count of the item + * being watched. This is good for keeping track of residencies in structures + * among other things. - * @todo add lateny to the stat and fix binning. + */ +struct AvgStor +{ + public: + /** The paramaters for this storage type */ - struct Params - { - /** - * The current count. We stash this here because the current - * value is not a binned value. - */ - Counter current; - }; ++ struct Params { }; + + private: ++ /** The current count. */ ++ Counter current; + /** The total count for all cycles. */ + mutable Result total; + /** The cycle that current last changed. */ + mutable Tick last; + + public: + /** + * Build and initializes this stat storage. + */ - AvgStor(Params &p) : total(0), last(0) { p.current = Counter(); } ++ AvgStor(Params &p) : current(0), total(0), last(0) { } + + /** + * Set the current count to the one provided, update the total and last + * set values. + * @param val The new count. + * @param p The parameters for this storage. + */ + void set(Counter val, Params &p) { - total += p.current * (curTick - last); ++ total += current * (curTick - last); + last = curTick; - p.current = val; ++ current = val; + } + + /** + * Increment the current count by the provided value, calls set. + * @param val The amount to increment. + * @param p The parameters for this storage. + */ - void inc(Counter val, Params &p) { set(p.current + val, p); } ++ void inc(Counter val, Params &p) { set(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(Counter val, Params &p) { set(p.current - val, p); } ++ void dec(Counter val, Params &p) { set(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; } ++ Counter value(const Params &p) const { return current; } + + /** + * Return the current average. + * @param p The parameters for this storage. + * @return The current average. + */ + Result result(const Params &p) const + { - total += p.current * (curTick - last); ++ total += current * (curTick - last); + last = curTick; - return (Result)(total + p.current) / (Result)(curTick + 1); ++ return (Result)(total + current) / (Result)(curTick + 1); + } + + /** + * Reset stat value to default + */ + void reset() + { + total = 0; + last = curTick; + } + + /** + * @return true if zero value + */ + bool zero() const { return total == 0.0; } +}; + +/** + * Implementation of a scalar stat. The type of stat is determined by the - * Storage template. The storage for this stat is held within the Bin class. - * This allows for breaking down statistics across multiple bins easily. ++ * Storage template. + */ - template ++template +class ScalarBase : public DataAccess +{ + public: ++ typedef Stor Storage; ++ + /** Define the params of the storage class. */ - typedef typename Storage::Params params_t; - /** Define the bin type. */ - typedef typename Bin::template Bin bin_t; ++ typedef typename Storage::Params Params; + + protected: - /** The bin of this stat. */ - bin_t bin; ++ /** The storage of this stat. */ ++ char storage[sizeof(Storage)]; ++ + /** The parameters for this stat. */ - params_t params; ++ Params params; + + protected: + /** - * Retrieve the storage from the bin. - * @return The storage object for this stat. ++ * Retrieve the storage. ++ * @param index The vector index to access. ++ * @return The storage object at the given index. + */ - Storage *data() { return bin.data(params); } ++ Storage * ++ data() ++ { ++ return reinterpret_cast(storage); ++ } ++ + /** - * Retrieve a const pointer to the storage from the bin. - * @return A const pointer to the storage object for this stat. ++ * Retrieve a const pointer to the storage. ++ * 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 *data() const ++ const Storage * ++ data() const + { - bin_t *_bin = const_cast(&bin); - params_t *_params = const_cast(¶ms); - return _bin->data(*_params); ++ return reinterpret_cast(storage); ++ } ++ ++ void ++ doInit() ++ { ++ new (storage) Storage(params); ++ setInit(); + } + + public: + /** + * Return the current value of this stat as its base type. + * @return The current value. + */ + Counter value() const { return data()->value(params); } + + public: + /** + * Create and initialize this stat, register it with the database. + */ + ScalarBase() - { - bin.init(params); - } ++ { } + + public: + // Common operators for stats + /** + * Increment the stat by 1. This calls the associated storage object inc + * function. + */ + void operator++() { data()->inc(1, params); } + /** + * Decrement the stat by 1. This calls the associated storage object dec + * function. + */ + void operator--() { data()->dec(1, params); } + + /** Increment the stat by 1. */ + void operator++(int) { ++*this; } + /** Decrement the stat by 1. */ + void operator--(int) { --*this; } + + /** + * Set the data value to the given value. This calls the associated storage + * object set function. + * @param v The new value. + */ + template + void operator=(const U &v) { data()->set(v, params); } + + /** + * Increment the stat by the given value. This calls the associated + * storage object inc function. + * @param v The value to add. + */ + template + void operator+=(const U &v) { data()->inc(v, params); } + + /** + * Decrement the stat by the given value. This calls the associated + * storage object dec function. + * @param v The value to substract. + */ + template + void operator-=(const U &v) { data()->dec(v, params); } + + /** + * Return the number of elements, always 1 for a scalar. + * @return 1. + */ + size_t size() const { return 1; } - /** - * Return true if stat is binned. - *@return True is stat is binned. - */ - bool binned() const { return bin_t::binned; } + - bool check() const { return bin.initialized(); } ++ bool check() const { return true; } + + /** + * Reset stat value to default + */ - void reset() { bin.reset(); } ++ void reset() { data()->reset(); } + + Counter value() { return data()->value(params); } + + Result result() { return data()->result(params); } + + Result total() { return result(); } + + bool zero() { return result() == 0.0; } + +}; + +class ProxyData : public ScalarData +{ + public: + virtual void visit(Visit &visitor) { visitor.visit(*this); } - virtual bool binned() const { return false; } + virtual std::string str() const { return to_string(value()); } + virtual size_t size() const { return 1; } + virtual bool zero() const { return value() == 0; } + virtual bool check() const { return true; } + virtual void reset() { } +}; + +template +class ValueProxy : public ProxyData +{ + private: + T *scalar; + + public: + ValueProxy(T &val) : scalar(&val) {} + virtual Counter value() const { return *scalar; } + virtual Result result() const { return *scalar; } + virtual Result total() const { return *scalar; } +}; + +template +class FunctorProxy : public ProxyData +{ + private: + T *functor; + + public: + FunctorProxy(T &func) : functor(&func) {} + virtual Counter value() const { return (*functor)(); } + virtual Result result() const { return (*functor)(); } + virtual Result total() const { return (*functor)(); } +}; + +class ValueBase : public DataAccess +{ + private: + ProxyData *proxy; + + public: + ValueBase() : proxy(NULL) { } + ~ValueBase() { if (proxy) delete proxy; } + + template + void scalar(T &value) + { + proxy = new ValueProxy(value); + setInit(); + } + + template + void functor(T &func) + { + proxy = new FunctorProxy(func); + setInit(); + } + + Counter value() { return proxy->value(); } + Result result() const { return proxy->result(); } + Result total() const { return proxy->total(); }; + size_t size() const { return proxy->size(); } + - bool binned() const { return proxy->binned(); } + std::string str() const { return proxy->str(); } + bool zero() const { return proxy->zero(); } + bool check() const { return proxy != NULL; } + void reset() { } +}; + +////////////////////////////////////////////////////////////////////// +// +// Vector Statistics +// +////////////////////////////////////////////////////////////////////// - template - class ScalarProxy; - - /** - * Implementation of a vector of stats. The type of stat is determined by the - * Storage class. @sa ScalarBase - */ - template - class VectorBase : public DataAccess - { - public: - /** Define the params of the storage class. */ - typedef typename Storage::Params params_t; - /** Define the bin type. */ - typedef typename Bin::template VectorBin bin_t; - - protected: - /** The bin of this stat. */ - bin_t bin; - /** The parameters for this stat. */ - params_t params; - - protected: - /** - * Retrieve the storage from the bin for the given index. - * @param index The vector index to access. - * @return The storage object at the given index. - */ - 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 *data(int index) const - { - bin_t *_bin = const_cast(&bin); - params_t *_params = const_cast(¶ms); - return _bin->data(index, *_params); - } - - 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 result(VResult &vec) const - { - vec.resize(size()); - for (int i = 0; i < size(); ++i) - vec[i] = data(i)->result(params); - } - - /** - * @return True is stat is binned. - */ - bool binned() const { return bin_t::binned; } - - /** - * Return a total of all entries in this vector. - * @return The total of all vector entries. - */ - Result total() const { - Result total = 0.0; - for (int i = 0; i < size(); ++i) - total += data(i)->result(params); - return total; - } - - /** - * @return the number of elements in this vector. - */ - size_t size() const { return bin.size(); } - - bool zero() const - { - for (int i = 0; i < size(); ++i) - if (data(i)->zero()) - return true; - return false; - } - - bool check() const { return bin.initialized(); } - void reset() { bin.reset(); } - - public: - VectorBase() {} - - /** Friend this class with the associated scalar proxy. */ - friend class ScalarProxy; - - /** - * 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 operator[](int index); - - void update(StatData *data) {} - }; - - 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 ++template +class ScalarProxy +{ - public: - /** Define the params of the storage class. */ - typedef typename Storage::Params params_t; - /** Define the bin type. */ - typedef typename Bin::template VectorBin bin_t; - + private: - /** Pointer to the bin in the parent VectorBase. */ - bin_t *bin; - /** Pointer to the params in the parent VectorBase. */ - params_t *params; ++ /** Pointer to the parent Vector. */ ++ Stat *stat; ++ + /** The index to access in the parent VectorBase. */ + int index; - /** Keep a pointer to the original stat so was can get data */ - void *stat; - - protected: - /** - * Retrieve the storage from the bin. - * @return The storage from the bin for this stat. - */ - 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 *data() const - { - bin_t *_bin = const_cast(bin); - params_t *_params = const_cast(params); - return _bin->data(index, *_params); - } + + public: + /** + * Return the current value of this stat as its base type. + * @return The current value. + */ - Counter value() const { return data()->value(*params); } ++ Counter value() const { return stat->data(index)->value(stat->params); } + + /** + * Return the current value of this statas a result type. + * @return The current value. + */ - Result result() const { return data()->result(*params); } ++ Result result() const { return stat->data(index)->result(stat->params); } + + public: + /** + * Create and initialize this proxy, do not register it with the database. - * @param b The bin to use. + * @param p The params to use. + * @param i The index to access. + */ - ScalarProxy(bin_t &b, params_t &p, int i, void *s) - : bin(&b), params(&p), index(i), stat(s) {} ++ ScalarProxy(Stat *s, int i) ++ : stat(s), index(i) ++ { ++ assert(stat); ++ } ++ + /** + * Create a copy of the provided ScalarProxy. + * @param sp The proxy to copy. + */ + ScalarProxy(const ScalarProxy &sp) - : bin(sp.bin), params(sp.params), index(sp.index), stat(sp.stat) {} ++ : stat(sp.stat), index(sp.index) ++ {} ++ + /** + * Set this proxy equal to the provided one. + * @param sp The proxy to copy. + * @return A reference to this proxy. + */ + const ScalarProxy &operator=(const ScalarProxy &sp) { - bin = sp.bin; - params = sp.params; - index = sp.index; + stat = sp.stat; ++ index = sp.index; + return *this; + } + + public: + // Common operators for stats + /** + * Increment the stat by 1. This calls the associated storage object inc + * function. + */ - void operator++() { data()->inc(1, *params); } ++ void operator++() { stat->data(index)->inc(1, stat->params); } + /** + * Decrement the stat by 1. This calls the associated storage object dec + * function. + */ - void operator--() { data()->dec(1, *params); } ++ void operator--() { stat->data(index)->dec(1, stat->params); } + + /** Increment the stat by 1. */ + void operator++(int) { ++*this; } + /** Decrement the stat by 1. */ + void operator--(int) { --*this; } + + /** + * Set the data value to the given value. This calls the associated storage + * object set function. + * @param v The new value. + */ + template - void operator=(const U &v) { data()->set(v, *params); } ++ void operator=(const U &v) { stat->data(index)->set(v, stat->params); } + + /** + * Increment the stat by the given value. This calls the associated + * storage object inc function. + * @param v The value to add. + */ + template - void operator+=(const U &v) { data()->inc(v, *params); } ++ void operator+=(const U &v) { stat->data(index)->inc(v, stat->params); } + + /** + * Decrement the stat by the given value. This calls the associated + * storage object dec function. + * @param v The value to substract. + */ + template - void operator-=(const U &v) { data()->dec(v, *params); } ++ void operator-=(const U &v) { stat->data(index)->dec(v, stat->params); } + + /** + * Return the number of elements, always 1 for a scalar. + * @return 1. + */ + size_t size() const { return 1; } + - /** - * Return true if stat is binned. - *@return false since Proxies aren't printed/binned - */ - bool binned() const { return false; } - + /** + * This stat has no state. Nothing to reset + */ + void reset() { } + + public: - const StatData *statData() const { return getStatData(stat); } - std::string str() const ++ std::string ++ str() const + { - return csprintf("%s[%d]", this->statData()->name, index); ++ return csprintf("%s[%d]", stat->str(), index); + + } +}; + - template - inline ScalarProxy - VectorBase::operator[](int index) ++/** ++ * Implementation of a vector of stats. The type of stat is determined by the ++ * Storage class. @sa ScalarBase ++ */ ++template ++class VectorBase : public DataAccess +{ - assert (index >= 0 && index < size()); - return ScalarProxy(bin, params, index, this); - } ++ public: ++ typedef Stor Storage; ++ ++ /** Define the params of the storage class. */ ++ typedef typename Storage::Params Params; + - template - class VectorProxy; ++ /** Proxy type */ ++ typedef ScalarProxy > Proxy; + - template - class Vector2dBase : public DataAccess - { - public: - typedef typename Storage::Params params_t; - typedef typename Bin::template VectorBin bin_t; ++ friend class ScalarProxy >; + + protected: - size_t x; - size_t y; - bin_t bin; - params_t params; ++ /** The storage of this stat. */ ++ Storage *storage; ++ size_t _size; ++ ++ /** The parameters for this stat. */ ++ Params params; + + protected: - Storage *data(int index) { return bin.data(index, params); } - const Storage *data(int index) const ++ /** ++ * Retrieve the storage. ++ * @param index The vector index to access. ++ * @return The storage object at the given index. ++ */ ++ Storage *data(int index) { return &storage[index]; } ++ ++ /** ++ * Retrieve a const pointer to the storage. ++ * @param index The vector index to access. ++ * @return A const pointer to the storage object at the given index. ++ */ ++ const Storage *data(int index) const { return &storage[index]; } ++ ++ void ++ doInit(int s) + { - bin_t *_bin = const_cast(&bin); - params_t *_params = const_cast(¶ms); - return _bin->data(index, *_params); ++ assert(s > 0 && "size must be positive!"); ++ assert(!storage && "already initialized"); ++ _size = s; ++ ++ char *ptr = new char[_size * sizeof(Storage)]; ++ storage = reinterpret_cast(ptr); ++ ++ for (int i = 0; i < _size; ++i) ++ new (&storage[i]) Storage(params); ++ ++ setInit(); + } + + public: - Vector2dBase() {} ++ void value(VCounter &vec) const ++ { ++ vec.resize(size()); ++ for (int i = 0; i < size(); ++i) ++ vec[i] = data(i)->value(params); ++ } + - void update(Vector2dData *data) ++ /** ++ * Copy the values to a local vector and return a reference to it. ++ * @return A reference to a vector of the stat values. ++ */ ++ void result(VResult &vec) const + { - int size = this->size(); - data->cvec.resize(size); - for (int i = 0; i < size; ++i) - data->cvec[i] = this->data(i)->value(params); ++ vec.resize(size()); ++ for (int i = 0; i < size(); ++i) ++ vec[i] = data(i)->result(params); + } + - std::string ysubname(int i) const { return (*this->y_subnames)[i]; } ++ /** ++ * Return a total of all entries in this vector. ++ * @return The total of all vector entries. ++ */ ++ Result total() const { ++ Result total = 0.0; ++ for (int i = 0; i < size(); ++i) ++ total += data(i)->result(params); ++ return total; ++ } ++ ++ /** ++ * @return the number of elements in this vector. ++ */ ++ size_t size() const { return _size; } + - friend class VectorProxy; - VectorProxy operator[](int index); ++ bool ++ zero() const ++ { ++ for (int i = 0; i < size(); ++i) ++ if (data(i)->zero()) ++ return false; ++ return true; ++ } + - size_t size() const { return bin.size(); } - bool zero() const { return data(0)->value(params) == 0.0; } ++ bool ++ check() const ++ { ++ return storage != NULL; ++ } ++ ++ void ++ reset() ++ { ++ for (int i = 0; i < size(); ++i) ++ data(i)->reset(); ++ } ++ ++ public: ++ VectorBase() ++ : storage(NULL) ++ {} ++ ++ ~VectorBase() ++ { ++ if (!storage) ++ return; ++ ++ for (int i = 0; i < _size; ++i) ++ data(i)->~Storage(); ++ delete [] reinterpret_cast(storage); ++ } + + /** - * Reset stat value to default ++ * Return a reference (ScalarProxy) to the stat at the given index. ++ * @param index The vector index to access. ++ * @return A reference of the stat. + */ - void reset() { bin.reset(); } ++ Proxy ++ operator[](int index) ++ { ++ assert (index >= 0 && index < size()); ++ return Proxy(this, index); ++ } + - bool check() { return bin.initialized(); } ++ void update(StatData *data) {} +}; + - template ++template +class VectorProxy +{ - public: - typedef typename Storage::Params params_t; - typedef typename Bin::template VectorBin bin_t; - + private: - bin_t *bin; - params_t *params; ++ Stat *stat; + int offset; + int len; - void *stat; + + private: - mutable VResult *vec; ++ mutable VResult vec; + - Storage *data(int index) { ++ typename Stat::Storage * ++ data(int index) ++ { + assert(index < len); - return bin->data(offset + index, *params); ++ return stat->data(offset + index); + } + - const Storage *data(int index) const { - bin_t *_bin = const_cast(bin); - params_t *_params = const_cast(params); - return _bin->data(offset + index, *_params); ++ const typename Stat::Storage * ++ data(int index) const ++ { ++ assert(index < len); ++ return const_cast(stat)->data(offset + index); + } + + public: - const VResult &result() const { - if (vec) - vec->resize(size()); - else - vec = new VResult(size()); ++ const VResult & ++ result() const ++ { ++ vec.resize(size()); + + for (int i = 0; i < size(); ++i) - (*vec)[i] = data(i)->result(*params); ++ vec[i] = data(i)->result(stat->params); + - return *vec; ++ return vec; + } + - Result total() const { - Result total = 0.0; ++ Result ++ total() const ++ { ++ Result total = 0; + for (int i = 0; i < size(); ++i) - total += data(i)->result(*params); ++ total += data(i)->result(stat->params); + return total; + } + + public: - VectorProxy(bin_t &b, params_t &p, int o, int l, void *s) - : bin(&b), params(&p), offset(o), len(l), stat(s), vec(NULL) ++ VectorProxy(Stat *s, int o, int l) ++ : stat(s), offset(o), len(l) + { + } + + VectorProxy(const VectorProxy &sp) - : bin(sp.bin), params(sp.params), offset(sp.offset), len(sp.len), - stat(sp.stat), vec(NULL) - { - } - - ~VectorProxy() ++ : stat(sp.stat), offset(sp.offset), len(sp.len) + { - if (vec) - delete vec; + } + - const VectorProxy &operator=(const VectorProxy &sp) ++ const VectorProxy & ++ operator=(const VectorProxy &sp) + { - bin = sp.bin; - params = sp.params; ++ stat = sp.stat; + offset = sp.offset; + len = sp.len; - stat = sp.stat; - if (vec) - delete vec; - vec = NULL; + return *this; + } + - ScalarProxy operator[](int index) ++ ScalarProxy operator[](int index) + { + assert (index >= 0 && index < size()); - return ScalarProxy(*bin, *params, offset + index, stat); ++ return ScalarProxy(stat, offset + index); + } + + size_t size() const { return len; } + - /** - * Return true if stat is binned. - *@return false since Proxies aren't printed/binned - */ - bool binned() const { return false; } - + /** + * This stat has no state. Nothing to reset. + */ + void reset() { } +}; + - template - inline VectorProxy - Vector2dBase::operator[](int index) ++template ++class Vector2dBase : public DataAccess +{ - int offset = index * y; - assert (index >= 0 && offset < size()); - return VectorProxy(bin, params, offset, y, this); - } ++ public: ++ typedef Stor Storage; ++ typedef typename Storage::Params Params; ++ typedef VectorProxy > Proxy; ++ friend class ScalarProxy >; ++ friend class VectorProxy >; ++ ++ protected: ++ size_t x; ++ size_t y; ++ size_t _size; ++ Storage *storage; ++ Params params; ++ ++ protected: ++ Storage *data(int index) { return &storage[index]; } ++ const Storage *data(int index) const { return &storage[index]; } ++ ++ void ++ doInit(int _x, int _y) ++ { ++ assert(_x > 0 && _y > 0 && "sizes must be positive!"); ++ assert(!storage && "already initialized"); ++ ++ Vector2dData *statdata = dynamic_cast(find()); ++ ++ x = _x; ++ y = _y; ++ statdata->x = _x; ++ statdata->y = _y; ++ _size = x * y; ++ ++ char *ptr = new char[_size * sizeof(Storage)]; ++ storage = reinterpret_cast(ptr); ++ ++ for (int i = 0; i < _size; ++i) ++ new (&storage[i]) Storage(params); ++ ++ setInit(); ++ } ++ ++ public: ++ Vector2dBase() ++ : storage(NULL) ++ {} ++ ++ ~Vector2dBase() ++ { ++ if (!storage) ++ return; ++ ++ for (int i = 0; i < _size; ++i) ++ data(i)->~Storage(); ++ delete [] reinterpret_cast(storage); ++ } ++ ++ void ++ update(Vector2dData *newdata) ++ { ++ int size = this->size(); ++ newdata->cvec.resize(size); ++ for (int i = 0; i < size; ++i) ++ newdata->cvec[i] = data(i)->value(params); ++ } ++ ++ std::string ysubname(int i) const { return (*this->y_subnames)[i]; } ++ ++ Proxy ++ operator[](int index) ++ { ++ int offset = index * y; ++ assert (index >= 0 && offset + index < size()); ++ return Proxy(this, offset, y); ++ } ++ ++ ++ size_t ++ size() const ++ { ++ return _size; ++ } ++ ++ bool ++ zero() const ++ { ++ return data(0)->zero(); ++#if 0 ++ for (int i = 0; i < size(); ++i) ++ if (!data(i)->zero()) ++ return false; ++ return true; ++#endif ++ } ++ ++ /** ++ * Reset stat value to default ++ */ ++ void ++ reset() ++ { ++ for (int i = 0; i < size(); ++i) ++ data(i)->reset(); ++ } ++ ++ bool ++ check() ++ { ++ return storage != NULL; ++ } ++}; + +////////////////////////////////////////////////////////////////////// +// +// Non formula statistics +// +////////////////////////////////////////////////////////////////////// + +/** + * Templatized storage and interface for a distrbution stat. + */ +struct DistStor +{ + public: + /** The parameters for a distribution stat. */ + struct Params + { + /** The minimum value to track. */ + Counter min; + /** The maximum value to track. */ + Counter max; + /** The number of entries in each bucket. */ + Counter bucket_size; + /** The number of buckets. Equal to (max-min)/bucket_size. */ + int size; + }; + enum { fancy = false }; + + private: + /** The smallest value sampled. */ + Counter min_val; + /** The largest value sampled. */ + Counter max_val; + /** The number of values sampled less than min. */ + Counter underflow; + /** The number of values sampled more than max. */ + Counter overflow; + /** The current sum. */ + Counter sum; + /** The sum of squares. */ + Counter squares; + /** The number of samples. */ + Counter samples; + /** Counter for each bucket. */ + VCounter cvec; + + public: - /** - * Construct this storage with the supplied params. - * @param params The parameters. - */ + DistStor(const Params ¶ms) - : min_val(INT_MAX), max_val(INT_MIN), underflow(Counter()), - overflow(Counter()), sum(Counter()), squares(Counter()), - samples(Counter()), cvec(params.size) ++ : cvec(params.size) + { + reset(); + } + + /** + * Add a value to the distribution for the given number of times. + * @param val The value to add. + * @param number The number of times to add the value. + * @param params The paramters of the distribution. + */ + 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 = (int)floor((val - params.min) / params.bucket_size); + assert(index < size(params)); + cvec[index] += number; + } + + if (val < min_val) + min_val = val; + + if (val > max_val) + max_val = val; + + Counter sample = val * number; + sum += sample; + squares += sample * sample; + samples += number; + } + + /** + * Return the number of buckets in this distribution. + * @return the number of buckets. + * @todo Is it faster to return the size from the parameters? + */ + size_t size(const Params &) const { return cvec.size(); } + + /** + * Returns true if any calls to sample have been made. + * @param params The paramters of the distribution. + * @return True if any values have been sampled. + */ + bool zero(const Params ¶ms) const + { + return samples == Counter(); + } + + void update(DistDataData *data, const Params ¶ms) + { + data->min = params.min; + data->max = params.max; + data->bucket_size = params.bucket_size; + data->size = params.size; + + data->min_val = (min_val == INT_MAX) ? 0 : min_val; + data->max_val = (max_val == INT_MIN) ? 0 : max_val; + data->underflow = underflow; + data->overflow = overflow; + data->cvec.resize(params.size); + for (int i = 0; i < params.size; ++i) + data->cvec[i] = cvec[i]; + + data->sum = sum; + data->squares = squares; + data->samples = samples; + } + + /** + * Reset stat value to default + */ + void reset() + { + min_val = INT_MAX; + max_val = INT_MIN; + underflow = 0; + overflow = 0; + + int size = cvec.size(); + for (int i = 0; i < size; ++i) + cvec[i] = Counter(); + + sum = Counter(); + squares = Counter(); + samples = Counter(); + } +}; + +/** + * Templatized storage and interface for a distribution that calculates mean + * and variance. + */ +struct FancyStor +{ + public: + /** + * No paramters for this storage. + */ + struct Params {}; + enum { fancy = true }; + + private: + /** The current sum. */ + Counter sum; + /** The sum of squares. */ + Counter squares; + /** The number of samples. */ + Counter samples; + + public: + /** + * Create and initialize this storage. + */ + FancyStor(const Params &) + : sum(Counter()), squares(Counter()), samples(Counter()) + { } + + /** + * Add a value the given number of times to this running average. + * Update the running sum and sum of squares, increment the number of + * values seen by the given number. + * @param val The value to add. + * @param number The number of times to add the value. + * @param p The parameters of this stat. + */ + void sample(Counter val, int number, const Params &p) + { + Counter value = val * number; + sum += value; + squares += value * value; + samples += number; + } + + void update(DistDataData *data, const Params ¶ms) + { + data->sum = sum; + data->squares = squares; + data->samples = samples; + } + + /** + * Return the number of entries in this stat, 1 + * @return 1. + */ + size_t size(const Params &) const { return 1; } + + /** + * Return true if no samples have been added. + * @return True if no samples have been added. + */ + bool zero(const Params &) const { return samples == Counter(); } + + /** + * Reset stat value to default + */ + void reset() + { + sum = Counter(); + squares = Counter(); + samples = Counter(); + } +}; + +/** + * Templatized storage for distribution that calculates per cycle mean and + * variance. + */ +struct AvgFancy +{ + public: + /** No parameters for this storage. */ + struct Params {}; + enum { fancy = true }; + + private: + /** Current total. */ + Counter sum; + /** Current sum of squares. */ + Counter squares; + + public: + /** + * Create and initialize this storage. + */ + AvgFancy(const Params &) : sum(Counter()), squares(Counter()) {} + + /** + * Add a value to the distribution for the given number of times. + * Update the running sum and sum of squares. + * @param val The value to add. + * @param number The number of times to add the value. + * @param p The paramters of the distribution. + */ + void sample(Counter val, int number, const Params &p) + { + Counter value = val * number; + sum += value; + squares += value * value; + } + + void update(DistDataData *data, const Params ¶ms) + { + data->sum = sum; + data->squares = squares; + data->samples = curTick; + } + + /** + * Return the number of entries, in this case 1. + * @return 1. + */ + size_t size(const Params ¶ms) const { return 1; } + /** + * Return true if no samples have been added. + * @return True if the sum is zero. + */ + bool zero(const Params ¶ms) const { return sum == Counter(); } + /** + * Reset stat value to default + */ + void reset() + { + sum = Counter(); + squares = Counter(); + } +}; + +/** + * Implementation of a distribution stat. The type of distribution is + * determined by the Storage template. @sa ScalarBase + */ - template ++template +class DistBase : public DataAccess +{ + public: ++ typedef Stor Storage; + /** Define the params of the storage class. */ - typedef typename Storage::Params params_t; - /** Define the bin type. */ - typedef typename Bin::template Bin bin_t; ++ typedef typename Storage::Params Params; + + protected: - /** The bin of this stat. */ - bin_t bin; ++ /** The storage for this stat. */ ++ char storage[sizeof(Storage)]; ++ + /** The parameters for this stat. */ - params_t params; ++ Params params; + + protected: + /** - * Retrieve the storage from the bin. ++ * Retrieve the storage. + * @return The storage object for this stat. + */ - Storage *data() { return bin.data(params); } ++ Storage *data() ++ { ++ return reinterpret_cast(storage); ++ } ++ + /** - * Retrieve a const pointer to the storage from the bin. ++ * Retrieve a const pointer to the storage. + * @return A const pointer to the storage object for this stat. + */ - const Storage *data() const ++ const Storage * ++ data() const + { - bin_t *_bin = const_cast(&bin); - params_t *_params = const_cast(¶ms); - return _bin->data(*_params); ++ return reinterpret_cast(storage); ++ } ++ ++ void ++ doInit() ++ { ++ new (storage) Storage(params); ++ setInit(); + } + + public: + DistBase() { } + + /** + * Add a value to the distribtion n times. Calls sample on the storage + * class. + * @param v The value to add. + * @param n The number of times to add it, defaults to 1. + */ + template + void sample(const U &v, int n = 1) { data()->sample(v, n, params); } + + /** + * Return the number of entries in this stat. + * @return The number of entries. + */ + size_t size() const { return data()->size(params); } + /** + * Return true if no samples have been added. + * @return True if there haven't been any samples. + */ + bool zero() const { return data()->zero(params); } + + void update(DistData *base) + { + base->data.fancy = Storage::fancy; + data()->update(&(base->data), params); + } - /** - * @return True is stat is binned. - */ - bool binned() const { return bin_t::binned; } ++ + /** + * Reset stat value to default + */ - void reset() ++ void ++ reset() + { - bin.reset(); ++ data()->reset(); + } + - bool check() { return bin.initialized(); } ++ bool ++ check() ++ { ++ return true; ++ } +}; + - template ++template +class DistProxy; + - template ++template +class VectorDistBase : public DataAccess +{ + public: - typedef typename Storage::Params params_t; - typedef typename Bin::template VectorBin bin_t; ++ typedef Stor Storage; ++ typedef typename Storage::Params Params; ++ typedef DistProxy > Proxy; ++ friend class DistProxy >; + + protected: - bin_t bin; - params_t params; ++ Storage *storage; ++ size_t _size; ++ Params params; + + protected: - Storage *data(int index) { return bin.data(index, params); } - const Storage *data(int index) const ++ Storage * ++ data(int index) ++ { ++ return &storage[index]; ++ } ++ ++ const Storage * ++ data(int index) const + { - bin_t *_bin = const_cast(&bin); - params_t *_params = const_cast(¶ms); - return _bin->data(index, *_params); ++ return &storage[index]; ++ } ++ ++ void ++ doInit(int s) ++ { ++ assert(s > 0 && "size must be positive!"); ++ assert(!storage && "already initialized"); ++ _size = s; ++ ++ char *ptr = new char[_size * sizeof(Storage)]; ++ storage = reinterpret_cast(ptr); ++ ++ for (int i = 0; i < _size; ++i) ++ new (&storage[i]) Storage(params); ++ ++ setInit(); + } + + public: - VectorDistBase() {} ++ VectorDistBase() ++ : storage(NULL) ++ {} + - friend class DistProxy; - DistProxy operator[](int index); - const DistProxy operator[](int index) const; ++ ~VectorDistBase() ++ { ++ if (!storage) ++ return ; ++ ++ for (int i = 0; i < _size; ++i) ++ data(i)->~Storage(); ++ delete [] reinterpret_cast(storage); ++ } ++ ++ Proxy operator[](int index); ++ ++ size_t ++ size() const ++ { ++ return _size; ++ } ++ ++ bool ++ zero() const ++ { ++ return false; ++#if 0 ++ for (int i = 0; i < size(); ++i) ++ if (!data(i)->zero(params)) ++ return false; ++ return true; ++#endif ++ } + - size_t size() const { return bin.size(); } - bool zero() const { return false; } - /** - * Return true if stat is binned. - *@return True is stat is binned. - */ - bool binned() const { return bin_t::binned; } + /** + * Reset stat value to default + */ - void reset() { bin.reset(); } ++ void ++ reset() ++ { ++ for (int i = 0; i < size(); ++i) ++ data(i)->reset(); ++ } ++ ++ bool ++ check() ++ { ++ return storage != NULL; ++ } + - bool check() { return bin.initialized(); } - void update(VectorDistData *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::fancy; + data(i)->update(&(base->data[i]), params); + } + } +}; + - template ++template +class DistProxy +{ - public: - typedef typename Storage::Params params_t; - typedef typename Bin::template Bin bin_t; - typedef VectorDistBase base_t; - + private: - union { - base_t *stat; - const base_t *cstat; - }; ++ Stat *stat; + int index; + + protected: - Storage *data() { return stat->data(index); } - const Storage *data() const { return cstat->data(index); } ++ typename Stat::Storage *data() { return stat->data(index); } ++ const typename Stat::Storage *data() const { return stat->data(index); } + + public: - DistProxy(const VectorDistBase &s, int i) - : cstat(&s), index(i) {} ++ DistProxy(Stat *s, int i) ++ : stat(s), index(i) ++ {} ++ + DistProxy(const DistProxy &sp) - : cstat(sp.cstat), index(sp.index) {} - const DistProxy &operator=(const DistProxy &sp) { - cstat = sp.cstat; index = sp.index; return *this; ++ : stat(sp.stat), index(sp.index) ++ {} ++ ++ const DistProxy &operator=(const DistProxy &sp) ++ { ++ stat = sp.stat; ++ index = sp.index; ++ return *this; + } + + public: + template - void sample(const U &v, int n = 1) { data()->sample(v, n, cstat->params); } ++ void ++ sample(const U &v, int n = 1) ++ { ++ data()->sample(v, n, stat->params); ++ } ++ ++ size_t ++ size() const ++ { ++ return 1; ++ } ++ ++ bool ++ zero() const ++ { ++ return data()->zero(stat->params); ++ } + - size_t size() const { return 1; } - bool zero() const { return data()->zero(cstat->params); } - /** - * Return true if stat is binned. - *@return false since Proxies are not binned/printed. - */ - bool binned() const { return false; } + /** + * Proxy has no state. Nothing to reset. + */ + void reset() { } +}; + - template - inline DistProxy - VectorDistBase::operator[](int index) ++template ++inline typename VectorDistBase::Proxy ++VectorDistBase::operator[](int index) +{ + assert (index >= 0 && index < size()); - return DistProxy(*this, index); - } - - template - inline const DistProxy - VectorDistBase::operator[](int index) const - { - assert (index >= 0 && index < size()); - return DistProxy(*this, index); ++ return typename VectorDistBase::Proxy(this, index); +} + +#if 0 - template ++template +Result - VectorDistBase::total(int index) const ++VectorDistBase::total(int index) const +{ + int total = 0; - for (int i=0; i < x_size(); ++i) { - total += data(i)->result(*params); ++ for (int i = 0; i < x_size(); ++i) { ++ total += data(i)->result(stat->params); + } +} +#endif + +////////////////////////////////////////////////////////////////////// +// +// Formula Details +// +////////////////////////////////////////////////////////////////////// + +/** + * Base class for formula statistic node. These nodes are used to build a tree + * that represents the formula. + */ +class Node : public RefCounted +{ + public: + /** + * Return the number of nodes in the subtree starting at this node. + * @return the number of nodes in this subtree. + */ + virtual size_t size() const = 0; + /** + * Return the result vector of this subtree. + * @return The result vector of this subtree. + */ + virtual const VResult &result() const = 0; + /** + * Return the total of the result vector. + * @return The total of the result vector. + */ + virtual Result total() const = 0; - /** - * Return true if stat is binned. - *@return True is stat is binned. - */ - virtual bool binned() const = 0; + + /** + * + */ + virtual std::string str() const = 0; +}; + +/** Reference counting pointer to a function Node. */ +typedef RefCountingPtr NodePtr; + +class ScalarStatNode : public Node +{ + private: + const ScalarData *data; + mutable VResult vresult; + + public: + ScalarStatNode(const ScalarData *d) : data(d), vresult(1) {} + virtual const VResult &result() const + { + vresult[0] = data->result(); + return vresult; + } + virtual Result total() const { return data->result(); }; + + virtual size_t size() const { return 1; } - /** - * Return true if stat is binned. - *@return True is stat is binned. - */ - virtual bool binned() const { return data->binned(); } + + /** + * + */ + virtual std::string str() const { return data->name; } +}; + - template ++template +class ScalarProxyNode : public Node +{ + private: - const ScalarProxy proxy; ++ const ScalarProxy proxy; + mutable VResult vresult; + + public: - ScalarProxyNode(const ScalarProxy &p) - : proxy(p), vresult(1) { } - virtual const VResult &result() const ++ ScalarProxyNode(const ScalarProxy &p) ++ : proxy(p), vresult(1) ++ { } ++ ++ virtual const VResult & ++ result() const + { + vresult[0] = proxy.result(); + return vresult; + } - virtual Result total() const { return proxy.result(); }; + - virtual size_t size() const { return 1; } - /** - * Return true if stat is binned. - *@return True is stat is binned. - */ - virtual bool binned() const { return proxy.binned(); } ++ virtual Result ++ total() const ++ { ++ return proxy.result(); ++ } ++ ++ virtual size_t ++ size() const ++ { ++ return 1; ++ } + + /** + * + */ - virtual std::string str() const { return proxy.str(); } ++ virtual std::string ++ str() const ++ { ++ return proxy.str(); ++ } +}; + +class VectorStatNode : public Node +{ + private: + const VectorData *data; + + public: + 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(); } - /** - * Return true if stat is binned. - *@return True is stat is binned. - */ - virtual bool binned() const { return data->binned(); } + + virtual std::string str() const { return data->name; } +}; + +template +class ConstNode : public Node +{ + private: + VResult vresult; + + public: + 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(vresult[0]); } +}; + +template +struct OpString; + +template<> +struct OpString > +{ + static std::string str() { return "+"; } +}; + +template<> +struct OpString > +{ + static std::string str() { return "-"; } +}; + +template<> +struct OpString > +{ + static std::string str() { return "*"; } +}; + +template<> +struct OpString > +{ + static std::string str() { return "/"; } +}; + +template<> +struct OpString > +{ + static std::string str() { return "%"; } +}; + +template<> +struct OpString > +{ + static std::string str() { return "-"; } +}; + +template +class UnaryNode : public Node +{ + public: + NodePtr l; + mutable VResult vresult; + + public: + UnaryNode(NodePtr &p) : l(p) {} + + const VResult &result() const + { + const VResult &lvec = l->result(); + int size = lvec.size(); + + assert(size > 0); + + vresult.resize(size); + Op op; + for (int i = 0; i < size; ++i) + vresult[i] = op(lvec[i]); + + return vresult; + } + + Result total() const { + Op op; + return op(l->total()); + } + + virtual size_t size() const { return l->size(); } - /** - * Return true if child of node is binned. - *@return True if child of node is binned. - */ - virtual bool binned() const { return l->binned(); } + + virtual std::string str() const + { + return OpString::str() + l->str(); + } +}; + +template +class BinaryNode : public Node +{ + public: + NodePtr l; + NodePtr r; + mutable VResult vresult; + + public: + BinaryNode(NodePtr &a, NodePtr &b) : l(a), r(b) {} + + const VResult &result() const + { + Op op; + const VResult &lvec = l->result(); + const VResult &rvec = r->result(); + + assert(lvec.size() > 0 && rvec.size() > 0); + + if (lvec.size() == 1 && rvec.size() == 1) { + vresult.resize(1); + vresult[0] = op(lvec[0], rvec[0]); + } else if (lvec.size() == 1) { + int size = rvec.size(); + vresult.resize(size); + for (int i = 0; i < size; ++i) + vresult[i] = op(lvec[0], rvec[i]); + } else if (rvec.size() == 1) { + int size = lvec.size(); + vresult.resize(size); + for (int i = 0; i < size; ++i) + vresult[i] = op(lvec[i], rvec[0]); + } else if (rvec.size() == lvec.size()) { + int size = rvec.size(); + vresult.resize(size); + for (int i = 0; i < size; ++i) + vresult[i] = op(lvec[i], rvec[i]); + } + + return vresult; + } + + Result total() const { + Op op; + return op(l->total(), r->total()); + } + + virtual size_t size() const { + int ls = l->size(); + int rs = r->size(); + if (ls == 1) + return rs; + else if (rs == 1) + return ls; + else { + assert(ls == rs && "Node vector sizes are not equal"); + return ls; + } + } - /** - * Return true if any children of node are binned - *@return True if either child of node is binned. - */ - virtual bool binned() const { return (l->binned() || r->binned()); } + + virtual std::string str() const + { + return csprintf("(%s %s %s)", l->str(), OpString::str(), r->str()); + } +}; + +template +class SumNode : public Node +{ + public: + NodePtr l; + mutable VResult vresult; + + public: + SumNode(NodePtr &p) : l(p), vresult(1) {} + + const VResult &result() const + { + const VResult &lvec = l->result(); + int size = lvec.size(); + assert(size > 0); + + vresult[0] = 0.0; + + Op op; + for (int i = 0; i < size; ++i) + vresult[0] = op(vresult[0], lvec[i]); + + return vresult; + } + + Result total() const + { + const VResult &lvec = l->result(); + int size = lvec.size(); + assert(size > 0); + + Result vresult = 0.0; + + Op op; + for (int i = 0; i < size; ++i) + vresult = op(vresult, lvec[i]); + + return vresult; + } + + virtual size_t size() const { return 1; } - /** - * Return true if child of node is binned. - *@return True if child of node is binned. - */ - virtual bool binned() const { return l->binned(); } + + virtual std::string str() const + { + return csprintf("total(%s)", l->str()); + } +}; + + +////////////////////////////////////////////////////////////////////// +// +// Visible Statistics Types +// +////////////////////////////////////////////////////////////////////// +/** + * @defgroup VisibleStats "Statistic Types" - * These are the statistics that are used in the simulator. By default these - * store counters and don't use binning, but are templatized to accept any type - * and any Bin class. ++ * These are the statistics that are used in the simulator. + * @{ + */ + - /** - * This is an easy way to assign all your stats to be binned or not - * binned. If the typedef is NoBin, nothing is binned. If it is - * MainBin, then all stats are binned under that Bin. - */ - #if STATS_BINNING - typedef MainBin DefaultBin; - #else - typedef NoBin DefaultBin; - #endif - +/** + * This is a simple scalar statistic, like a counter. + * @sa Stat, ScalarBase, StatStor + */ - template - class Scalar - : public Wrap, - ScalarBase, - ScalarStatData> ++template ++class Scalar : public Wrap, ScalarBase, ScalarStatData> +{ + public: + /** The base implementation. */ - typedef ScalarBase Base; ++ typedef ScalarBase Base; + + Scalar() + { - this->setInit(); ++ this->doInit(); + } + + /** + * Sets the stat equal to the given value. Calls the base implementation + * of operator= + * @param v The new value. + */ + template + void operator=(const U &v) { Base::operator=(v); } +}; + - class Value - : public Wrap ++class Value : public Wrap +{ + public: + /** The base implementation. */ + typedef ValueBase Base; + + template + Value &scalar(T &value) + { + Base::scalar(value); + return *this; + } + + template + Value &functor(T &func) + { + Base::functor(func); + return *this; + } +}; + +/** + * A stat that calculates the per cycle average of a value. + * @sa Stat, ScalarBase, AvgStor + */ - template - class Average - : public Wrap, - ScalarBase, - ScalarStatData> ++template ++class Average : public Wrap, ScalarBase, ScalarStatData> +{ + public: + /** The base implementation. */ - typedef ScalarBase Base; ++ typedef ScalarBase Base; + + Average() + { - this->setInit(); ++ this->doInit(); + } + + /** + * Sets the stat equal to the given value. Calls the base implementation + * of operator= + * @param v The new value. + */ + template + void operator=(const U &v) { Base::operator=(v); } +}; + +/** + * A vector of scalar stats. + * @sa Stat, VectorBase, StatStor + */ - template - class Vector - : public WrapVec, - VectorBase, - VectorStatData> ++template ++class Vector : public WrapVec, VectorBase, VectorStatData> +{ + public: + /** The base implementation. */ - typedef ScalarBase Base; ++ typedef ScalarBase Base; + + /** + * Set this vector to have the given size. + * @param size The new size. + * @return A reference to this stat. + */ + Vector &init(size_t size) { - this->bin.init(size, this->params); - this->setInit(); - ++ this->doInit(size); + return *this; + } +}; + +/** + * A vector of Average stats. + * @sa Stat, VectorBase, AvgStor + */ - template ++template +class AverageVector - : public WrapVec, - VectorBase, - VectorStatData> ++ : public WrapVec, VectorBase, VectorStatData> +{ + public: + /** + * Set this vector to have the given size. + * @param size The new size. + * @return A reference to this stat. + */ + AverageVector &init(size_t size) { - this->bin.init(size, this->params); - this->setInit(); - ++ this->doInit(size); + return *this; + } +}; + +/** + * A 2-Dimensional vecto of scalar stats. + * @sa Stat, Vector2dBase, StatStor + */ - template ++template +class Vector2d - : public WrapVec2d, - Vector2dBase, - Vector2dStatData> ++ : public WrapVec2d, Vector2dBase, Vector2dStatData> +{ + public: - Vector2d &init(size_t _x, size_t _y) { - this->statData()->x = this->x = _x; - this->statData()->y = this->y = _y; - this->bin.init(this->x * this->y, this->params); - this->setInit(); - ++ Vector2d &init(size_t x, size_t y) { ++ this->doInit(x, y); + return *this; + } +}; + +/** + * A simple distribution stat. + * @sa Stat, DistBase, DistStor + */ - template ++template +class Distribution - : public Wrap, - DistBase, - DistStatData> ++ : public Wrap, DistBase, DistStatData> +{ + public: + /** Base implementation. */ - typedef DistBase Base; ++ typedef DistBase Base; + /** The Parameter type. */ - typedef typename DistStor::Params Params; ++ typedef DistStor::Params Params; + + public: + /** + * Set the parameters of this distribution. @sa DistStor::Params + * @param min The minimum value of the distribution. + * @param max The maximum value of the distribution. + * @param bkt The number of values in each bucket. + * @return A reference to this distribution. + */ + Distribution &init(Counter min, Counter max, Counter bkt) { + this->params.min = min; + this->params.max = max; + this->params.bucket_size = bkt; + this->params.size = (int)rint((max - min) / bkt + 1.0); - this->bin.init(this->params); - this->setInit(); - ++ this->doInit(); + return *this; + } +}; + +/** + * Calculates the mean and variance of all the samples. + * @sa Stat, DistBase, FancyStor + */ - template ++template +class StandardDeviation - : public Wrap, - DistBase, - DistStatData> ++ : public Wrap, DistBase, DistStatData> +{ + public: + /** The base implementation */ - typedef DistBase Base; ++ typedef DistBase Base; + /** The parameter type. */ - typedef typename DistStor::Params Params; ++ typedef DistStor::Params Params; + + public: + /** + * Construct and initialize this distribution. + */ + StandardDeviation() { - this->bin.init(this->params); - this->setInit(); ++ this->doInit(); + } +}; + +/** + * Calculates the per cycle mean and variance of the samples. + * @sa Stat, DistBase, AvgFancy + */ - template ++template +class AverageDeviation - : public Wrap, - DistBase, - DistStatData> ++ : public Wrap, DistBase, DistStatData> +{ + public: + /** The base implementation */ - typedef DistBase Base; ++ typedef DistBase Base; + /** The parameter type. */ - typedef typename DistStor::Params Params; ++ typedef DistStor::Params Params; + + public: + /** + * Construct and initialize this distribution. + */ + AverageDeviation() + { - this->bin.init(this->params); - this->setInit(); ++ this->doInit(); + } +}; + +/** + * A vector of distributions. + * @sa Stat, VectorDistBase, DistStor + */ - template ++template +class VectorDistribution - : public WrapVec, - VectorDistBase, ++ : public WrapVec, ++ VectorDistBase, + VectorDistStatData> +{ + public: + /** The base implementation */ - typedef VectorDistBase Base; ++ typedef VectorDistBase Base; + /** The parameter type. */ - typedef typename DistStor::Params Params; ++ typedef DistStor::Params Params; + + public: + /** + * Initialize storage and parameters for this distribution. + * @param size The size of the vector (the number of distributions). + * @param min The minimum value of the distribution. + * @param max The maximum value of the distribution. + * @param bkt The number of values in each bucket. + * @return A reference to this distribution. + */ + VectorDistribution &init(int size, Counter min, Counter max, Counter bkt) { + this->params.min = min; + this->params.max = max; + this->params.bucket_size = bkt; + this->params.size = (int)rint((max - min) / bkt + 1.0); - this->bin.init(size, this->params); - this->setInit(); - ++ this->doInit(size); + return *this; + } +}; + +/** + * This is a vector of StandardDeviation stats. + * @sa Stat, VectorDistBase, FancyStor + */ - template ++template +class VectorStandardDeviation - : public WrapVec, - VectorDistBase, ++ : public WrapVec, ++ VectorDistBase, + VectorDistStatData> +{ + public: + /** The base implementation */ - typedef VectorDistBase Base; ++ typedef VectorDistBase Base; + /** The parameter type. */ - typedef typename DistStor::Params Params; ++ typedef DistStor::Params Params; + + public: + /** + * Initialize storage for this distribution. + * @param size The size of the vector. + * @return A reference to this distribution. + */ + VectorStandardDeviation &init(int size) { - this->bin.init(size, this->params); - this->setInit(); - ++ this->doInit(size); + return *this; + } +}; + +/** + * This is a vector of AverageDeviation stats. + * @sa Stat, VectorDistBase, AvgFancy + */ - template ++template +class VectorAverageDeviation - : public WrapVec, - VectorDistBase, ++ : public WrapVec, ++ VectorDistBase, + VectorDistStatData> +{ + public: + /** The base implementation */ - typedef VectorDistBase Base; ++ typedef VectorDistBase Base; + /** The parameter type. */ - typedef typename DistStor::Params Params; ++ typedef DistStor::Params Params; + + public: + /** + * Initialize storage for this distribution. + * @param size The size of the vector. + * @return A reference to this distribution. + */ + VectorAverageDeviation &init(int size) { - this->bin.init(size, this->params); - this->setInit(); - ++ this->doInit(size); + return *this; + } +}; + +/** + * A formula for statistics that is calculated when printed. A formula is + * stored as a tree of Nodes that represent the equation to calculate. + * @sa Stat, ScalarStat, VectorStat, Node, Temp + */ +class FormulaBase : public DataAccess +{ + protected: + /** The root of the tree which represents the Formula */ + NodePtr root; + friend class Temp; + + public: + /** + * Return the result of the Fomula in a vector. If there were no Vector + * components to the Formula, then the vector is size 1. If there were, + * like x/y with x being a vector of size 3, then the result returned will + * be x[0]/y, x[1]/y, x[2]/y, respectively. + * @return The result vector. + */ + void result(VResult &vec) const; + + /** + * Return the total Formula result. If there is a Vector + * component to this Formula, then this is the result of the + * Formula if the formula is applied after summing all the + * 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 VResult val() returns. + * @return The total of the result vector. + */ + Result total() const; + + /** + * Return the number of elements in the tree. + */ + size_t size() const; + - /** - * Return true if Formula is binned. i.e. any of its children - * nodes are binned - * @return True if Formula is binned. - */ - bool binned() const; - + bool check() const { return true; } + + /** + * Formulas don't need to be reset + */ + void reset(); + + /** + * + */ + bool zero() const; + + /** + * + */ + void update(StatData *); + + std::string str() const; +}; + +class FormulaData : public VectorData +{ + public: + virtual std::string str() const = 0; + virtual bool check() const { return true; } +}; + +template +class FormulaStatData : public FormulaData +{ + protected: + Stat &s; + mutable VResult vec; + mutable VCounter cvec; + + public: + 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 VResult &result() const + { + s.result(vec); + return vec; + } + virtual Result total() const { return s.total(); } + virtual VCounter &value() const { return cvec; } + virtual void visit(Visit &visitor) + { + update(); + s.update(this); + visitor.visit(*this); + } + virtual std::string str() const { return s.str(); } +}; + +class Temp; +class Formula + : public WrapVec +{ + public: + /** + * Create and initialize thie formula, and register it with the database. + */ + Formula(); + + /** + * Create a formula with the given root node, register it with the + * database. + * @param r The root of the expression tree. + */ + Formula(Temp r); + + /** + * Set an unitialized Formula to the given root. + * @param r The root of the expression tree. + * @return a reference to this formula. + */ + const Formula &operator=(Temp r); + + /** + * Add the given tree to the existing one. + * @param r The root of the expression tree. + * @return a reference to this formula. + */ + const Formula &operator+=(Temp r); +}; + +class FormulaNode : public Node +{ + private: + const Formula &formula; + mutable VResult vec; + + public: + FormulaNode(const Formula &f) : formula(f) {} + + virtual size_t size() const { return formula.size(); } + 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(); } +}; + +/** + * Helper class to construct formula node trees. + */ +class Temp +{ + protected: + /** + * Pointer to a Node object. + */ + NodePtr node; + + public: + /** + * Copy the given pointer to this class. + * @param n A pointer to a Node object to copy. + */ + Temp(NodePtr n) : node(n) { } + + /** + * Return the node pointer. + * @return the node pointer. + */ + operator NodePtr&() { return node;} + + public: + /** + * Create a new ScalarStatNode. + * @param s The ScalarStat to place in a node. + */ - template - Temp(const Scalar &s) ++ template ++ Temp(const Scalar &s) + : node(new ScalarStatNode(s.statData())) { } + + /** + * Create a new ScalarStatNode. + * @param s The ScalarStat to place in a node. + */ + Temp(const Value &s) + : node(new ScalarStatNode(s.statData())) { } + + /** + * Create a new ScalarStatNode. + * @param s The ScalarStat to place in a node. + */ - template - Temp(const Average &s) ++ template ++ Temp(const Average &s) + : node(new ScalarStatNode(s.statData())) { } + + /** + * Create a new VectorStatNode. + * @param s The VectorStat to place in a node. + */ - template - Temp(const Vector &s) ++ template ++ Temp(const Vector &s) + : node(new VectorStatNode(s.statData())) { } + + /** + * + */ + Temp(const Formula &f) + : node(new FormulaNode(f)) { } + + /** + * Create a new ScalarProxyNode. + * @param p The ScalarProxy to place in a node. + */ - template - Temp(const ScalarProxy &p) - : node(new ScalarProxyNode(p)) { } ++ template ++ Temp(const ScalarProxy &p) ++ : node(new ScalarProxyNode(p)) { } + + /** + * Create a ConstNode + * @param value The value of the const node. + */ + Temp(signed char value) + : node(new ConstNode(value)) {} + + /** + * Create a ConstNode + * @param value The value of the const node. + */ + Temp(unsigned char value) + : node(new ConstNode(value)) {} + + /** + * Create a ConstNode + * @param value The value of the const node. + */ + Temp(signed short value) + : node(new ConstNode(value)) {} + + /** + * Create a ConstNode + * @param value The value of the const node. + */ + Temp(unsigned short value) + : node(new ConstNode(value)) {} + + /** + * Create a ConstNode + * @param value The value of the const node. + */ + Temp(signed int value) + : node(new ConstNode(value)) {} + + /** + * Create a ConstNode + * @param value The value of the const node. + */ + Temp(unsigned int value) + : node(new ConstNode(value)) {} + + /** + * Create a ConstNode + * @param value The value of the const node. + */ + Temp(signed long value) + : node(new ConstNode(value)) {} + + /** + * Create a ConstNode + * @param value The value of the const node. + */ + Temp(unsigned long value) + : node(new ConstNode(value)) {} + + /** + * Create a ConstNode + * @param value The value of the const node. + */ + Temp(signed long long value) + : node(new ConstNode(value)) {} + + /** + * Create a ConstNode + * @param value The value of the const node. + */ + Temp(unsigned long long value) + : node(new ConstNode(value)) {} + + /** + * Create a ConstNode + * @param value The value of the const node. + */ + Temp(float value) + : node(new ConstNode(value)) {} + + /** + * Create a ConstNode + * @param value The value of the const node. + */ + Temp(double value) + : node(new ConstNode(value)) {} +}; + + +/** + * @} + */ + +void check(); +void reset(); +void registerResetCallback(Callback *cb); + +inline Temp +operator+(Temp l, Temp r) +{ + return NodePtr(new BinaryNode >(l, r)); +} + +inline Temp +operator-(Temp l, Temp r) +{ + return NodePtr(new BinaryNode >(l, r)); +} + +inline Temp +operator*(Temp l, Temp r) +{ + return NodePtr(new BinaryNode >(l, r)); +} + +inline Temp +operator/(Temp l, Temp r) +{ + return NodePtr(new BinaryNode >(l, r)); +} + +inline Temp +operator-(Temp l) +{ + return NodePtr(new UnaryNode >(l)); +} + +template +inline Temp +constant(T val) +{ + return NodePtr(new ConstNode(val)); +} + +inline Temp +sum(Temp val) +{ + return NodePtr(new SumNode >(val)); +} + +/* namespace Stats */ } + +#endif // __BASE_STATISTICS_HH__ diff --cc src/base/stats/mysql.cc index fa4bcd5ee,000000000..0fb31f4ce mode 100644,000000..100644 --- a/src/base/stats/mysql.cc +++ b/src/base/stats/mysql.cc @@@ -1,902 -1,0 +1,828 @@@ +/* + * Copyright (c) 2004-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Nathan Binkert + */ + +#include +#include +#include +#include +#include + +#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/mysql_run.hh" +#include "base/stats/statdb.hh" +#include "base/stats/types.hh" +#include "base/str.hh" +#include "sim/host.hh" + +using namespace std; + +namespace Stats { + +MySqlRun MySqlDB; + +bool +MySqlConnected() +{ + return MySqlDB.connected(); +} + +void +MySqlRun::connect(const string &host, const string &user, const string &passwd, + const string &db, const string &name, const string &sample, + const string &project) +{ + if (connected()) + panic("can only get one database connection at this time!"); + + mysql.connect(host, user, passwd, db); + if (mysql.error) + panic("could not connect to database server\n%s\n", mysql.error); + + if (mysql.autocommit(false)) + panic("could not set autocommit\n%s\n", mysql.error); + + remove(name); + //cleanup(); + setup(name, sample, user, project); +} + +void +MySqlRun::setup(const string &name, const string &sample, const string &user, + const string &project) +{ + assert(mysql.connected()); + + stringstream insert; + ccprintf(insert, + "INSERT INTO " + "runs(rn_name,rn_sample,rn_user,rn_project,rn_date,rn_expire)" + "values(\"%s\", \"%s\", \"%s\", \"%s\", NOW()," + "DATE_ADD(CURDATE(), INTERVAL 31 DAY))", + name, sample, user, project); + + mysql.query(insert); + if (mysql.error) + panic("could not get a run\n%s\n", mysql.error); + + run_id = mysql.insert_id(); + if (mysql.commit()) + panic("could not commit transaction\n%s\n", mysql.error); +} + +void +MySqlRun::remove(const string &name) +{ + assert(mysql.connected()); + stringstream sql; + ccprintf(sql, "DELETE FROM runs WHERE rn_name=\"%s\"", name); + mysql.query(sql); + if (mysql.error) + panic("could not delete run\n%s\n", mysql.error); + if (mysql.commit()) + panic("could not commit transaction\n%s\n", mysql.error); +} + +void +MySqlRun::cleanup() +{ + assert(mysql.connected()); + + mysql.query("DELETE data " + "FROM data " + "LEFT JOIN runs ON dt_run=rn_id " + "WHERE rn_id IS NULL"); + + if (mysql.commit()) + panic("could not commit transaction\n%s\n", mysql.error); + + mysql.query("DELETE formula_ref " + "FROM formula_ref " + "LEFT JOIN runs ON fr_run=rn_id " + "WHERE rn_id IS NULL"); + + if (mysql.commit()) + panic("could not commit transaction\n%s\n", mysql.error); + + mysql.query("DELETE formulas " + "FROM formulas " + "LEFT JOIN formula_ref ON fm_stat=fr_stat " + "WHERE fr_stat IS NULL"); + + if (mysql.commit()) + panic("could not commit transaction\n%s\n", mysql.error); + + mysql.query("DELETE stats " + "FROM stats " + "LEFT JOIN data ON st_id=dt_stat " + "WHERE dt_stat IS NULL"); + + if (mysql.commit()) + panic("could not commit transaction\n%s\n", mysql.error); + + mysql.query("DELETE subdata " + "FROM subdata " + "LEFT JOIN data ON sd_stat=dt_stat " + "WHERE dt_stat IS NULL"); + + if (mysql.commit()) + panic("could not commit transaction\n%s\n", mysql.error); + - mysql.query("DELETE bins " - "FROM bins " - "LEFT JOIN data ON bn_id=dt_bin " - "WHERE dt_bin IS NULL"); - - if (mysql.commit()) - panic("could not commit transaction\n%s\n", mysql.error); - + mysql.query("DELETE events" + "FROM events" + "LEFT JOIN runs ON ev_run=rn_id" + "WHERE rn_id IS NULL"); + + if (mysql.commit()) + panic("could not commit transaction\n%s\n", mysql.error); + + mysql.query("DELETE event_names" + "FROM event_names" + "LEFT JOIN events ON en_id=ev_event" + "WHERE ev_event IS NULL"); + + if (mysql.commit()) + panic("could not commit transaction\n%s\n", mysql.error); +} + +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::setup() +{ + MySQL::Connection &mysql = MySqlDB.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) { + int id = mysql.insert_id(); + if (mysql.commit()) + panic("could not commit transaction\n%s\n", mysql.error); + return 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 find stat\n%s\n", mysql.error); + + assert(result.num_fields() == 16); + MySQL::Row row = result.fetch_row(); + if (!row) + panic("could not get stat row\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(const string &bin) - { - static map binmap; - - using namespace MySQL; - map::const_iterator i = binmap.find(bin); - if (i != binmap.end()) - return (*i).second; - - Connection &mysql = MySqlDB.conn(); - assert(mysql.connected()); - - uint16_t bin_id; - - stringstream select; - stringstream insert; - 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); - MySQL::Row row = result.fetch_row(); - if (row) { - to_number(row[0], bin_id); - goto exit; - } - } - - ccprintf(insert, "INSERT INTO bins(bn_name) values(\"%s\")", bin); - - mysql.query(insert); - if (mysql.error) - panic("could not get a bin\n%s\n", mysql.error); - - bin_id = mysql.insert_id(); - if (mysql.commit()) - panic("could not commit transaction\n%s\n", mysql.error); - - binmap.insert(make_pair(bin, bin_id)); - - exit: - return bin_id; - } - +InsertData::InsertData() +{ + query = new char[maxsize + 1]; + size = 0; + flush(); +} + +InsertData::~InsertData() +{ + delete [] query; +} + +void +InsertData::flush() +{ + if (size) { + MySQL::Connection &mysql = MySqlDB.conn(); + assert(mysql.connected()); + mysql.query(query); + if (mysql.error) + panic("could not insert data\n%s\n", mysql.error); + if (mysql.commit()) + panic("could not commit transaction\n%s\n", mysql.error); + } + + query[0] = '\0'; + size = 0; + first = true; + strcpy(query, "INSERT INTO " - "data(dt_stat,dt_x,dt_y,dt_run,dt_tick,dt_bin,dt_data) " ++ "data(dt_stat,dt_x,dt_y,dt_run,dt_tick,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\")", ++ size += sprintf(query + size, "(%u,%d,%d,%u,%llu,\"%f\")", + stat, x, y, MySqlDB.run(), (unsigned long long)tick, - bin, data); ++ data); +} + +struct InsertSubData +{ + uint16_t stat; + int16_t x; + int16_t y; + string name; + string descr; + + void setup(); +}; + +void +InsertSubData::setup() +{ + MySQL::Connection &mysql = MySqlDB.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); +// if (mysql.error) +// panic("could not insert subdata\n%s\n", mysql.error); + + if (mysql.commit()) + panic("could not commit transaction\n%s\n", mysql.error); +} + +void +InsertFormula(uint16_t stat, const string &formula) +{ + MySQL::Connection &mysql = MySqlDB.conn(); + assert(mysql.connected()); + stringstream insert_formula; + ccprintf(insert_formula, + "INSERT INTO formulas(fm_stat,fm_formula) values(%d, \"%s\")", + stat, formula); + + mysql.query(insert_formula); +// if (mysql.error) +// panic("could not insert formula\n%s\n", mysql.error); + + stringstream insert_ref; + ccprintf(insert_ref, + "INSERT INTO formula_ref(fr_stat,fr_run) values(%d, %d)", + stat, MySqlDB.run()); + + mysql.query(insert_ref); +// if (mysql.error) +// panic("could not insert formula reference\n%s\n", mysql.error); + + if (mysql.commit()) + panic("could not commit transaction\n%s\n", mysql.error); +} + +void +UpdatePrereq(uint16_t stat, uint16_t prereq) +{ + MySQL::Connection &mysql = MySqlDB.conn(); + assert(mysql.connected()); + stringstream update; + ccprintf(update, "UPDATE stats SET st_prereq=%d WHERE st_id=%d", + prereq, stat); + mysql.query(update); + if (mysql.error) + panic("could not update prereq\n%s\n", mysql.error); + + if (mysql.commit()) + panic("could not commit transaction\n%s\n", mysql.error); +} + +void +MySql::configure() +{ + /* + * set up all stats! + */ + using namespace Database; + + MySQL::Connection &mysql = MySqlDB.conn(); + + 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(stat_id, prereq_id); + } + } + + if (mysql.commit()) + panic("could not commit transaction\n%s\n", mysql.error); + + configured = true; +} + + +bool +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; + + return stat.print; +} + +void +MySql::configure(const ScalarData &data) +{ + if (!configure(data, "SCALAR")) + return; + + insert(data.id, stat.setup()); +} + +void +MySql::configure(const VectorData &data) +{ + if (!configure(data, "VECTOR")) + return; + + uint16_t statid = stat.setup(); + + 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.setup(); + } + } + + insert(data.id, statid); +} + +void +MySql::configure(const DistData &data) +{ + if (!configure(data, "DIST")) + return; + + 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.setup()); +} + +void +MySql::configure(const VectorDistData &data) +{ + if (!configure(data, "VECTORDIST")) + return; + + 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.setup(); + + 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.setup(); + } + } + + insert(data.id, statid); +} + +void +MySql::configure(const Vector2dData &data) +{ + if (!configure(data, "VECTOR2D")) + return; + + uint16_t statid = stat.setup(); + + if (!data.subnames.empty()) { + InsertSubData subdata; + subdata.stat = statid; + subdata.y = -1; + 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.setup(); + } + } + + if (!data.y_subnames.empty()) { + InsertSubData subdata; + subdata.stat = statid; + subdata.x = -1; + 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.setup(); + } + } + + insert(data.id, statid); +} + +void +MySql::configure(const FormulaData &data) +{ + configure(data, "FORMULA"); + insert(data.id, stat.setup()); + InsertFormula(find(data.id), data.str()); +} + - void - MySql::output(MainBin *bin) - { - MySQL::Connection &mysql = MySqlDB.conn(); - - if (bin) { - bin->activate(); - newdata.bin = SetupBin(bin->name()); - } else { - newdata.bin = 0; - } - - Database::stat_list_t::const_iterator i, end = Database::stats().end(); - for (i = Database::stats().begin(); i != end; ++i) { - StatData *stat = *i; - if (bin && stat->binned() || !bin && !stat->binned()) { - stat->visit(*this); - if (mysql.commit()) - panic("could not commit transaction\n%s\n", mysql.error); - } - } - } - +bool +MySql::valid() const +{ + return MySqlDB.connected(); +} + +void +MySql::output() +{ + using namespace Database; + assert(valid()); + + if (!configured) + configure(); + + // store sample # + newdata.tick = curTick; + - output(NULL); - if (!bins().empty()) { - bin_list_t::iterator i, end = bins().end(); - for (i = bins().begin(); i != end; ++i) - output(*i); ++ MySQL::Connection &mysql = MySqlDB.conn(); ++ ++ Database::stat_list_t::const_iterator i, end = Database::stats().end(); ++ for (i = Database::stats().begin(); i != end; ++i) { ++ StatData *stat = *i; ++ stat->visit(*this); ++ if (mysql.commit()) ++ panic("could not commit transaction\n%s\n", mysql.error); + } + + newdata.flush(); +} + +void +MySql::output(const ScalarData &data) +{ + if (!(data.flags & print)) + return; + + newdata.stat = find(data.id); + newdata.x = 0; + newdata.y = 0; + newdata.data = data.value(); + + newdata.insert(); +} + +void +MySql::output(const VectorData &data) +{ + if (!(data.flags & print)) + return; + + 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) +{ + if (!(data.flags & print)) + return; + + newdata.stat = find(data.id); + newdata.y = 0; + output(data.data); +} + +void +MySql::output(const VectorDistData &data) +{ + if (!(data.flags & print)) + return; + + 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) +{ + if (!(data.flags & print)) + return; + + 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) +{ +} + +/* + * 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) +{ + return; + if (!configured) + configure(data); + else + output(data); +} + +void +MySql::visit(const VectorDistData &data) +{ + return; + if (!configured) + configure(data); + else + output(data); +} + +void +MySql::visit(const Vector2dData &data) +{ + return; + if (!configured) + configure(data); + else + output(data); +} + +void +MySql::visit(const FormulaData &data) +{ + if (!configured) + configure(data); + else + output(data); +} + +/* namespace Stats */ } diff --cc src/base/stats/mysql.hh index 1d88fbcd9,000000000..50f7d9e97 mode 100644,000000..100644 --- a/src/base/stats/mysql.hh +++ b/src/base/stats/mysql.hh @@@ -1,157 -1,0 +1,154 @@@ +/* + * Copyright (c) 2004-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Nathan Binkert + */ + +#ifndef __BASE_STATS_MYSQL_HH__ +#define __BASE_STATS_MYSQL_HH__ + +#include +#include + +#include "base/stats/output.hh" + +namespace MySQL { class Connection; } +namespace Stats { + - class MainBin; +class DistDataData; +class MySqlRun; +bool MySqlConnected(); +extern MySqlRun MySqlDB; + +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 setup(); +}; + +class InsertData +{ + private: + char *query; + int size; + bool first; + static const int maxsize = 1024*1024; + + public: + MySqlRun *run; + + public: + uint64_t tick; + double data; + uint16_t stat; - uint16_t bin; + int16_t x; + int16_t y; + + public: + InsertData(); + ~InsertData(); + + void flush(); + void insert(); +}; + +class MySql : public Output +{ + protected: + SetupStat stat; + InsertData newdata; + std::list formulas; + bool configured; + + protected: + std::map idmap; + + void insert(int sim_id, int db_id) + { + using namespace std; + idmap.insert(make_pair(sim_id, db_id)); + } + + int find(int sim_id) + { + using namespace std; + map::const_iterator i = idmap.find(sim_id); + assert(i != idmap.end()); + return (*i).second; + } + public: + // 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(MainBin *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(); + bool 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 Stats */ } + +#endif // __BASE_STATS_MYSQL_HH__ diff --cc src/base/stats/statdb.cc index 682f62dc1,000000000..f9136807a mode 100644,000000..100644 --- a/src/base/stats/statdb.cc +++ b/src/base/stats/statdb.cc @@@ -1,95 -1,0 +1,83 @@@ +/* + * Copyright (c) 2004-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Nathan Binkert + */ + +#include "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 Stats { +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) - { - bin_list_t::iterator i, end = bins().end(); - for (i = bins().begin(); i != end; ++i) - if ((*i)->name() == _name) - panic("re-registering bin %s", _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 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 Stats */ } diff --cc src/base/stats/statdb.hh index 8c56e031e,000000000..a5b9be7eb mode 100644,000000..100644 --- a/src/base/stats/statdb.hh +++ b/src/base/stats/statdb.hh @@@ -1,76 -1,0 +1,70 @@@ +/* + * Copyright (c) 2004-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Nathan Binkert + */ + +#ifndef __BASE_STATS_STATDB_HH__ +#define __BASE_STATS_STATDB_HH__ + +#include +#include +#include +#include + +class Python; + +namespace Stats { + - class MainBin; +class StatData; + +namespace Database { + +typedef std::map stat_map_t; +typedef std::list stat_list_t; - typedef std::list 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 Stats */ } + +#endif // __BASE_STATS_STATDB_HH__ diff --cc src/base/stats/text.cc index 8d2144665,000000000..c4448efc9 mode 100644,000000..100644 --- a/src/base/stats/text.cc +++ b/src/base/stats/text.cc @@@ -1,738 -1,0 +1,724 @@@ +/* + * Copyright (c) 2004-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Nathan Binkert + */ + +#if defined(__APPLE__) +#define _GLIBCPP_USE_C99 1 +#endif + +#include +#include +#include +#include + +#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 Stats { + +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() || bins().size() == 1) { - 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->name()); - stat_list_t::const_iterator i, end = stats().end(); - for (i = stats().begin(); i != end; ++i) - (*i)->visit(*this); - ccprintf(*stream, "---------------------------------\n"); - } - } ++ stat_list_t::const_iterator i, end = stats().end(); ++ for (i = stats().begin(); i != end; ++i) ++ (*i)->visit(*this); + 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 ? "" : "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 subnames; + vector 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 & ::Stats::total) { + print.name = base + "total"; + print.desc = desc; + print.value = total; + print(stream); + } + } else { + if (flags & ::Stats::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 & ::Stats::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 Stats */ } diff --cc src/base/stats/text.hh index de27abe1b,000000000..b3faf5ad5 mode 100644,000000..100644 --- a/src/base/stats/text.hh +++ b/src/base/stats/text.hh @@@ -1,79 -1,0 +1,78 @@@ +/* + * Copyright (c) 2004-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Nathan Binkert + */ + +#ifndef __BASE_STATS_TEXT_HH__ +#define __BASE_STATS_TEXT_HH__ + +#include +#include + +#include "base/stats/output.hh" + +namespace Stats { + +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 Stats */ } + +#endif // __BASE_STATS_TEXT_HH__ diff --cc src/cpu/simple/base.cc index c1ecf3967,000000000..d94b0e079 mode 100644,000000..100644 --- a/src/cpu/simple/base.cc +++ b/src/cpu/simple/base.cc @@@ -1,474 -1,0 +1,469 @@@ +/* + * Copyright (c) 2002-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Steve Reinhardt + */ + +#include "arch/utility.hh" +#include "base/cprintf.hh" +#include "base/inifile.hh" +#include "base/loader/symtab.hh" +#include "base/misc.hh" +#include "base/pollevent.hh" +#include "base/range.hh" +#include "base/stats/events.hh" +#include "base/trace.hh" +#include "cpu/base.hh" +#include "cpu/exetrace.hh" +#include "cpu/profile.hh" +#include "cpu/sampler/sampler.hh" +#include "cpu/simple/base.hh" +#include "cpu/simple_thread.hh" +#include "cpu/smt.hh" +#include "cpu/static_inst.hh" +#include "cpu/thread_context.hh" +#include "kern/kernel_stats.hh" +#include "mem/packet_impl.hh" +#include "sim/builder.hh" +#include "sim/byteswap.hh" +#include "sim/debug.hh" +#include "sim/host.hh" +#include "sim/sim_events.hh" +#include "sim/sim_object.hh" +#include "sim/stats.hh" + +#if FULL_SYSTEM +#include "base/remote_gdb.hh" +#include "sim/system.hh" +#include "arch/tlb.hh" +#include "arch/stacktrace.hh" +#include "arch/vtophys.hh" +#else // !FULL_SYSTEM +#include "mem/mem_object.hh" +#endif // FULL_SYSTEM + +using namespace std; +using namespace TheISA; + +BaseSimpleCPU::BaseSimpleCPU(Params *p) + : BaseCPU(p), mem(p->mem), thread(NULL) +{ +#if FULL_SYSTEM + thread = new SimpleThread(this, 0, p->system, p->itb, p->dtb); +#else + thread = new SimpleThread(this, /* thread_num */ 0, p->process, + /* asid */ 0, mem); +#endif // !FULL_SYSTEM + + thread->setStatus(ThreadContext::Suspended); + + tc = thread->getTC(); + + numInst = 0; + startNumInst = 0; + numLoad = 0; + startNumLoad = 0; + lastIcacheStall = 0; + lastDcacheStall = 0; + + threadContexts.push_back(tc); +} + +BaseSimpleCPU::~BaseSimpleCPU() +{ +} + +void +BaseSimpleCPU::deallocateContext(int thread_num) +{ + // for now, these are equivalent + suspendContext(thread_num); +} + + +void +BaseSimpleCPU::haltContext(int thread_num) +{ + // for now, these are equivalent + suspendContext(thread_num); +} + + +void +BaseSimpleCPU::regStats() +{ + using namespace Stats; + + BaseCPU::regStats(); + + numInsts + .name(name() + ".num_insts") + .desc("Number of instructions executed") + ; + + numMemRefs + .name(name() + ".num_refs") + .desc("Number of memory references") + ; + + notIdleFraction + .name(name() + ".not_idle_fraction") + .desc("Percentage of non-idle cycles") + ; + + idleFraction + .name(name() + ".idle_fraction") + .desc("Percentage of idle cycles") + ; + + icacheStallCycles + .name(name() + ".icache_stall_cycles") + .desc("ICache total stall cycles") + .prereq(icacheStallCycles) + ; + + dcacheStallCycles + .name(name() + ".dcache_stall_cycles") + .desc("DCache total stall cycles") + .prereq(dcacheStallCycles) + ; + + icacheRetryCycles + .name(name() + ".icache_retry_cycles") + .desc("ICache total retry cycles") + .prereq(icacheRetryCycles) + ; + + dcacheRetryCycles + .name(name() + ".dcache_retry_cycles") + .desc("DCache total retry cycles") + .prereq(dcacheRetryCycles) + ; + + idleFraction = constant(1.0) - notIdleFraction; +} + +void +BaseSimpleCPU::resetStats() +{ + startNumInst = numInst; + // notIdleFraction = (_status != Idle); +} + +void +BaseSimpleCPU::serialize(ostream &os) +{ + BaseCPU::serialize(os); + SERIALIZE_SCALAR(inst); + nameOut(os, csprintf("%s.xc", name())); + thread->serialize(os); +} + +void +BaseSimpleCPU::unserialize(Checkpoint *cp, const string §ion) +{ + BaseCPU::unserialize(cp, section); + UNSERIALIZE_SCALAR(inst); + thread->unserialize(cp, csprintf("%s.xc", section)); +} + +void +change_thread_state(int thread_number, int activate, int priority) +{ +} + +Fault +BaseSimpleCPU::copySrcTranslate(Addr src) +{ +#if 0 + static bool no_warn = true; + int blk_size = (dcacheInterface) ? dcacheInterface->getBlockSize() : 64; + // Only support block sizes of 64 atm. + assert(blk_size == 64); + int offset = src & (blk_size - 1); + + // Make sure block doesn't span page + if (no_warn && + (src & PageMask) != ((src + blk_size) & PageMask) && + (src >> 40) != 0xfffffc) { + warn("Copied block source spans pages %x.", src); + no_warn = false; + } + + memReq->reset(src & ~(blk_size - 1), blk_size); + + // translate to physical address + Fault fault = thread->translateDataReadReq(req); + + if (fault == NoFault) { + thread->copySrcAddr = src; + thread->copySrcPhysAddr = memReq->paddr + offset; + } else { + assert(!fault->isAlignmentFault()); + + thread->copySrcAddr = 0; + thread->copySrcPhysAddr = 0; + } + return fault; +#else + return NoFault; +#endif +} + +Fault +BaseSimpleCPU::copy(Addr dest) +{ +#if 0 + static bool no_warn = true; + int blk_size = (dcacheInterface) ? dcacheInterface->getBlockSize() : 64; + // Only support block sizes of 64 atm. + assert(blk_size == 64); + uint8_t data[blk_size]; + //assert(thread->copySrcAddr); + int offset = dest & (blk_size - 1); + + // Make sure block doesn't span page + if (no_warn && + (dest & PageMask) != ((dest + blk_size) & PageMask) && + (dest >> 40) != 0xfffffc) { + no_warn = false; + warn("Copied block destination spans pages %x. ", dest); + } + + memReq->reset(dest & ~(blk_size -1), blk_size); + // translate to physical address + Fault fault = thread->translateDataWriteReq(req); + + if (fault == NoFault) { + Addr dest_addr = memReq->paddr + offset; + // Need to read straight from memory since we have more than 8 bytes. + memReq->paddr = thread->copySrcPhysAddr; + thread->mem->read(memReq, data); + memReq->paddr = dest_addr; + thread->mem->write(memReq, data); + if (dcacheInterface) { + memReq->cmd = Copy; + memReq->completionEvent = NULL; + memReq->paddr = thread->copySrcPhysAddr; + memReq->dest = dest_addr; + memReq->size = 64; + memReq->time = curTick; + memReq->flags &= ~INST_READ; + dcacheInterface->access(memReq); + } + } + else + assert(!fault->isAlignmentFault()); + + return fault; +#else + panic("copy not implemented"); + return NoFault; +#endif +} + +#if FULL_SYSTEM +Addr +BaseSimpleCPU::dbg_vtophys(Addr addr) +{ + return vtophys(tc, addr); +} +#endif // FULL_SYSTEM + +#if FULL_SYSTEM +void +BaseSimpleCPU::post_interrupt(int int_num, int index) +{ + BaseCPU::post_interrupt(int_num, index); + + if (thread->status() == ThreadContext::Suspended) { + DPRINTF(IPI,"Suspended Processor awoke\n"); + thread->activate(); + } +} +#endif // FULL_SYSTEM + +void +BaseSimpleCPU::checkForInterrupts() +{ +#if FULL_SYSTEM + if (checkInterrupts && check_interrupts() && !thread->inPalMode()) { + int ipl = 0; + int summary = 0; + checkInterrupts = false; + + if (thread->readMiscReg(IPR_SIRR)) { + for (int i = INTLEVEL_SOFTWARE_MIN; + i < INTLEVEL_SOFTWARE_MAX; i++) { + if (thread->readMiscReg(IPR_SIRR) & (ULL(1) << i)) { + // See table 4-19 of 21164 hardware reference + ipl = (i - INTLEVEL_SOFTWARE_MIN) + 1; + summary |= (ULL(1) << i); + } + } + } + + uint64_t interrupts = thread->cpu->intr_status(); + for (int i = INTLEVEL_EXTERNAL_MIN; + i < INTLEVEL_EXTERNAL_MAX; i++) { + if (interrupts & (ULL(1) << i)) { + // See table 4-19 of 21164 hardware reference + ipl = i; + summary |= (ULL(1) << i); + } + } + + if (thread->readMiscReg(IPR_ASTRR)) + panic("asynchronous traps not implemented\n"); + + if (ipl && ipl > thread->readMiscReg(IPR_IPLR)) { + thread->setMiscReg(IPR_ISR, summary); + thread->setMiscReg(IPR_INTID, ipl); + + Fault(new InterruptFault)->invoke(tc); + + DPRINTF(Flow, "Interrupt! IPLR=%d ipl=%d summary=%x\n", + thread->readMiscReg(IPR_IPLR), ipl, summary); + } + } +#endif +} + + +Fault +BaseSimpleCPU::setupFetchRequest(Request *req) +{ + // set up memory request for instruction fetch + DPRINTF(Fetch,"Fetch: PC:%08p NPC:%08p NNPC:%08p\n",thread->readPC(), + thread->readNextPC(),thread->readNextNPC()); + + req->setVirt(0, thread->readPC() & ~3, sizeof(MachInst), + (FULL_SYSTEM && (thread->readPC() & 1)) ? PHYSICAL : 0, + thread->readPC()); + + Fault fault = thread->translateInstReq(req); + + return fault; +} + + +void +BaseSimpleCPU::preExecute() +{ + // maintain $r0 semantics + thread->setIntReg(ZeroReg, 0); +#if THE_ISA == ALPHA_ISA + thread->setFloatReg(ZeroReg, 0.0); +#endif // ALPHA_ISA + + // keep an instruction count + numInst++; + numInsts++; + + thread->funcExeInst++; + + // check for instruction-count-based events + comInstEventQueue[0]->serviceEvents(numInst); + + // decode the instruction + inst = gtoh(inst); + curStaticInst = StaticInst::decode(makeExtMI(inst, thread->readPC())); + + traceData = Trace::getInstRecord(curTick, tc, this, curStaticInst, + thread->readPC()); + + DPRINTF(Decode,"Decode: Decoded %s instruction (opcode: 0x%x): 0x%x\n", + curStaticInst->getName(), curStaticInst->getOpcode(), + curStaticInst->machInst); + +#if FULL_SYSTEM + thread->setInst(inst); +#endif // FULL_SYSTEM +} + +void +BaseSimpleCPU::postExecute() +{ +#if FULL_SYSTEM - if (system->kernelBinning->fnbin) { - assert(thread->getKernelStats()); - system->kernelBinning->execute(tc, inst); - } - + if (thread->profile) { + bool usermode = + (thread->readMiscReg(AlphaISA::IPR_DTB_CM) & 0x18) != 0; + thread->profilePC = usermode ? 1 : thread->readPC(); + ProfileNode *node = thread->profile->consume(tc, inst); + if (node) + thread->profileNode = node; + } +#endif + + if (curStaticInst->isMemRef()) { + numMemRefs++; + } + + if (curStaticInst->isLoad()) { + ++numLoad; + comLoadEventQueue[0]->serviceEvents(numLoad); + } + + traceFunctions(thread->readPC()); + + if (traceData) { + traceData->finalize(); + } +} + + +void +BaseSimpleCPU::advancePC(Fault fault) +{ + if (fault != NoFault) { +#if FULL_SYSTEM + fault->invoke(tc); +#else // !FULL_SYSTEM + fatal("fault (%s) detected @ PC %08p", fault->name(), thread->readPC()); +#endif // FULL_SYSTEM + } + else { + // go to the next instruction + thread->setPC(thread->readNextPC()); +#if THE_ISA == ALPHA_ISA + thread->setNextPC(thread->readNextPC() + sizeof(MachInst)); +#else + thread->setNextPC(thread->readNextNPC()); + thread->setNextNPC(thread->readNextNPC() + sizeof(MachInst)); +#endif + + } + +#if FULL_SYSTEM + Addr oldpc; + do { + oldpc = thread->readPC(); + system->pcEventQueue.service(tc); + } while (oldpc != thread->readPC()); +#endif +} + diff --cc src/kern/kernel_stats.cc index 2ba120b6f,000000000..f7868b50f mode 100644,000000..100644 --- a/src/kern/kernel_stats.cc +++ b/src/kern/kernel_stats.cc @@@ -1,302 -1,0 +1,290 @@@ +/* + * Copyright (c) 2004-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Lisa Hsu + * Nathan Binkert + */ + +#include +#include +#include + +#include "arch/alpha/osfpal.hh" +#include "base/trace.hh" +#include "cpu/thread_context.hh" +#include "kern/kernel_stats.hh" +#include "kern/tru64/tru64_syscalls.hh" +#include "sim/system.hh" + +using namespace std; +using namespace Stats; + +namespace Kernel { + - const char *modestr[] = { "kernel", "user", "idle", "interrupt" }; ++const char *modestr[] = { "kernel", "user", "idle" }; + +Statistics::Statistics(System *system) + : idleProcess((Addr)-1), themode(kernel), lastModeTick(0), + iplLast(0), iplLastTick(0) +{ - bin_int = system->params()->bin_int; +} + +void +Statistics::regStats(const string &_name) +{ + myname = _name; + + _arm + .name(name() + ".inst.arm") + .desc("number of arm instructions executed") + ; + + _quiesce + .name(name() + ".inst.quiesce") + .desc("number of quiesce instructions executed") + ; + + _ivlb + .name(name() + ".inst.ivlb") + .desc("number of ivlb instructions executed") + ; + + _ivle + .name(name() + ".inst.ivle") + .desc("number of ivle instructions executed") + ; + + _hwrei + .name(name() + ".inst.hwrei") + .desc("number of hwrei instructions executed") + ; + + _iplCount + .init(32) + .name(name() + ".ipl_count") + .desc("number of times we switched to this ipl") + .flags(total | pdf | nozero | nonan) + ; + + _iplGood + .init(32) + .name(name() + ".ipl_good") + .desc("number of times we switched to this ipl from a different ipl") + .flags(total | pdf | nozero | nonan) + ; + + _iplTicks + .init(32) + .name(name() + ".ipl_ticks") + .desc("number of cycles we spent at this ipl") + .flags(total | pdf | nozero | nonan) + ; + + _iplUsed + .name(name() + ".ipl_used") + .desc("fraction of swpipl calls that actually changed the ipl") + .flags(total | nozero | nonan) + ; + + _iplUsed = _iplGood / _iplCount; + + _callpal + .init(256) + .name(name() + ".callpal") + .desc("number of callpals executed") + .flags(total | pdf | nozero | nonan) + ; + + for (int i = 0; i < PAL::NumCodes; ++i) { + const char *str = PAL::name(i); + if (str) + _callpal.subname(i, str); + } + + _syscall + .init(SystemCalls::Number) + .name(name() + ".syscall") + .desc("number of syscalls executed") + .flags(total | pdf | nozero | nonan) + ; + + for (int i = 0; i < SystemCalls::Number; ++i) { + const char *str = SystemCalls::name(i); + if (str) { + _syscall.subname(i, str); + } + } + + _mode + .init(cpu_mode_num) + .name(name() + ".mode_switch") + .desc("number of protection mode switches") + ; + + for (int i = 0; i < cpu_mode_num; ++i) + _mode.subname(i, modestr[i]); + + _modeGood + .init(cpu_mode_num) + .name(name() + ".mode_good") + ; + + for (int i = 0; i < cpu_mode_num; ++i) + _modeGood.subname(i, modestr[i]); + + _modeFraction + .name(name() + ".mode_switch_good") + .desc("fraction of useful protection mode switches") + .flags(total) + ; + + for (int i = 0; i < cpu_mode_num; ++i) + _modeFraction.subname(i, modestr[i]); + + _modeFraction = _modeGood / _mode; + + _modeTicks + .init(cpu_mode_num) + .name(name() + ".mode_ticks") + .desc("number of ticks spent at the given mode") + .flags(pdf) + ; + for (int i = 0; i < cpu_mode_num; ++i) + _modeTicks.subname(i, modestr[i]); + + _swap_context + .name(name() + ".swap_context") + .desc("number of times the context was actually changed") + ; +} + +void +Statistics::setIdleProcess(Addr idlepcbb, ThreadContext *tc) +{ - assert(themode == kernel || themode == interrupt); ++ assert(themode == kernel); + idleProcess = idlepcbb; + themode = idle; + changeMode(themode, tc); +} + +void +Statistics::changeMode(cpu_mode newmode, ThreadContext *tc) +{ + _mode[newmode]++; + + if (newmode == themode) + return; + + DPRINTF(Context, "old mode=%-8s new mode=%-8s\n", + modestr[themode], modestr[newmode]); + + _modeGood[newmode]++; + _modeTicks[themode] += curTick - lastModeTick; + - tc->getSystemPtr()->kernelBinning->changeMode(newmode); - + lastModeTick = curTick; + themode = newmode; +} + +void +Statistics::swpipl(int ipl) +{ + assert(ipl >= 0 && ipl <= 0x1f && "invalid IPL\n"); + + _iplCount[ipl]++; + + if (ipl == iplLast) + return; + + _iplGood[ipl]++; + _iplTicks[iplLast] += curTick - iplLastTick; + iplLastTick = curTick; + iplLast = ipl; +} + +void +Statistics::mode(cpu_mode newmode, ThreadContext *tc) +{ + Addr pcbb = tc->readMiscReg(AlphaISA::IPR_PALtemp23); + - if ((newmode == kernel || newmode == interrupt) && - pcbb == idleProcess) ++ if (newmode == kernel && pcbb == idleProcess) + newmode = idle; + - if (bin_int == false && newmode == interrupt) - newmode = kernel; - + changeMode(newmode, tc); +} + +void +Statistics::context(Addr oldpcbb, Addr newpcbb, ThreadContext *tc) +{ + assert(themode != user); + + _swap_context++; + changeMode(newpcbb == idleProcess ? idle : kernel, tc); +} + +void +Statistics::callpal(int code, ThreadContext *tc) +{ + if (!PAL::name(code)) + return; + + _callpal[code]++; + + switch (code) { + case PAL::callsys: { + int number = tc->readIntReg(0); + if (SystemCalls::validSyscallNumber(number)) { + int cvtnum = SystemCalls::convert(number); + _syscall[cvtnum]++; + } + } break; - - case PAL::swpctx: - if (tc->getSystemPtr()->kernelBinning) - tc->getSystemPtr()->kernelBinning->palSwapContext(tc); - break; + } +} + +void +Statistics::serialize(ostream &os) +{ + int exemode = themode; + SERIALIZE_SCALAR(exemode); + SERIALIZE_SCALAR(idleProcess); + SERIALIZE_SCALAR(iplLast); + SERIALIZE_SCALAR(iplLastTick); + SERIALIZE_SCALAR(lastModeTick); +} + +void +Statistics::unserialize(Checkpoint *cp, const string §ion) +{ + int exemode; + UNSERIALIZE_SCALAR(exemode); + UNSERIALIZE_SCALAR(idleProcess); + UNSERIALIZE_SCALAR(iplLast); + UNSERIALIZE_SCALAR(iplLastTick); + UNSERIALIZE_SCALAR(lastModeTick); + themode = (cpu_mode)exemode; +} + +/* end namespace Kernel */ } diff --cc src/kern/kernel_stats.hh index 781b6f6da,000000000..c691ad8cf mode 100644,000000..100644 --- a/src/kern/kernel_stats.hh +++ b/src/kern/kernel_stats.hh @@@ -1,195 -1,0 +1,117 @@@ +/* + * Copyright (c) 2004-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Lisa Hsu + * Nathan Binkert + */ + +#ifndef __KERNEL_STATS_HH__ +#define __KERNEL_STATS_HH__ + +#include +#include +#include +#include + +#include "cpu/static_inst.hh" + +class BaseCPU; +class ThreadContext; +class FnEvent; +// What does kernel stats expect is included? +class System; + +namespace Kernel { + - enum cpu_mode { kernel, user, idle, interrupt, cpu_mode_num }; ++enum cpu_mode { kernel, user, idle, cpu_mode_num }; +extern const char *modestr[]; + - class Binning - { - private: - std::string myname; - System *system; - - private: - // lisa's binning stuff - struct fnCall - { - Stats::MainBin *myBin; - std::string name; - }; - - struct SWContext - { - Counter calls; - std::stack callStack; - }; - - std::map fnBins; - std::map swCtxMap; - - std::multimap callerMap; - void populateMap(std::string caller, std::string callee); - - std::vector fnEvents; - - Stats::Scalar<> fnCalls; - - Stats::MainBin *getBin(const std::string &name); - bool findCaller(std::string, std::string) const; - - SWContext *findContext(Addr pcb); - bool addContext(Addr pcb, SWContext *ctx) - { - return (swCtxMap.insert(std::make_pair(pcb, ctx))).second; - } - - void remContext(Addr pcb) - { - swCtxMap.erase(pcb); - } - - void dumpState() const; - - SWContext *swctx; - std::vector binned_fns; - - private: - Stats::MainBin *modeBin[cpu_mode_num]; - - public: - const bool bin; - const bool fnbin; - - cpu_mode themode; - void palSwapContext(ThreadContext *tc); - void execute(ThreadContext *tc, StaticInstPtr inst); - void call(ThreadContext *tc, Stats::MainBin *myBin); - void changeMode(cpu_mode mode); - - public: - Binning(System *sys); - virtual ~Binning(); - - const std::string name() const { return myname; } - void regStats(const std::string &name); - - public: - virtual void serialize(std::ostream &os); - virtual void unserialize(Checkpoint *cp, const std::string §ion); - }; - +class Statistics : public Serializable +{ - private: - friend class Binning; - + private: + std::string myname; + + Addr idleProcess; + cpu_mode themode; + Tick lastModeTick; - bool bin_int; + + void changeMode(cpu_mode newmode, ThreadContext *tc); + + private: + Stats::Scalar<> _arm; + Stats::Scalar<> _quiesce; + Stats::Scalar<> _ivlb; + Stats::Scalar<> _ivle; + Stats::Scalar<> _hwrei; + + Stats::Vector<> _iplCount; + Stats::Vector<> _iplGood; + Stats::Vector<> _iplTicks; + Stats::Formula _iplUsed; + + Stats::Vector<> _callpal; + Stats::Vector<> _syscall; +// Stats::Vector<> _faults; + + Stats::Vector<> _mode; + Stats::Vector<> _modeGood; + Stats::Formula _modeFraction; + Stats::Vector<> _modeTicks; + + Stats::Scalar<> _swap_context; + + private: + int iplLast; + Tick iplLastTick; + + public: + Statistics(System *system); + + const std::string name() const { return myname; } + void regStats(const std::string &name); + + public: + void arm() { _arm++; } + void quiesce() { _quiesce++; } + void ivlb() { _ivlb++; } + void ivle() { _ivle++; } + void hwrei() { _hwrei++; } + void swpipl(int ipl); + void mode(cpu_mode newmode, ThreadContext *tc); + void context(Addr oldpcbb, Addr newpcbb, ThreadContext *tc); + void callpal(int code, ThreadContext *tc); + + void setIdleProcess(Addr idle, ThreadContext *tc); + + public: + virtual void serialize(std::ostream &os); + virtual void unserialize(Checkpoint *cp, const std::string §ion); +}; + +/* end namespace Kernel */ } + +#endif // __KERNEL_STATS_HH__ diff --cc src/kern/system_events.cc index fe3805ce2,000000000..177ce96d1 mode 100644,000000..100644 --- a/src/kern/system_events.cc +++ b/src/kern/system_events.cc @@@ -1,97 -1,0 +1,65 @@@ +/* + * Copyright (c) 2004-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Lisa Hsu + * Nathan Binkert + */ + +#include "cpu/base.hh" +#include "cpu/thread_context.hh" +#include "kern/kernel_stats.hh" +#include "kern/system_events.hh" +#include "sim/system.hh" + +using namespace TheISA; + +void +SkipFuncEvent::process(ThreadContext *tc) +{ + Addr newpc = tc->readIntReg(ReturnAddressReg); + + DPRINTF(PCEvent, "skipping %s: pc=%x, newpc=%x\n", description, + tc->readPC(), newpc); + + tc->setPC(newpc); + tc->setNextPC(tc->readPC() + sizeof(TheISA::MachInst)); +/* + BranchPred *bp = tc->getCpuPtr()->getBranchPred(); + if (bp != NULL) { + bp->popRAS(tc->getThreadNum()); + } +*/ +} + - - FnEvent::FnEvent(PCEventQueue *q, const std::string &desc, Addr addr, - Stats::MainBin *bin) - : PCEvent(q, desc, addr), _name(desc), mybin(bin) - { - } - - void - FnEvent::process(ThreadContext *tc) - { - if (tc->misspeculating()) - return; - - tc->getSystemPtr()->kernelBinning->call(tc, mybin); - } - +void +IdleStartEvent::process(ThreadContext *tc) +{ + if (tc->getKernelStats()) + tc->getKernelStats()->setIdleProcess( + tc->readMiscReg(AlphaISA::IPR_PALtemp23), tc); + remove(); +} - - void - InterruptStartEvent::process(ThreadContext *tc) - { - if (tc->getKernelStats()) - tc->getKernelStats()->mode(Kernel::interrupt, tc); - } - - void - InterruptEndEvent::process(ThreadContext *tc) - { - // We go back to kernel, if we are user, inside the rti - // pal code we will get switched to user because of the ICM write - if (tc->getKernelStats()) - tc->getKernelStats()->mode(Kernel::kernel, tc); - } diff --cc src/kern/system_events.hh index 05c878577,000000000..ccd6bd9a4 mode 100644,000000..100644 --- a/src/kern/system_events.hh +++ b/src/kern/system_events.hh @@@ -1,89 -1,0 +1,57 @@@ +/* + * Copyright (c) 2004-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Lisa Hsu + * Ali Saidi + */ + +#ifndef __SYSTEM_EVENTS_HH__ +#define __SYSTEM_EVENTS_HH__ + +#include "cpu/pc_event.hh" + +class System; + +class SkipFuncEvent : public PCEvent +{ + public: + SkipFuncEvent(PCEventQueue *q, const std::string &desc, Addr addr) + : PCEvent(q, desc, addr) + {} + virtual void process(ThreadContext *tc); +}; + - class FnEvent : public PCEvent - { - public: - FnEvent(PCEventQueue *q, const std::string &desc, Addr addr, - Stats::MainBin *bin); - virtual void process(ThreadContext *tc); - std::string myname() const { return _name; } - - private: - std::string _name; - Stats::MainBin *mybin; - }; - +class IdleStartEvent : public PCEvent +{ + public: + IdleStartEvent(PCEventQueue *q, const std::string &desc, Addr addr) + : PCEvent(q, desc, addr) + {} + virtual void process(ThreadContext *tc); +}; + - class InterruptStartEvent : public PCEvent - { - public: - InterruptStartEvent(PCEventQueue *q, const std::string &desc, Addr addr) - : PCEvent(q, desc, addr) - {} - virtual void process(ThreadContext *tc); - }; - - class InterruptEndEvent : public PCEvent - { - public: - InterruptEndEvent(PCEventQueue *q, const std::string &desc, Addr addr) - : PCEvent(q, desc, addr) - {} - virtual void process(ThreadContext *tc); - }; - - +#endif // __SYSTEM_EVENTS_HH__ diff --cc src/python/m5/objects/System.py index a8063a274,000000000..9a1e1d690 mode 100644,000000..100644 --- a/src/python/m5/objects/System.py +++ b/src/python/m5/objects/System.py @@@ -1,22 -1,0 +1,20 @@@ +from m5 import build_env +from m5.config import * + +class System(SimObject): + type = 'System' + physmem = Param.PhysicalMemory(Parent.any, "phsyical memory") + if build_env['FULL_SYSTEM']: + boot_cpu_frequency = Param.Frequency(Self.cpu[0].clock.frequency, + "boot processor frequency") + init_param = Param.UInt64(0, "numerical value to pass into simulator") - bin = Param.Bool(False, "is this system binned") - binned_fns = VectorParam.String([], "functions broken down and binned") + boot_osflags = Param.String("a", "boot flags to pass to the kernel") + kernel = Param.String("file that contains the kernel code") + readfile = Param.String("", "file to read startup script from") + +class AlphaSystem(System): + type = 'AlphaSystem' + console = Param.String("file that contains the console code") + pal = Param.String("file that contains palcode") + system_type = Param.UInt64("Type of system we are emulating") + system_rev = Param.UInt64("Revision of system we are emulating") diff --cc src/sim/system.cc index 7953607d5,000000000..b3c7870fd mode 100644,000000..100644 --- a/src/sim/system.cc +++ b/src/sim/system.cc @@@ -1,300 -1,0 +1,286 @@@ +/* + * Copyright (c) 2003-2006 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Steve Reinhardt + * Lisa Hsu + * Nathan Binkert + * Ali Saidi + */ + +#include "arch/isa_traits.hh" +#include "base/loader/object_file.hh" +#include "base/loader/symtab.hh" +#include "base/trace.hh" +#include "cpu/thread_context.hh" +#include "mem/mem_object.hh" +#include "mem/physical.hh" +#include "sim/builder.hh" +#include "sim/byteswap.hh" +#include "sim/system.hh" +#if FULL_SYSTEM +#include "arch/vtophys.hh" +#include "base/remote_gdb.hh" +#include "kern/kernel_stats.hh" +#endif + +using namespace std; +using namespace TheISA; + +vector System::systemList; + +int System::numSystemsRunning = 0; + +System::System(Params *p) + : SimObject(p->name), physmem(p->physmem), numcpus(0), +#if FULL_SYSTEM + init_param(p->init_param), + functionalPort(p->name + "-fport"), + virtPort(p->name + "-vport"), +#else + page_ptr(0), +#endif + _params(p) +{ + // add self to global system list + systemList.push_back(this); + +#if FULL_SYSTEM + kernelSymtab = new SymbolTable; + debugSymbolTable = new SymbolTable; + + + /** + * Get a functional port to memory + */ + Port *mem_port; + mem_port = physmem->getPort("functional"); + functionalPort.setPeer(mem_port); + mem_port->setPeer(&functionalPort); + + mem_port = physmem->getPort("functional"); + virtPort.setPeer(mem_port); + mem_port->setPeer(&virtPort); + + + /** + * Load the kernel code into memory + */ + // Load kernel code + kernel = createObjectFile(params()->kernel_path); + if (kernel == NULL) + fatal("Could not load kernel file %s", params()->kernel_path); + + // Load program sections into memory + kernel->loadSections(&functionalPort, LoadAddrMask); + + // setup entry points + kernelStart = kernel->textBase(); + kernelEnd = kernel->bssBase() + kernel->bssSize(); + kernelEntry = kernel->entryPoint(); + + // load symbols + if (!kernel->loadGlobalSymbols(kernelSymtab)) + panic("could not load kernel symbols\n"); + + if (!kernel->loadLocalSymbols(kernelSymtab)) + panic("could not load kernel local symbols\n"); + + if (!kernel->loadGlobalSymbols(debugSymbolTable)) + panic("could not load kernel symbols\n"); + + if (!kernel->loadLocalSymbols(debugSymbolTable)) + panic("could not load kernel local symbols\n"); + + DPRINTF(Loader, "Kernel start = %#x\n", kernelStart); + DPRINTF(Loader, "Kernel end = %#x\n", kernelEnd); + DPRINTF(Loader, "Kernel entry = %#x\n", kernelEntry); + DPRINTF(Loader, "Kernel loaded...\n"); + + kernelBinning = new Kernel::Binning(this); +#endif // FULL_SYSTEM + + // increment the number of running systms + numSystemsRunning++; +} + +System::~System() +{ +#if FULL_SYSTEM + delete kernelSymtab; + delete kernel; - - delete kernelBinning; +#else + panic("System::fixFuncEventAddr needs to be rewritten " + "to work with syscall emulation"); +#endif // FULL_SYSTEM} +} + +#if FULL_SYSTEM + + +int rgdb_wait = -1; + +#endif // FULL_SYSTEM + +int +System::registerThreadContext(ThreadContext *tc, int id) +{ + if (id == -1) { + for (id = 0; id < threadContexts.size(); id++) { + if (!threadContexts[id]) + break; + } + } + + if (threadContexts.size() <= id) + threadContexts.resize(id + 1); + + if (threadContexts[id]) + panic("Cannot have two CPUs with the same id (%d)\n", id); + + threadContexts[id] = tc; + numcpus++; + +#if FULL_SYSTEM + RemoteGDB *rgdb = new RemoteGDB(this, tc); + GDBListener *gdbl = new GDBListener(rgdb, 7000 + id); + gdbl->listen(); + /** + * Uncommenting this line waits for a remote debugger to connect + * to the simulator before continuing. + */ + if (rgdb_wait != -1 && rgdb_wait == id) + gdbl->accept(); + + if (remoteGDB.size() <= id) { + remoteGDB.resize(id + 1); + } + + remoteGDB[id] = rgdb; +#endif // FULL_SYSTEM + + return id; +} + +void +System::startup() +{ + int i; + for (i = 0; i < threadContexts.size(); i++) + threadContexts[i]->activate(0); +} + +void +System::replaceThreadContext(ThreadContext *tc, int id) +{ + if (id >= threadContexts.size()) { + panic("replaceThreadContext: bad id, %d >= %d\n", + id, threadContexts.size()); + } + + threadContexts[id] = tc; +#if FULL_SYSTEM + remoteGDB[id]->replaceThreadContext(tc); +#endif // FULL_SYSTEM +} + +#if !FULL_SYSTEM +Addr +System::new_page() +{ + Addr return_addr = page_ptr << LogVMPageSize; + ++page_ptr; + return return_addr; +} +#endif + - void - System::regStats() - { - #if FULL_SYSTEM - kernelBinning->regStats(name() + ".kern"); - #endif // FULL_SYSTEM - } - +void +System::serialize(ostream &os) +{ +#if FULL_SYSTEM - kernelBinning->serialize(os); - + kernelSymtab->serialize("kernel_symtab", os); +#endif // FULL_SYSTEM +} + + +void +System::unserialize(Checkpoint *cp, const string §ion) +{ +#if FULL_SYSTEM - kernelBinning->unserialize(cp, section); - + kernelSymtab->unserialize("kernel_symtab", cp, section); +#endif // FULL_SYSTEM +} + +void +System::printSystems() +{ + vector::iterator i = systemList.begin(); + vector::iterator end = systemList.end(); + for (; i != end; ++i) { + System *sys = *i; + cerr << "System " << sys->name() << ": " << hex << sys << endl; + } +} + +extern "C" +void +printSystems() +{ + System::printSystems(); +} + +#if FULL_SYSTEM + +// In full system mode, only derived classes (e.g. AlphaLinuxSystem) +// can be created directly. + +DEFINE_SIM_OBJECT_CLASS_NAME("System", System) + +#else + +BEGIN_DECLARE_SIM_OBJECT_PARAMS(System) + + SimObjectParam physmem; + +END_DECLARE_SIM_OBJECT_PARAMS(System) + +BEGIN_INIT_SIM_OBJECT_PARAMS(System) + + INIT_PARAM(physmem, "physical memory") + +END_INIT_SIM_OBJECT_PARAMS(System) + +CREATE_SIM_OBJECT(System) +{ + System::Params *p = new System::Params; + p->name = getInstanceName(); + p->physmem = physmem; + return new System(p); +} + +REGISTER_SIM_OBJECT("System", System) + +#endif diff --cc src/sim/system.hh index 3a9fdc3d2,000000000..059dc92dc mode 100644,000000..100644 --- a/src/sim/system.hh +++ b/src/sim/system.hh @@@ -1,233 -1,0 +1,226 @@@ +/* + * Copyright (c) 2002-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Steve Reinhardt + * Lisa Hsu + * Nathan Binkert + */ + +#ifndef __SYSTEM_HH__ +#define __SYSTEM_HH__ + +#include +#include + +#include "base/loader/symtab.hh" +#include "base/misc.hh" +#include "base/statistics.hh" +#include "cpu/pc_event.hh" +#include "mem/port.hh" +#include "sim/sim_object.hh" +#if FULL_SYSTEM +#include "kern/system_events.hh" +#include "mem/vport.hh" +#endif + +class BaseCPU; +class ThreadContext; +class ObjectFile; +class PhysicalMemory; + +#if FULL_SYSTEM +class Platform; +class GDBListener; +class RemoteGDB; - namespace Kernel { class Binning; } +#endif + +class System : public SimObject +{ + public: + PhysicalMemory *physmem; + PCEventQueue pcEventQueue; + + std::vector threadContexts; + int numcpus; + + int getNumCPUs() + { + if (numcpus != threadContexts.size()) + panic("cpu array not fully populated!"); + + return numcpus; + } + +#if FULL_SYSTEM + Platform *platform; + uint64_t init_param; + + /** Port to physical memory used for writing object files into ram at + * boot.*/ + FunctionalPort functionalPort; + VirtualPort virtPort; + + /** kernel symbol table */ + SymbolTable *kernelSymtab; + + /** Object pointer for the kernel code */ + ObjectFile *kernel; + + /** Begining of kernel code */ + Addr kernelStart; + + /** End of kernel code */ + Addr kernelEnd; + + /** Entry point in the kernel to start at */ + Addr kernelEntry; + - Kernel::Binning *kernelBinning; - +#else + + int page_ptr; + + +#endif // FULL_SYSTEM + + protected: + +#if FULL_SYSTEM + /** + * Fix up an address used to match PCs for hooking simulator + * events on to target function executions. See comment in + * system.cc for details. + */ + virtual Addr fixFuncEventAddr(Addr addr) = 0; + + /** + * Add a function-based event to the given function, to be looked + * up in the specified symbol table. + */ + template + T *System::addFuncEvent(SymbolTable *symtab, const char *lbl) + { + Addr addr = 0; // initialize only to avoid compiler warning + + if (symtab->findAddress(lbl, addr)) { + T *ev = new T(&pcEventQueue, lbl, fixFuncEventAddr(addr)); + return ev; + } + + return NULL; + } + + /** Add a function-based event to kernel code. */ + template + T *System::addKernelFuncEvent(const char *lbl) + { + return addFuncEvent(kernelSymtab, lbl); + } + +#endif + public: +#if FULL_SYSTEM + std::vector remoteGDB; + std::vector gdbListen; + virtual bool breakpoint() = 0; +#endif // FULL_SYSTEM + + public: + struct Params + { + std::string name; + PhysicalMemory *physmem; + +#if FULL_SYSTEM + Tick boot_cpu_frequency; + std::string boot_osflags; + uint64_t init_param; - bool bin; - std::vector binned_fns; - bool bin_int; + + std::string kernel_path; + std::string readfile; +#endif + }; + + protected: + Params *_params; + + public: + System(Params *p); + ~System(); + + void startup(); + + const Params *params() const { return (const Params *)_params; } + + public: + +#if FULL_SYSTEM + /** + * Returns the addess the kernel starts at. + * @return address the kernel starts at + */ + Addr getKernelStart() const { return kernelStart; } + + /** + * Returns the addess the kernel ends at. + * @return address the kernel ends at + */ + Addr getKernelEnd() const { return kernelEnd; } + + /** + * Returns the addess the entry point to the kernel code. + * @return entry point of the kernel code + */ + Addr getKernelEntry() const { return kernelEntry; } + +#else + + Addr new_page(); + +#endif // FULL_SYSTEM + + int registerThreadContext(ThreadContext *tc, int tcIndex); + void replaceThreadContext(ThreadContext *tc, int tcIndex); + - void regStats(); + void serialize(std::ostream &os); + void unserialize(Checkpoint *cp, const std::string §ion); + + public: + //////////////////////////////////////////// + // + // STATIC GLOBAL SYSTEM LIST + // + //////////////////////////////////////////// + + static std::vector systemList; + static int numSystemsRunning; + + static void printSystems(); + + +}; + +#endif // __SYSTEM_HH__ diff --cc src/unittest/stattest.cc index 496d1f672,000000000..4e504fde9 mode 100644,000000..100644 --- a/src/unittest/stattest.cc +++ b/src/unittest/stattest.cc @@@ -1,562 -1,0 +1,556 @@@ +/* + * Copyright (c) 2003-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Nathan Binkert + */ + +#include +#include +#include +#include +#include + +#include "base/cprintf.hh" +#include "base/misc.hh" +#include "base/statistics.hh" +#include "base/stats/text.hh" +#include "base/stats/mysql.hh" +#include "sim/host.hh" + +using namespace std; +using namespace Stats; + +Tick curTick = 0; +Tick ticksPerSecond = ULL(2000000000); + +Scalar<> s1; +Scalar<> s2; +Average<> s3; - Scalar s4; - Vector s5; - Distribution s6; - Vector s7; ++Scalar<> s4; ++Vector<> s5; ++Distribution<> s6; ++Vector<> s7; +AverageVector<> s8; +StandardDeviation<> s9; +AverageDeviation<> s10; +Scalar<> s11; +Distribution<> s12; +VectorDistribution<> s13; +VectorStandardDeviation<> s14; +VectorAverageDeviation<> s15; +Vector2d<> s16; + +Formula f1; +Formula f2; +Formula f3; +Value f4; +Value f5; +Formula f6; +Formula f7; + - MainBin bin1("bin1"); - MainBin bin2("bin2"); - +ostream *outputStream = &cout; + +double +testfunc() +{ + return 9.8; +} + +class TestClass { + public: + double operator()() { return 9.7; } +}; + +char *progname = ""; + +void +usage() +{ + panic("incorrect usage.\n" + "usage:\n" + "\t%s [-t [-c] [-d]]\n", progname); +} + +int +main(int argc, char *argv[]) +{ + bool descriptions = false; + bool compat = false; + bool text = false; + string mysql_name; + string mysql_host; + string mysql_user = "binkertn"; + string mysql_passwd; + + char c; + progname = argv[0]; + while ((c = getopt(argc, argv, "cdh:P:p:s:tu:")) != -1) { + switch (c) { + case 'c': + compat = true; + break; + case 'd': + descriptions = true; + break; + case 'h': + mysql_host = optarg; + break; + case 'P': + mysql_passwd = 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); + s8.init(10); + s12.init(1, 100, 13); + s13.init(4, 0, 99, 10); + s14.init(9); + s15.init(10); + s16.init(2, 9); + + s1 + .name("Stat01") + .desc("this is statistic 1") + ; + + s2 + .name("Stat02") + .desc("this is statistic 2") + .prereq(s11) + ; + + s3 + .name("Stat03") + .desc("this is statistic 3") + .prereq(f7) + ; + + s4 + .name("Stat04") + .desc("this is statistic 4") + .prereq(s11) + ; + + s5 + .name("Stat05") + .desc("this is statistic 5") + .prereq(s11) + .subname(0, "foo1") + .subname(1, "foo2") + .subname(2, "foo3") + .subname(3, "foo4") + .subname(4, "foo5") + ; + + s6 + .name("Stat06") + .desc("this is statistic 6") + .prereq(s11) + ; + + s7 + .name("Stat07") + .desc("this is statistic 7") + .precision(1) + .flags(pdf | total) + .prereq(s11) + ; + + s8 + .name("Stat08") + .desc("this is statistic 8") + .precision(2) + .prereq(s11) + .subname(4, "blarg") + ; + + s9 + .name("Stat09") + .desc("this is statistic 9") + .precision(4) + .prereq(s11) + ; + + s10 + .name("Stat10") + .desc("this is statistic 10") + .prereq(s11) + ; + + s12 + .name("Stat12") + .desc("this is statistic 12") + ; + + s13 + .name("Stat13") + .desc("this is statistic 13") + ; + + s14 + .name("Stat14") + .desc("this is statistic 14") + ; + + s15 + .name("Stat15") + .desc("this is statistic 15") + ; + + s16 + .name("Stat16") + .desc("this is statistic 16") + .flags(total) + .subname(0, "sub0") + .subname(1, "sub1") + .ysubname(0, "y0") + .ysubname(1, "y1") + ; + + f1 + .name("Formula1") + .desc("this is formula 1") + .prereq(s11) + ; + + f2 + .name("Formula2") + .desc("this is formula 2") + .prereq(s11) + .precision(1) + ; + + f3 + .name("Formula3") + .desc("this is formula 3") + .prereq(s11) + .subname(0, "bar1") + .subname(1, "bar2") + .subname(2, "bar3") + .subname(3, "bar4") + .subname(4, "bar5") + ; + + f4 + .functor(testfunc) + .name("Formula4") + .desc("this is formula 4") + ; + + TestClass testclass; + f5 + .functor(testclass) + .name("Formula5") + .desc("this is formula 5") + ; + + f6 + .name("Formula6") + .desc("this is formula 6") + ; + + f1 = s1 + s2; + f2 = (-s1) / (-s2) * (-s3 + ULL(100) + s4); + f3 = sum(s5) * s7; + f6 += constant(10.0); + f6 += s5[3]; + f7 = constant(1); + + check(); + reset(); + - bin1.activate(); - + s16[1][0] = 1; + s16[0][1] = 3; + s16[0][0] = 2; + s16[1][1] = 9; + s16[1][1] += 9; + s16[1][8] += 8; + s16[1][7] += 7; + s16[1][6] += 6; + s16[1][5] += 5; + s16[1][4] += 4; + + s11 = 1; + s3 = 9; + s8[3] = 9; + s15[0].sample(1234); + s15[1].sample(1234); + s15[2].sample(1234); + s15[3].sample(1234); + s15[4].sample(1234); + s15[5].sample(1234); + s15[6].sample(1234); + s15[7].sample(1234); + s15[8].sample(1234); + s15[9].sample(1234); + + s10.sample(1000000000); + curTick += ULL(1000000); + s10.sample(100000); + s10.sample(100000); + s10.sample(100000); + s10.sample(100000); + s10.sample(100000); + s10.sample(100000); + s10.sample(100000); + s10.sample(100000); + s10.sample(100000); + s10.sample(100000); + s10.sample(100000); + s10.sample(100000); + s10.sample(100000); + s13[0].sample(12); + s13[1].sample(29); + s13[2].sample(12); + s13[3].sample(29); + s13[0].sample(42); + s13[1].sample(29); + s13[2].sample(42); + s13[3].sample(32); + s13[0].sample(52); + s13[1].sample(49); + s13[2].sample(42); + s13[3].sample(25); + s13[0].sample(32); + s13[1].sample(49); + s13[2].sample(22); + s13[3].sample(49); + s13[0].sample(62); + s13[1].sample(99); + s13[2].sample(72); + s13[3].sample(23); + s13[0].sample(52); + s13[1].sample(78); + s13[2].sample(69); + s13[3].sample(49); + + s14[0].sample(1234); + s14[1].sample(4134); + s14[4].sample(1213); + s14[3].sample(1124); + s14[2].sample(1243); + s14[7].sample(1244); + s14[4].sample(7234); + s14[2].sample(9234); + s14[3].sample(1764); + s14[7].sample(1564); + s14[3].sample(3234); + s14[1].sample(2234); + s14[5].sample(1234); + s14[2].sample(4334); + s14[2].sample(1234); + s14[4].sample(4334); + s14[6].sample(1234); + s14[8].sample(8734); + s14[1].sample(5234); + s14[3].sample(8234); + s14[7].sample(5234); + s14[4].sample(4434); + s14[3].sample(7234); + s14[2].sample(1934); + s14[1].sample(9234); + s14[5].sample(5634); + s14[3].sample(1264); + s14[7].sample(5223); + s14[0].sample(1234); + s14[0].sample(5434); + s14[3].sample(8634); + s14[1].sample(1234); + + + s15[0].sample(1234); + s15[1].sample(4134); + curTick += ULL(1000000); + s15[4].sample(1213); + curTick += ULL(1000000); + s15[3].sample(1124); + curTick += ULL(1000000); + s15[2].sample(1243); + curTick += ULL(1000000); + s15[7].sample(1244); + curTick += ULL(1000000); + s15[4].sample(7234); + s15[2].sample(9234); + s15[3].sample(1764); + s15[7].sample(1564); + s15[3].sample(3234); + s15[1].sample(2234); + curTick += ULL(1000000); + s15[5].sample(1234); + curTick += ULL(1000000); + s15[9].sample(4334); + curTick += ULL(1000000); + s15[2].sample(1234); + curTick += ULL(1000000); + s15[4].sample(4334); + s15[6].sample(1234); + curTick += ULL(1000000); + s15[8].sample(8734); + curTick += ULL(1000000); + s15[1].sample(5234); + curTick += ULL(1000000); + s15[3].sample(8234); + curTick += ULL(1000000); + s15[7].sample(5234); + s15[4].sample(4434); + s15[3].sample(7234); + s15[2].sample(1934); + s15[1].sample(9234); + curTick += ULL(1000000); + s15[5].sample(5634); + s15[3].sample(1264); + s15[7].sample(5223); + s15[0].sample(1234); + s15[0].sample(5434); + s15[3].sample(8634); + curTick += ULL(1000000); + s15[1].sample(1234); + + s4 = curTick; + + s8[3] = 99999; + + s3 = 12; + s3++; + curTick += 9; + + s1 = 9; + s1 += 9; + s1 -= 11; + s1++; + ++s1; + s1--; + --s1; + + s2 = 9; + + s5[0] += 1; + s5[1] += 2; + s5[2] += 3; + s5[3] += 4; + s5[4] += 5; + + s7[0] = 10; + s7[1] = 20; + s7[2] = 30; + s7[3] = 40; + s7[4] = 50; + s7[5] = 60; + s7[6] = 70; + + s6.sample(0); + s6.sample(1); + s6.sample(2); + s6.sample(3); + s6.sample(4); + s6.sample(5); + s6.sample(6); + s6.sample(7); + s6.sample(8); + s6.sample(9); + - bin2.activate(); + s6.sample(10); + s6.sample(10); + s6.sample(10); + s6.sample(10); + s6.sample(10); + s6.sample(10); + s6.sample(10); + s6.sample(10); + s6.sample(11); + s6.sample(19); + s6.sample(20); + s6.sample(20); + s6.sample(21); + s6.sample(21); + s6.sample(31); + s6.sample(98); + s6.sample(99); + s6.sample(99); + s6.sample(99); + + s7[0] = 700; + s7[1] = 600; + s7[2] = 500; + s7[3] = 400; + s7[4] = 300; + s7[5] = 200; + s7[6] = 100; + + s9.sample(100); + s9.sample(100); + s9.sample(100); + s9.sample(100); + s9.sample(10); + s9.sample(10); + s9.sample(10); + s9.sample(10); + s9.sample(10); + + curTick += 9; + s4 = curTick; + s6.sample(100); + s6.sample(100); + s6.sample(100); + s6.sample(101); + s6.sample(102); + + s12.sample(100); + + if (text) { + Text out(cout); + out.descriptions = descriptions; + out.compat = compat; + out(); + } + + if (!mysql_name.empty()) { + MySql out; + out.connect(mysql_host, mysql_user, mysql_passwd, "m5stats", + mysql_name, "test"); + out(); + } + + return 0; +}