You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

254 lines
6.6 KiB

/*
* 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 <map>
#include <vector>
#include <cassert>
/*!
* 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 KEY, class INDEX>
class COMPRESSOR
{
protected:
typedef std::pair<const KEY, INDEX> PAIR;
typedef std::map<KEY, INDEX> 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 KEY, class INDEX, class COUNTER>
class COMPRESSOR_COUNTER : public COMPRESSOR<KEY, INDEX>
{
private:
typedef std::vector<COUNTER> VECTOR;
static const UINT32 defaultInitCounterSize = 8*1024;
VECTOR _counters;
std::string _counterName;
COUNTER _threshold;
public:
// constructors/destructors
COMPRESSOR_COUNTER(UINT32 initCounterSize = defaultInitCounterSize)
: COMPRESSOR<KEY,INDEX>(),
_counters(initCounterSize)
{}
// accessors
std::string StringLong () const
{
std::string os;
INDEX num_counters = 0;
for (typename COMPRESSOR<KEY,INDEX>::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<KEY,INDEX>::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<KEY,INDEX>::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 NUMTYPE, UINT32 NUM_COUNTERS>
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<ADDRINT, UINT32, COUNTER_ARRAY<UINT32, n> >
#endif // PIN_PROFILE_H