gem5/src/mem/stack_dist_calc.cc

599 lines
21 KiB
C++
Raw Normal View History

mem: Add a stack distance calculator This patch adds a stand-alone stack distance calculator. The stack distance calculator is a passive SimObject that observes the addresses passed to it. It calculates stack distances (LRU Distances) of incoming addresses based on the partial sum hierarchy tree algorithm described by Alamasi et al. http://doi.acm.org/10.1145/773039.773043. For each transaction a hashtable look-up is performed. At every non-unique transaction the tree is traversed from the leaf at the returned index to the root, the old node is deleted from the tree, and the sums (to the right) are collected and decremented. The collected sum represets the stack distance of the found node. At every unique transaction the stack distance is returned as numeric_limits<uint64>::max(). In addition to the basic stack distance calculation, a feature to mark an old node in the tree is added. This is useful if it is required to see the reuse pattern. For example, Writebacks to the lower level (e.g. membus from L2), can be marked instead of being removed from the stack (isMarked flag of Node set to True). And then later if this same address is accessed (by L1), the value of the isMarked flag would be True. This gives some insight on how the Writeback policy of the lower level affect the read/write accesses in an application. Debugging is enabled by setting the verify flag to true. Debugging is implemented using a dummy stack that behaves in a naive way, using STL vectors. Note that this has a large impact on run time.
2014-12-23 15:31:18 +01:00
/*
* Copyright (c) 2014-2015 ARM Limited
mem: Add a stack distance calculator This patch adds a stand-alone stack distance calculator. The stack distance calculator is a passive SimObject that observes the addresses passed to it. It calculates stack distances (LRU Distances) of incoming addresses based on the partial sum hierarchy tree algorithm described by Alamasi et al. http://doi.acm.org/10.1145/773039.773043. For each transaction a hashtable look-up is performed. At every non-unique transaction the tree is traversed from the leaf at the returned index to the root, the old node is deleted from the tree, and the sums (to the right) are collected and decremented. The collected sum represets the stack distance of the found node. At every unique transaction the stack distance is returned as numeric_limits<uint64>::max(). In addition to the basic stack distance calculation, a feature to mark an old node in the tree is added. This is useful if it is required to see the reuse pattern. For example, Writebacks to the lower level (e.g. membus from L2), can be marked instead of being removed from the stack (isMarked flag of Node set to True). And then later if this same address is accessed (by L1), the value of the isMarked flag would be True. This gives some insight on how the Writeback policy of the lower level affect the read/write accesses in an application. Debugging is enabled by setting the verify flag to true. Debugging is implemented using a dummy stack that behaves in a naive way, using STL vectors. Note that this has a large impact on run time.
2014-12-23 15:31:18 +01:00
* All rights reserved
*
* The license below extends only to copyright in the software and shall
* not be construed as granting a license to any other intellectual
* property including but not limited to intellectual property relating
* to a hardware implementation of the functionality of the software
* licensed hereunder. You may use the software subject to the license
* terms below provided that you ensure that this notice is replicated
* unmodified and in its entirety in all distributions of the software,
* modified or unmodified, in source code or in binary form.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer;
* redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution;
* neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Authors: Kanishk Sugand
*/
#include "mem/stack_dist_calc.hh"
#include "base/chunk_generator.hh"
mem: Add a stack distance calculator This patch adds a stand-alone stack distance calculator. The stack distance calculator is a passive SimObject that observes the addresses passed to it. It calculates stack distances (LRU Distances) of incoming addresses based on the partial sum hierarchy tree algorithm described by Alamasi et al. http://doi.acm.org/10.1145/773039.773043. For each transaction a hashtable look-up is performed. At every non-unique transaction the tree is traversed from the leaf at the returned index to the root, the old node is deleted from the tree, and the sums (to the right) are collected and decremented. The collected sum represets the stack distance of the found node. At every unique transaction the stack distance is returned as numeric_limits<uint64>::max(). In addition to the basic stack distance calculation, a feature to mark an old node in the tree is added. This is useful if it is required to see the reuse pattern. For example, Writebacks to the lower level (e.g. membus from L2), can be marked instead of being removed from the stack (isMarked flag of Node set to True). And then later if this same address is accessed (by L1), the value of the isMarked flag would be True. This gives some insight on how the Writeback policy of the lower level affect the read/write accesses in an application. Debugging is enabled by setting the verify flag to true. Debugging is implemented using a dummy stack that behaves in a naive way, using STL vectors. Note that this has a large impact on run time.
2014-12-23 15:31:18 +01:00
#include "base/intmath.hh"
#include "base/trace.hh"
#include "debug/StackDist.hh"
StackDistCalc::StackDistCalc(bool verify_stack)
: index(0),
verifyStack(verify_stack)
mem: Add a stack distance calculator This patch adds a stand-alone stack distance calculator. The stack distance calculator is a passive SimObject that observes the addresses passed to it. It calculates stack distances (LRU Distances) of incoming addresses based on the partial sum hierarchy tree algorithm described by Alamasi et al. http://doi.acm.org/10.1145/773039.773043. For each transaction a hashtable look-up is performed. At every non-unique transaction the tree is traversed from the leaf at the returned index to the root, the old node is deleted from the tree, and the sums (to the right) are collected and decremented. The collected sum represets the stack distance of the found node. At every unique transaction the stack distance is returned as numeric_limits<uint64>::max(). In addition to the basic stack distance calculation, a feature to mark an old node in the tree is added. This is useful if it is required to see the reuse pattern. For example, Writebacks to the lower level (e.g. membus from L2), can be marked instead of being removed from the stack (isMarked flag of Node set to True). And then later if this same address is accessed (by L1), the value of the isMarked flag would be True. This gives some insight on how the Writeback policy of the lower level affect the read/write accesses in an application. Debugging is enabled by setting the verify flag to true. Debugging is implemented using a dummy stack that behaves in a naive way, using STL vectors. Note that this has a large impact on run time.
2014-12-23 15:31:18 +01:00
{
// Instantiate a new root and leaf layer
// Map type variable, representing a layer in the tree
IndexNodeMap tree_level;
// Initialize tree count for leaves
nextIndex.push_back(0);
// Add the initial leaf layer to the tree
tree.push_back(tree_level);
// Create a root node. Node type variable in the topmost layer
Node* root_node = new Node();
// Initialize tree count for root
nextIndex.push_back(1);
// Add the empty root layer to the tree
tree.push_back(tree_level);
// Add the initial root to the tree
tree[1][root_node->nodeIndex] = root_node;
}
StackDistCalc::~StackDistCalc()
{
// Walk through each layer and destroy the nodes
for (auto& layer : tree) {
for (auto& index_node : layer) {
// each map entry contains an index and a node
delete index_node.second;
}
// Clear each layer in the tree
layer.clear();
}
// Clear the tree
tree.clear();
aiMap.clear();
nextIndex.clear();
// For verification
stack.clear();
}
// The updateSum method is a recursive function which updates
// the node sums till the root. It also deletes the nodes that
// are not used anymore.
uint64_t
StackDistCalc::updateSum(Node* node, bool from_left,
uint64_t sum_from_below, uint64_t level,
uint64_t stack_dist, bool discard_node)
{
++level;
// Make a copy of the node variables and work on them
// as a node may be deleted by this function
uint64_t node_sum_l = node->sumLeft;
uint64_t node_sum_r = node->sumRight;
bool node_left = node->isLeftNode;
bool node_discard_left = node->discardLeft;
bool node_discard_right = node->discardRight;
uint64_t node_n_index = node->nodeIndex;
Node* node_parent_ptr = node->parent;
// For verification
if (verifyStack) {
// This sanity check makes sure that the left_sum and
// right_sum of the node is not greater than the
// maximum possible value given by the leaves below it
// for example a node in layer 3 (tree[3]) can at most
// have 8 leaves (4 to the left and 4 to the right)
// thus left_sum and right_sum should be <= 4
panic_if(node_sum_l > (1 << (level - 1)),
"Error in sum left of level %ul, node index %ull, "
"Sum = %ull \n", level, node_n_index, node_sum_l);
panic_if(node_sum_r > (1 << (level - 1)),
"Error in sum right of level %ul, node index %ull, "
"Sum = %ull \n", level, node_n_index, node_sum_r);
}
// Update the left sum or the right sum depending on the
// from_left flag. Variable stack_dist is updated only
// when arriving from Left.
if (from_left) {
// update sumLeft
node_sum_l = sum_from_below;
stack_dist += node_sum_r;
} else {
// update sum_r
node_sum_r = sum_from_below;
}
// sum_from_below == 0 can be a leaf discard operation
if (discard_node && !sum_from_below) {
if (from_left)
node_discard_left = true;
else
node_discard_right = true;
}
// Update the node variables with new values
node->nodeIndex = node_n_index;
node->sumLeft = node_sum_l;
node->sumRight = node_sum_r;
node->isLeftNode = node_left;
node->discardLeft = node_discard_left;
node->discardRight = node_discard_right;
// Delete the node if it is not required anymore
if (node_discard_left && node_discard_right &&
discard_node && node_parent_ptr && !sum_from_below) {
delete node;
tree[level].erase(node_n_index);
discard_node = true;
} else {
// propogate discard_node as false upwards if the
// above conditions are not met.
discard_node = false;
}
// Recursively call the updateSum operation till the
// root node is reached
if (node_parent_ptr) {
stack_dist = updateSum(node_parent_ptr, node_left,
node_sum_l + node_sum_r,
level, stack_dist, discard_node);
}
return stack_dist;
}
// This function is called by the calcStackDistAndUpdate function
// If is_new_leaf is true then a new leaf is added otherwise a leaf
// removed from the tree. In both cases the tree is updated using
// the updateSum operation.
uint64_t
StackDistCalc::updateSumsLeavesToRoot(Node* node, bool is_new_leaf)
{
uint64_t level = 0;
uint64_t stack_dist = 0;
if (is_new_leaf) {
node->sumLeft = 1;
updateSum(node->parent,
node->isLeftNode, node->sumLeft,
level, 0, false);
stack_dist = Infinity;
} else {
node->sumLeft = 0;
stack_dist = updateSum(node->parent,
node->isLeftNode, 0,
level, stack_dist, true);
}
return stack_dist;
}
// This method is a recursive function which calculates
// the node sums till the root.
uint64_t
StackDistCalc::getSum(Node* node, bool from_left, uint64_t sum_from_below,
uint64_t stack_dist, uint64_t level) const
{
++level;
// Variable stack_dist is updated only
// when arriving from Left.
if (from_left) {
mem: Add a stack distance calculator This patch adds a stand-alone stack distance calculator. The stack distance calculator is a passive SimObject that observes the addresses passed to it. It calculates stack distances (LRU Distances) of incoming addresses based on the partial sum hierarchy tree algorithm described by Alamasi et al. http://doi.acm.org/10.1145/773039.773043. For each transaction a hashtable look-up is performed. At every non-unique transaction the tree is traversed from the leaf at the returned index to the root, the old node is deleted from the tree, and the sums (to the right) are collected and decremented. The collected sum represets the stack distance of the found node. At every unique transaction the stack distance is returned as numeric_limits<uint64>::max(). In addition to the basic stack distance calculation, a feature to mark an old node in the tree is added. This is useful if it is required to see the reuse pattern. For example, Writebacks to the lower level (e.g. membus from L2), can be marked instead of being removed from the stack (isMarked flag of Node set to True). And then later if this same address is accessed (by L1), the value of the isMarked flag would be True. This gives some insight on how the Writeback policy of the lower level affect the read/write accesses in an application. Debugging is enabled by setting the verify flag to true. Debugging is implemented using a dummy stack that behaves in a naive way, using STL vectors. Note that this has a large impact on run time.
2014-12-23 15:31:18 +01:00
stack_dist += node->sumRight;
}
// Recursively call the getSum operation till the
// root node is reached
if (node->parent) {
mem: Add a stack distance calculator This patch adds a stand-alone stack distance calculator. The stack distance calculator is a passive SimObject that observes the addresses passed to it. It calculates stack distances (LRU Distances) of incoming addresses based on the partial sum hierarchy tree algorithm described by Alamasi et al. http://doi.acm.org/10.1145/773039.773043. For each transaction a hashtable look-up is performed. At every non-unique transaction the tree is traversed from the leaf at the returned index to the root, the old node is deleted from the tree, and the sums (to the right) are collected and decremented. The collected sum represets the stack distance of the found node. At every unique transaction the stack distance is returned as numeric_limits<uint64>::max(). In addition to the basic stack distance calculation, a feature to mark an old node in the tree is added. This is useful if it is required to see the reuse pattern. For example, Writebacks to the lower level (e.g. membus from L2), can be marked instead of being removed from the stack (isMarked flag of Node set to True). And then later if this same address is accessed (by L1), the value of the isMarked flag would be True. This gives some insight on how the Writeback policy of the lower level affect the read/write accesses in an application. Debugging is enabled by setting the verify flag to true. Debugging is implemented using a dummy stack that behaves in a naive way, using STL vectors. Note that this has a large impact on run time.
2014-12-23 15:31:18 +01:00
stack_dist = getSum(node->parent, node->isLeftNode,
node->sumLeft + node->sumRight,
stack_dist, level);
}
return stack_dist;
}
// This function is called by the calcStackDistance function
uint64_t
StackDistCalc::getSumsLeavesToRoot(Node* node) const
{
return getSum(node->parent, node->isLeftNode, 0, 0, 0);
}
// Update tree is a tree balancing operation which maintains
// the binary tree structure. This method is called whenever
// index%2 == 0 (i.e. every alternate cycle)
// The two main operation are :
// OP1. moving the root node one layer up if index counter
// crosses power of 2
// OP2. Addition of intermediate nodes as and when required
// and linking them to their parents in the layer above.
void
StackDistCalc::updateTree()
{
uint64_t i;
if (isPowerOf2(index)) {
// OP1. moving the root node one layer up if index counter
// crosses power of 2
// If index counter crosses a power of 2, then add a
// new tree layer above and create a new Root node in it.
// After the root is created the old node
// in the layer below is updated to point to this
// newly created root node. The sum_l of this new root node
// becomes the sum_l + sum_r of the old node.
//
// After this root update operation a chain of intermediate
// nodes is created from root layer to tree[1](one layer
// above the leaf layer)
// Create a new root node
Node* newRootNode = new Node();
// Update its sum_l as the sum_l+sum_r from below
newRootNode->sumLeft = tree[getTreeDepth()][0]->sumRight +
tree[getTreeDepth()][0]->sumLeft;
// Update its discard left flag if the node below has
// has both discardLeft and discardRight set.
newRootNode->discardLeft = tree[getTreeDepth()][0]->discardLeft &&
tree[getTreeDepth()][0]->discardRight;
// Map type variable, representing a layer in the tree
IndexNodeMap treeLevel;
// Add a new layer to the tree
tree.push_back(treeLevel);
nextIndex.push_back(1);
tree[getTreeDepth()][newRootNode->nodeIndex] = newRootNode;
// Update the parent pointer at lower layer to
// point to newly created root node
tree[getTreeDepth() - 1][0]->parent = tree[getTreeDepth()][0];
// Add intermediate nodes from root till bottom (one layer above the
// leaf layer)
for (i = getTreeDepth() - 1; i >= 1; --i) {
Node* newINode = new Node();
// newNode is left or right child depending on the number of nodes
// in that layer
if (nextIndex[i] % 2 == 0) {
newINode->isLeftNode = true;
} else {
newINode->isLeftNode = false;
}
newINode->parent = tree[i + 1][nextIndex[i + 1] - 1];
newINode->nodeIndex = ++nextIndex[i] - 1;
tree[i][newINode->nodeIndex] = newINode;
}
} else {
// OP2. Addition of intermediate nodes as and when required
// and linking them to their parents in the layer above.
//
// At layer 1 a new INode is added whenever index%(2^1)==0
// (multiples of 2)
//
// At layer 2 a new INode is added whenever index%(2^2)==0
// (multiples of 4)
//
// At layer 3 a new INode is added whenever index%(2^3)==0
// (multiples of 8)
//...
//
// At layer N a new INode is added whenever index%(2^N)==0
// (multiples of 2^N)
for (i = getTreeDepth() - 1; i >= 1; --i) {
// Traverse each layer from root to leaves and add a new
// intermediate node if required. Link the parent_ptr of
// the new node to the parent in the above layer.
if ((index % (1 << i)) == 0) {
// Checks if current (index % 2^treeDepth) == 0 if true
// a new node at that layer is created
Node* newINode = new Node();
// newNode is left or right child depending on the
// number of nodes in that layer.
if (nextIndex[i] % 2 == 0) {
newINode->isLeftNode = true;
} else {
newINode->isLeftNode = false;
}
// Pointing to its parent in the upper layer
newINode->parent = tree[i + 1][nextIndex[i + 1] - 1];
newINode->nodeIndex = ++nextIndex[i] - 1;
tree[i][newINode->nodeIndex] = newINode;
}
}
}
}
// This function is called everytime to get the stack distance and add
// a new node. A feature to mark an old node in the tree is
// added. This is useful if it is required to see the reuse
// pattern. For example, BackInvalidates from the lower level (Membus)
// to L2, can be marked (isMarked flag of Node set to True). And then
// later if this same address is accessed by L1, the value of the
// isMarked flag would be True. This would give some insight on how
// the BackInvalidates policy of the lower level affect the read/write
// accesses in an application.
std::pair< uint64_t, bool>
StackDistCalc::calcStackDistAndUpdate(const Addr r_address, bool addNewNode)
{
Node* newLeafNode;
auto ai = aiMap.lower_bound(r_address);
// Default value of flag indicating as the left or right leaf
bool isLeft = true;
// Default value of isMarked flag for each node.
bool _mark = false;
// By default stackDistacne is treated as infinity
uint64_t stack_dist;
// Lookup aiMap by giving address as the key:
// If found take address and Lookup in tree
// Update tree from leaves by making B(found index) = 0
// Add sums to right till root while Updating them
// Stack Distance of that address sums to right
if (ai != aiMap.end() && !(aiMap.key_comp()(r_address, ai->first))) {
// key already exists
// save the index counter value when this address was
// encountered before and update it to the current index value
uint64_t r_index = ai->second;
mem: Add a stack distance calculator This patch adds a stand-alone stack distance calculator. The stack distance calculator is a passive SimObject that observes the addresses passed to it. It calculates stack distances (LRU Distances) of incoming addresses based on the partial sum hierarchy tree algorithm described by Alamasi et al. http://doi.acm.org/10.1145/773039.773043. For each transaction a hashtable look-up is performed. At every non-unique transaction the tree is traversed from the leaf at the returned index to the root, the old node is deleted from the tree, and the sums (to the right) are collected and decremented. The collected sum represets the stack distance of the found node. At every unique transaction the stack distance is returned as numeric_limits<uint64>::max(). In addition to the basic stack distance calculation, a feature to mark an old node in the tree is added. This is useful if it is required to see the reuse pattern. For example, Writebacks to the lower level (e.g. membus from L2), can be marked instead of being removed from the stack (isMarked flag of Node set to True). And then later if this same address is accessed (by L1), the value of the isMarked flag would be True. This gives some insight on how the Writeback policy of the lower level affect the read/write accesses in an application. Debugging is enabled by setting the verify flag to true. Debugging is implemented using a dummy stack that behaves in a naive way, using STL vectors. Note that this has a large impact on run time.
2014-12-23 15:31:18 +01:00
if (addNewNode) {
// Update aiMap aiMap(Address) = current index
ai->second = index;
} else {
aiMap.erase(r_address);
}
// Call update tree operation on the tree starting with
// the r_index value found above. This function would return
// the value of the stack distcance.
stack_dist = updateSumsLeavesToRoot(tree[0][r_index], false);
newLeafNode = tree[0][r_index];
// determine if this node was marked earlier
_mark = newLeafNode->isMarked;
delete newLeafNode;
tree[0].erase(r_index);
} else {
if (addNewNode) {
// Update aiMap aiMap(Address) = current index
aiMap[r_address] = index;
}
// Update infinity bin count
// By default stackDistacne is treated as infinity
stack_dist = Infinity;
}
if (addNewNode) {
// If index%2 == 0 then update tree
if (index % 2 == 0) {
updateTree();
} else {
// At odd values of index counter, a new right-type node is
// added to the leaf layer, else a left-type node is added
isLeft = false;
}
// Add new leaf node in the leaf layer (tree[0])
// set n_index = current index
newLeafNode = new Node();
++nextIndex[0];
newLeafNode->nodeIndex=index;
newLeafNode->isLeftNode=isLeft;
// Point the parent pointer to the intermediate node above
newLeafNode->parent = tree[1][nextIndex[1] - 1];
tree[0][index] = newLeafNode;
// call an update operation which would update the tree after
// addition of this new leaf node.
updateSumsLeavesToRoot(tree[0][index], true);
// For verification
if (verifyStack) {
// This function checks the sanity of the tree to make sure the
// last node in the link of parent pointers is the root node.
// It takes a leaf node as an argument and traveses upwards till
// the root layer to check if the last parent is null
sanityCheckTree(tree[0][index]);
// Push the same element in debug stack, and check
uint64_t verify_stack_dist = verifyStackDist(r_address, true);
panic_if(verify_stack_dist != stack_dist,
"Expected stack-distance for address \
%#lx is %#lx but found %#lx",
r_address, verify_stack_dist, stack_dist);
printStack();
}
// The index counter is updated at the end of each transaction
// (unique or non-unique)
++index;
}
return (std::make_pair(stack_dist, _mark));
}
// This function is called everytime to get the stack distance
// no new node is added. It can be used to mark a previous access
// and inspect the value of the mark flag.
std::pair< uint64_t, bool>
StackDistCalc::calcStackDist(const Addr r_address, bool mark)
{
// Default value of isMarked flag for each node.
bool _mark = false;
auto ai = aiMap.lower_bound(r_address);
// By default stackDistacne is treated as infinity
uint64_t stack_dist = 0;
// Lookup aiMap by giving address as the key:
// If found take address and Lookup in tree
// Add sums to right till root
// Stack Distance of that address sums to right
if (ai != aiMap.end() && !(aiMap.key_comp()(r_address, ai->first))) {
// key already exists
// save the index counter value when this address was
// encountered before
uint64_t r_index = ai->second;
mem: Add a stack distance calculator This patch adds a stand-alone stack distance calculator. The stack distance calculator is a passive SimObject that observes the addresses passed to it. It calculates stack distances (LRU Distances) of incoming addresses based on the partial sum hierarchy tree algorithm described by Alamasi et al. http://doi.acm.org/10.1145/773039.773043. For each transaction a hashtable look-up is performed. At every non-unique transaction the tree is traversed from the leaf at the returned index to the root, the old node is deleted from the tree, and the sums (to the right) are collected and decremented. The collected sum represets the stack distance of the found node. At every unique transaction the stack distance is returned as numeric_limits<uint64>::max(). In addition to the basic stack distance calculation, a feature to mark an old node in the tree is added. This is useful if it is required to see the reuse pattern. For example, Writebacks to the lower level (e.g. membus from L2), can be marked instead of being removed from the stack (isMarked flag of Node set to True). And then later if this same address is accessed (by L1), the value of the isMarked flag would be True. This gives some insight on how the Writeback policy of the lower level affect the read/write accesses in an application. Debugging is enabled by setting the verify flag to true. Debugging is implemented using a dummy stack that behaves in a naive way, using STL vectors. Note that this has a large impact on run time.
2014-12-23 15:31:18 +01:00
// Get the value of mark flag if previously marked
_mark = tree[0][r_index]->isMarked;
// Mark the leaf node if required
tree[0][r_index]->isMarked = mark;
// Call get sums operation on the tree starting with
// the r_index value found above. This function would return
// the value of the stack distcance.
stack_dist = getSumsLeavesToRoot(tree[0][r_index]);
} else {
// Update infinity bin count
// By default stackDistacne is treated as infinity
stack_dist = Infinity;
}
// For verification
if (verifyStack) {
// Calculate the SD of the same address in the debug stack
uint64_t verify_stack_dist = verifyStackDist(r_address);
panic_if(verify_stack_dist != stack_dist,
"Expected stack-distance for address \
%#lx is %#lx but found %#lx",
r_address, verify_stack_dist, stack_dist);
printStack();
}
return std::make_pair(stack_dist, _mark);
}
// For verification
// Simple sanity check for the tree
void
StackDistCalc::sanityCheckTree(const Node* node, uint64_t level) const
{
const Node* next_up = node->parent;
for (uint64_t i = level + 1; i < getTreeDepth() - level; ++i) {
next_up = next_up->parent;
panic_if(!next_up, "Sanity check failed for node %ull \n",
node->nodeIndex);
}
// At the root layer the parent_ptr should be null
panic_if(next_up->parent, "Sanity check failed for node %ull \n",
node->nodeIndex);
}
// This method can be called to compute the stack distance in a naive
// way It can be used to verify the functionality of the stack
// distance calculator. It uses std::vector to compute the stack
// distance using a naive stack.
uint64_t
StackDistCalc::verifyStackDist(const Addr r_address, bool update_stack)
{
bool found = false;
uint64_t stack_dist = 0;
auto a = stack.rbegin();
for (; a != stack.rend(); ++a) {
if (*a == r_address) {
found = true;
break;
} else {
++stack_dist;
}
}
if (found) {
++a;
if (update_stack)
stack.erase(a.base());
} else {
stack_dist = Infinity;
}
if (update_stack)
stack.push_back(r_address);
return stack_dist;
}
// This method is useful to print top n entities in the stack.
void
StackDistCalc::printStack(int n) const
{
Node* node;
int count = 0;
DPRINTF(StackDist, "Printing last %d entries in tree\n", n);
// Walk through leaf layer to display the last n nodes
for (auto it = tree[0].rbegin(); (count < n) && (it != tree[0].rend());
++it, ++count) {
node = it->second;
uint64_t r_index = node->nodeIndex;
mem: Add a stack distance calculator This patch adds a stand-alone stack distance calculator. The stack distance calculator is a passive SimObject that observes the addresses passed to it. It calculates stack distances (LRU Distances) of incoming addresses based on the partial sum hierarchy tree algorithm described by Alamasi et al. http://doi.acm.org/10.1145/773039.773043. For each transaction a hashtable look-up is performed. At every non-unique transaction the tree is traversed from the leaf at the returned index to the root, the old node is deleted from the tree, and the sums (to the right) are collected and decremented. The collected sum represets the stack distance of the found node. At every unique transaction the stack distance is returned as numeric_limits<uint64>::max(). In addition to the basic stack distance calculation, a feature to mark an old node in the tree is added. This is useful if it is required to see the reuse pattern. For example, Writebacks to the lower level (e.g. membus from L2), can be marked instead of being removed from the stack (isMarked flag of Node set to True). And then later if this same address is accessed (by L1), the value of the isMarked flag would be True. This gives some insight on how the Writeback policy of the lower level affect the read/write accesses in an application. Debugging is enabled by setting the verify flag to true. Debugging is implemented using a dummy stack that behaves in a naive way, using STL vectors. Note that this has a large impact on run time.
2014-12-23 15:31:18 +01:00
// Lookup aiMap using the index returned by the leaf iterator
for (auto ai = aiMap.rbegin(); ai != aiMap.rend(); ++ai) {
if (ai->second == r_index) {
DPRINTF(StackDist,"Tree leaves, Rightmost-[%d] = %#lx\n",
count, ai->first);
break;
}
}
}
DPRINTF(StackDist,"Tree depth = %#ld\n", getTreeDepth());
if (verifyStack) {
DPRINTF(StackDist,"Printing Last %d entries in VerifStack \n", n);
count = 0;
for (auto a = stack.rbegin(); (count < n) && (a != stack.rend());
++a, ++count) {
DPRINTF(StackDist, "Verif Stack, Top-[%d] = %#lx\n", count, *a);
}
}
}