5592798865
Result of running 'hg m5style --skip-all --fix-control -a'.
598 lines
21 KiB
C++
598 lines
21 KiB
C++
/*
|
|
* Copyright (c) 2014-2015 ARM Limited
|
|
* 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"
|
|
#include "base/intmath.hh"
|
|
#include "base/trace.hh"
|
|
#include "debug/StackDist.hh"
|
|
|
|
StackDistCalc::StackDistCalc(bool verify_stack)
|
|
: index(0),
|
|
verifyStack(verify_stack)
|
|
{
|
|
// 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) {
|
|
stack_dist += node->sumRight;
|
|
}
|
|
|
|
// Recursively call the getSum operation till the
|
|
// root node is reached
|
|
if (node->parent) {
|
|
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;
|
|
|
|
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;
|
|
|
|
// 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;
|
|
|
|
// 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);
|
|
}
|
|
}
|
|
}
|