2014-12-23 15:31:18 +01:00
|
|
|
/*
|
2015-08-04 11:29:13 +02:00
|
|
|
* Copyright (c) 2014-2015 ARM Limited
|
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
|
|
|
|
* Andreas Hansson
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifndef __MEM_STACK_DIST_CALC_HH__
|
|
|
|
#define __MEM_STACK_DIST_CALC_HH__
|
|
|
|
|
2015-08-04 11:29:13 +02:00
|
|
|
#include <limits>
|
2014-12-23 15:31:18 +01:00
|
|
|
#include <map>
|
|
|
|
#include <vector>
|
|
|
|
|
|
|
|
#include "base/types.hh"
|
|
|
|
|
|
|
|
/**
|
|
|
|
* The stack distance calculator is a passive object that merely
|
|
|
|
* observes the addresses pass to it. It calculates stack 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.
|
|
|
|
*
|
|
|
|
* A tree structure is maintained and updated at each transaction
|
|
|
|
* (unique or non-unique). The tree is implemented as an STL vector
|
|
|
|
* with layers of the form <map> Each layer in this tree is an
|
|
|
|
* ordered map <uint64_t, Node*>. Nodes are structs which take form
|
|
|
|
* of leaf, intermediate and root nodes. For example, in a tree with 3
|
|
|
|
* layers, tree[0][5] gives a leaf node pointer for key=5 tree[1][1]
|
|
|
|
* gives an intermediate node pointer for key=1 tree[2][0] gives the
|
|
|
|
* root node in the tree.
|
|
|
|
*
|
|
|
|
* At every transaction a hash-map (aiMap) is looked up to check if
|
|
|
|
* the address was already encountered before. Based on this lookup a
|
|
|
|
* transaction can be termed as unique or non-unique.
|
|
|
|
*
|
|
|
|
* In addition to the normal 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, BackInvalidates
|
|
|
|
* from a lower level (e.g. membus to L2), can be marked (isMarked
|
|
|
|
* flag of Node set to True). 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.
|
|
|
|
*
|
|
|
|
* There are two functions provided to interface with the calculator:
|
|
|
|
* 1. pair<uint64_t, bool> calcStackDistAndUpdate(Addr r_address,
|
|
|
|
* bool addNewNode)
|
|
|
|
* At every unique transaction a new leaf node is added at tree[0](leaf layer)
|
|
|
|
* and linked to the layer above (if addNewNode is True). The sums of all
|
|
|
|
* the intermediate nodes is updated till the root. The stack-distance is
|
|
|
|
* returned as a Constant representing INFINITY.
|
|
|
|
*
|
|
|
|
* 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. If this node was marked then a bool flag set to True
|
|
|
|
* is returned with the stack_distance. During this operation a node
|
|
|
|
* is discarded at the leaf layer always. Moreover during the
|
|
|
|
* traversal upwards using the updateSum() method, if an intermediate
|
|
|
|
* node is found with no children connected to it, then that is
|
|
|
|
* discarded too.
|
|
|
|
*
|
|
|
|
* The return value of this function is a pair representing the
|
|
|
|
* stack_distance and the value of the marked flag.
|
|
|
|
*
|
|
|
|
* 2. pair<uint64_t , bool> calcStackDist(Addr r_address, bool mark)
|
|
|
|
* This is a stripped down version of the above function which is used to
|
|
|
|
* just inspect the tree, and mark a leaf node (if mark flag is set). The
|
|
|
|
* functionality to add a new node is removed.
|
|
|
|
*
|
|
|
|
* At every unique transaction the stack-distance is returned as a constant
|
|
|
|
* representing INFINITY.
|
|
|
|
*
|
|
|
|
* At every non-unique transaction the tree is traversed from the
|
|
|
|
* leaf at the returned index to the root, and the sums (to the right)
|
|
|
|
* are collected. The collected sum represets the stack distance of
|
|
|
|
* the found node.
|
|
|
|
*
|
|
|
|
* This function does NOT Modify the stack. (No node is added or
|
|
|
|
* deleted). It is just used to mark a node already created and get
|
|
|
|
* its stack distance.
|
|
|
|
*
|
|
|
|
* The return value of this function is a pair representing the stack
|
|
|
|
* distance and the value of the marked flag.
|
|
|
|
*
|
|
|
|
* The table below depicts the usage of the Algorithm using the functions:
|
|
|
|
* pair<uint64_t Stack_dist, bool isMarked> calcStackDistAndUpdate
|
|
|
|
* (Addr r_address, bool addNewNode)
|
|
|
|
* pair<uint64_t Stack_dist, bool isMarked> calcStackDist
|
|
|
|
* (Addr r_address, bool mark)
|
|
|
|
*
|
|
|
|
* | Function | Arguments |Return Val |Use For|
|
|
|
|
* |calcStackDistAndUpdate|r_address, True|I/SD,False |A,GD,GM|
|
|
|
|
* |calcStackDistAndUpdate|r_address,False|SD,prevMark|D,GD,GM|
|
|
|
|
* |calcStackDist |r_address,False|SD,prevMark| GD,GM|
|
|
|
|
* |calcStackDist |r_address, True|SD,prevMark| GD,GM|
|
|
|
|
*
|
|
|
|
* (*A: Allocate an address in stack, if old entry present then it is deleted,
|
|
|
|
* *U: Delete old-address from stack, no new entry is added
|
|
|
|
* *GD: Get-Stack distance of an address,
|
|
|
|
* *GM: Get value of Mark flag, indicates if that address has been touched
|
|
|
|
* before,
|
|
|
|
* *I: stack-distance = infinity,
|
|
|
|
* *SD: Stack Distance
|
|
|
|
* *r_address: address to be added, *prevMark: value of isMarked flag
|
|
|
|
* of the Node)
|
|
|
|
*
|
|
|
|
* Invalidates refer to a type of packet that removes something from
|
|
|
|
* a cache, either autonoumously (due-to cache's own replacement
|
|
|
|
* policy), or snoops from other caches which invalidate something
|
|
|
|
* inside our cache.
|
|
|
|
*
|
|
|
|
* Usage | Function to use |Typical Use |
|
|
|
|
* Add new entry |calcStackDistAndUpdate|Read/Write Allocate |
|
|
|
|
* Delete Old Entry |calcStackDistAndUpdate|Writebacks/Cleanevicts|
|
|
|
|
* Dist.of Old entry|calcStackDist |Cleanevicts/Invalidate|
|
|
|
|
*
|
|
|
|
* Node Balancing: The tree structure is maintained by an
|
|
|
|
* updateTree() operation called when an intermediate node is
|
|
|
|
* required. The update operation is roughly categorized as a root
|
|
|
|
* update or intermediate layer update. When number of leaf nodes
|
|
|
|
* grow over a power of 2 then a new layer is added at the top of the
|
|
|
|
* tree and a new root node is initialized. The old node at the lower
|
|
|
|
* layer is connected to this. In an intermediate node update
|
|
|
|
* operation a new intermediate node is added to the required layer.
|
|
|
|
*
|
|
|
|
* Debugging: Debugging can be enabled by setting the verifyStack flag
|
|
|
|
* true. Debugging is implemented using a dummy stack that behaves in
|
|
|
|
* a naive way, using STL vectors (i.e each unique address is pushed
|
|
|
|
* on the top of an STL vector stack, and SD is returned as
|
|
|
|
* Infinity. If a non unique address is encountered then the previous
|
|
|
|
* entry in the STL vector is removed, all the entities above it are
|
|
|
|
* pushed down, and the address is pushed at the top of the stack).
|
|
|
|
*
|
|
|
|
* A printStack(int numOfEntitiesToPrint) is provided to print top n entities
|
|
|
|
* in both (tree and STL based dummy stack).
|
|
|
|
*/
|
2015-08-04 11:29:13 +02:00
|
|
|
class StackDistCalc
|
2014-12-23 15:31:18 +01:00
|
|
|
{
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
|
|
|
struct Node;
|
|
|
|
|
|
|
|
typedef std::map<uint64_t, Node*> IndexNodeMap;
|
|
|
|
typedef std::map<Addr, uint64_t> AddressIndexMap;
|
|
|
|
typedef std::vector<IndexNodeMap> TreeType;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Gets sum from the node upwards recursively till the root. This
|
|
|
|
* function is called first by getSumsLeavesToRoot, and then
|
|
|
|
* recursively calls itself.
|
|
|
|
*
|
|
|
|
* @param node pointer to the node which is updated
|
|
|
|
* @param from_left variable which says that the request arrived
|
|
|
|
* from the left
|
|
|
|
* @param sum_from_below Sum of left and right children below
|
|
|
|
* @param level level in the tree the calling node is located
|
|
|
|
* @param stack_dist stack distance of the node below
|
|
|
|
* @return The stack distance of the current address.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
uint64_t getSum(Node* node, bool from_left, uint64_t sum_from_below,
|
|
|
|
uint64_t stack_dist, uint64_t level) const;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Gets the sum from the leaf node specified. This function
|
|
|
|
* is called by calcStackDist.
|
|
|
|
*
|
|
|
|
* @param node pointer to the node which is updated
|
|
|
|
* @return The stack distance of the current address.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
uint64_t getSumsLeavesToRoot(Node* node) const;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Updates the nodes upwards recursively till the root.
|
|
|
|
* This function is first called by updateSumsLeavesToRoot,
|
|
|
|
* and then it recursively calls itself.
|
|
|
|
*
|
|
|
|
* @param node pointer to the node which is updated
|
|
|
|
* @param from_left variable which says that the request arrived
|
|
|
|
* from the left
|
|
|
|
* @param sum_from_below Sum of left and right children below
|
|
|
|
* @param level level in the tree the calling node is located
|
|
|
|
* @param stack_dist stack distance of the node below
|
|
|
|
* @param discard_node whether the calling node was discarded or not
|
|
|
|
* @return The stack distance of the current address.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
uint64_t updateSum(Node* node,
|
|
|
|
bool from_left, uint64_t sum_from_below, uint64_t level,
|
|
|
|
uint64_t stack_dist, bool discard_node);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Updates the leaf nodes and nodes above. This function is
|
|
|
|
* called by the calcStackDistAndUpdate.
|
|
|
|
*
|
|
|
|
* @param node pointer to the node which is updated
|
|
|
|
* @param is_new_leaf is true if this is a newly added node
|
|
|
|
* @return The stack distance of the current address.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
uint64_t updateSumsLeavesToRoot(Node* node, bool is_new_leaf);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* updateTree 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 updateTree();
|
|
|
|
|
|
|
|
/**
|
|
|
|
* This method is used for verification purposes
|
|
|
|
* It recursively traverses upwards from the given node till
|
|
|
|
* the root to check if the ultimate parent node (root-node) points
|
|
|
|
* to null.
|
|
|
|
*
|
|
|
|
* @param node pointer to the node whose sanity is being checked
|
|
|
|
* @param level the level at which this node is located in the tree
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
void sanityCheckTree(const Node* node, uint64_t level = 0) const;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Return the counter for address accesses (unique and
|
|
|
|
* non-unique). This is further used to dump stats at
|
|
|
|
* regular intervals.
|
|
|
|
*
|
|
|
|
* @return The stack distance of the current address.
|
|
|
|
*/
|
|
|
|
uint64_t getIndex() const { return index; }
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Query depth of the tree (tree[0] represents leaf layer while
|
|
|
|
* tree[treeDepth] represents the root layer, all layers in
|
|
|
|
* between contain intermediate nodes)
|
|
|
|
*
|
|
|
|
* @return Tree depth
|
|
|
|
*/
|
|
|
|
uint64_t getTreeDepth() const { return tree.size() - 1; }
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Print the last n items on the stack.
|
|
|
|
* This method prints top n entries in the tree based implementation as
|
|
|
|
* well as dummy stack.
|
|
|
|
* @param n Number of entries to print
|
|
|
|
*/
|
|
|
|
void printStack(int n = 5) const;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* This is an alternative implementation of the stack-distance
|
|
|
|
* in a naive way. It uses simple STL vector to represent the stack.
|
|
|
|
* It can be used in parallel for debugging purposes.
|
|
|
|
* It is 10x slower than the tree based implemenation.
|
|
|
|
*
|
|
|
|
* @param r_address The current address to process
|
|
|
|
* @param update_stack Flag to indicate if stack should be updated
|
|
|
|
* @return Stack distance which is calculated by this alternative
|
|
|
|
* implementation
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
uint64_t verifyStackDist(const Addr r_address,
|
|
|
|
bool update_stack = false);
|
|
|
|
|
|
|
|
public:
|
2015-08-04 11:29:13 +02:00
|
|
|
StackDistCalc(bool verify_stack = false);
|
|
|
|
|
|
|
|
~StackDistCalc();
|
2014-12-23 15:31:18 +01:00
|
|
|
|
|
|
|
/**
|
2015-08-04 11:29:13 +02:00
|
|
|
* A convenient way of refering to infinity.
|
2014-12-23 15:31:18 +01:00
|
|
|
*/
|
2015-08-04 11:29:13 +02:00
|
|
|
static constexpr uint64_t Infinity = std::numeric_limits<uint64_t>::max();
|
2014-12-23 15:31:18 +01:00
|
|
|
|
|
|
|
|
2015-08-04 11:29:13 +02:00
|
|
|
/**
|
|
|
|
* Process the given address. If Mark is true then set the
|
|
|
|
* mark flag of the leaf node.
|
|
|
|
* This function returns the stack distance of the incoming
|
|
|
|
* address and the previous status of the mark flag.
|
|
|
|
*
|
|
|
|
* @param r_address The current address to process
|
|
|
|
* @param mark set the mark flag for the address.
|
|
|
|
* @return The stack distance of the current address and the mark flag.
|
|
|
|
*/
|
|
|
|
std::pair<uint64_t, bool> calcStackDist(const Addr r_address,
|
|
|
|
bool mark = false);
|
2014-12-23 15:31:18 +01:00
|
|
|
|
|
|
|
/**
|
2015-08-04 11:29:13 +02:00
|
|
|
* Process the given address:
|
|
|
|
* - Lookup the tree for the given address
|
|
|
|
* - delete old node if found in tree
|
|
|
|
* - add a new node (if addNewNode flag is set)
|
|
|
|
* This function returns the stack distance of the incoming
|
|
|
|
* address and the status of the mark flag.
|
2014-12-23 15:31:18 +01:00
|
|
|
*
|
2015-08-04 11:29:13 +02:00
|
|
|
* @param r_address The current address to process
|
|
|
|
* @param addNewNode If true, a new node is added to the tree
|
|
|
|
* @return The stack distance of the current address and the mark flag.
|
2014-12-23 15:31:18 +01:00
|
|
|
*/
|
2015-08-04 11:29:13 +02:00
|
|
|
std::pair<uint64_t, bool> calcStackDistAndUpdate(const Addr r_address,
|
|
|
|
bool addNewNode = true);
|
2014-12-23 15:31:18 +01:00
|
|
|
|
|
|
|
private:
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Node which takes form of Leaf, INode or Root
|
|
|
|
*/
|
|
|
|
struct Node{
|
|
|
|
// Sum of the left children
|
|
|
|
uint64_t sumLeft;
|
|
|
|
|
|
|
|
// Sum of the right children
|
|
|
|
uint64_t sumRight;
|
|
|
|
|
|
|
|
// Flag to indicate that sumLeft has gone from non-zero value to 0
|
|
|
|
bool discardLeft;
|
|
|
|
|
|
|
|
// Flag to indicate that sumRight has gone from non-zero value to 0
|
|
|
|
bool discardRight;
|
|
|
|
|
|
|
|
// Index of the current element in the Map
|
|
|
|
uint64_t nodeIndex;
|
|
|
|
|
|
|
|
// Pointer to the parent
|
|
|
|
Node* parent;
|
|
|
|
|
|
|
|
// Flag to mark the node as the right/left child
|
|
|
|
bool isLeftNode;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Flag to indicate if this address is marked. Used in case
|
|
|
|
* where stack distance of a touched address is required.
|
|
|
|
*/
|
|
|
|
bool isMarked;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* The discard flags are false by default they become true if
|
|
|
|
* the node is reached again in a future lookup.
|
|
|
|
*/
|
|
|
|
Node() : sumLeft(0), sumRight(0), discardLeft(false),
|
|
|
|
discardRight(false), nodeIndex(0),
|
|
|
|
parent(nullptr), isLeftNode(true), isMarked(false)
|
|
|
|
{ }
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Internal counter for address accesses (unique and non-unique)
|
|
|
|
* This counter increments everytime the calcStackDist() method is
|
|
|
|
* called. This counter is used as a key for the hash- map at the
|
|
|
|
* leaf layer. Practically at every call to the calculator this
|
|
|
|
* counter is incremented and a new leaf node is added in the tree
|
|
|
|
* at the leaf layer using this counter value as the key.
|
|
|
|
*/
|
|
|
|
uint64_t index;
|
|
|
|
|
|
|
|
// Binary tree of partial sums
|
|
|
|
TreeType tree;
|
|
|
|
|
|
|
|
// Hash map which returns last seen index of each address
|
|
|
|
AddressIndexMap aiMap;
|
|
|
|
|
|
|
|
// Keeps count of number of the next unique index for each
|
|
|
|
// level in the tree
|
|
|
|
std::vector<uint64_t> nextIndex;
|
|
|
|
|
|
|
|
// Dummy Stack for verification
|
|
|
|
std::vector<uint64_t> stack;
|
|
|
|
|
|
|
|
// Flag to enable verification of stack. (Slows down the simulation)
|
|
|
|
const bool verifyStack;
|
|
|
|
};
|
|
|
|
|
2015-08-04 11:29:13 +02:00
|
|
|
|
2014-12-23 15:31:18 +01:00
|
|
|
#endif //__STACK_DIST_CALC_HH__
|