/* * Copyright 2002-2019 Intel Corporation. * * This software and the related documents are Intel copyrighted materials, and your * use of them is governed by the express license under which they were provided to * you ("License"). Unless the License provides otherwise, you may not use, modify, * copy, publish, distribute, disclose or transmit this software or the related * documents without Intel's prior written permission. * * This software and the related documents are provided as is, with no express or * implied warranties, other than those that are expressly stated in the License. */ /*! @file * This file contains support for stats counters on sparse input ranges. */ #ifndef PIN_PROFILE_H #define PIN_PROFILE_H #include #include #include /*! * Class to map arbitrary sequences of sparse input values to * a range of compact indices [0..N], * such that the same input value always produces the same index. */ template class COMPRESSOR { protected: typedef std::pair PAIR; typedef std::map MAP; MAP _map; INDEX _nextIndex; std::string _keyName; public: // constructors/destructors COMPRESSOR() { _nextIndex = 0; } // accessors std::string StringLong () const { std::string os; os += "COMPRESSOR BEGIN\n"; os += "# " + _nextIndex.str() + " counters\n"; os += "# " + _keyName + ": index\n"; for (typename MAP::const_iterator it = _map.begin(); it != _map.end(); it++) { os += it->first.str() + ": " + decstr(it->second,12) + "\n"; } os += "COMPRESSOR END\n"; return os; } // modifiers VOID SetKeyName(const std::string & keyName) { _keyName = keyName; } INDEX Map(KEY key) { typename MAP::const_iterator it = _map.find(key); if (it != _map.end()) { // key found: return index return it->second; } else { // key not yet present: insert and return new index const PAIR p(key, _nextIndex); _map.insert(p); return _nextIndex++; } } }; /*! * Class to provide a counter for each compresses index. Counters are * accessed similar to standard library classes with array syntax [] for * unchecked accesses, and with at() for range-checked accesses. The * array of counters is auto-extending as necessary and is guaranteed to * contain as many entries as have been mapped. */ template class COMPRESSOR_COUNTER : public COMPRESSOR { private: typedef std::vector VECTOR; static const UINT32 defaultInitCounterSize = 8*1024; VECTOR _counters; std::string _counterName; COUNTER _threshold; public: // constructors/destructors COMPRESSOR_COUNTER(UINT32 initCounterSize = defaultInitCounterSize) : COMPRESSOR(), _counters(initCounterSize) {} // accessors std::string StringLong () const { std::string os; INDEX num_counters = 0; for (typename COMPRESSOR::MAP::const_iterator it = this->_map.begin(); it != this->_map.end(); it++) { const COUNTER& counter = _counters[it->second]; if ( _threshold <= counter ) num_counters++; } os += "NumItems " + decstr(num_counters) +"\n"; os += "DATA:START\n"; os += "# counters\n"; os += "# " + this->_keyName + ": " + _counterName + "\n"; for (typename COMPRESSOR::MAP::const_iterator it = this->_map.begin(); it != this->_map.end(); it++) { const COUNTER& counter = _counters[it->second]; if ( _threshold <= counter) { os += hexstr(it->first,8) + ": " + counter.str() + "\n"; } } os += "DATA:END\n"; return os; } // modifiers VOID SetCounterName(const std::string & counterName) { _counterName = counterName; } VOID SetThreshold(const COUNTER& threshold) { _threshold = threshold; } INDEX Map(KEY key) { // use compressor to map const INDEX Idx = COMPRESSOR::Map(key); // ... and check if need to add more counters if (Idx + 1 >= _counters.capacity()) { _counters.reserve(2 * _counters.capacity()); } return Idx; } const COUNTER & operator[] (INDEX index) const { return _counters[index]; } COUNTER & operator[] (INDEX index) { return _counters[index]; } const COUNTER & at(INDEX index) const { return _counters.at(index); } COUNTER & at(INDEX index) { return _counters.at(index); } }; /*! * Class to provide an array of counters for use with COMPRESSOR_COUNTER * if more than a single counter is required. * Counters are accessed similar to standard library classes with array * syntax [] for unchecked accesses, and with at() for range-checked * accesses. The array of counters is auto-extending as necessary and is * guaranteed to contain as many entries as have been mapped. */ template class COUNTER_ARRAY { private: NUMTYPE _counters[NUM_COUNTERS]; public: // accessors std::string str() const { std::string os; for (UINT32 i = 0; i < NUM_COUNTERS; i++) { if (i != 0) os += " "; os += decstr(_counters[i],12); } return os; } // allow compare to 0 bool operator==(const COUNTER_ARRAY& x) const { for (UINT32 i = 0; i < NUM_COUNTERS; i++) { if (_counters[i] != x._counters[i]) return false; } return true; } bool operator!=(const COUNTER_ARRAY& x) const { return ! operator==(x); } bool operator<=(const COUNTER_ARRAY& x) const { for (UINT32 i = 0; i < NUM_COUNTERS; i++) { if (_counters[i] > x._counters[i]) return false; } return true; } // modifiers const NUMTYPE & operator[] (UINT32 index) const { return _counters[index]; } NUMTYPE & operator[] (UINT32 index) { return _counters[index]; } const NUMTYPE & at(UINT32 index) const { assert(index < NUM_COUNTERS); return _counters[index]; } NUMTYPE & at(UINT32 index) { assert(index < NUM_COUNTERS); return _counters[index]; } }; #define PROFILE(n) COMPRESSOR_COUNTER > #endif // PIN_PROFILE_H