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