gem5 v24.0.0.0
Loading...
Searching...
No Matches
stack_dist_calc.cc
Go to the documentation of this file.
1/*
2 * Copyright (c) 2014-2015 ARM Limited
3 * All rights reserved
4 *
5 * The license below extends only to copyright in the software and shall
6 * not be construed as granting a license to any other intellectual
7 * property including but not limited to intellectual property relating
8 * to a hardware implementation of the functionality of the software
9 * licensed hereunder. You may use the software subject to the license
10 * terms below provided that you ensure that this notice is replicated
11 * unmodified and in its entirety in all distributions of the software,
12 * modified or unmodified, in source code or in binary form.
13 *
14 * Redistribution and use in source and binary forms, with or without
15 * modification, are permitted provided that the following conditions are
16 * met: redistributions of source code must retain the above copyright
17 * notice, this list of conditions and the following disclaimer;
18 * redistributions in binary form must reproduce the above copyright
19 * notice, this list of conditions and the following disclaimer in the
20 * documentation and/or other materials provided with the distribution;
21 * neither the name of the copyright holders nor the names of its
22 * contributors may be used to endorse or promote products derived from
23 * this software without specific prior written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
26 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
27 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
28 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
29 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
30 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
31 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
32 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
33 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
34 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
35 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36 */
37
39
41#include "base/intmath.hh"
42#include "base/logging.hh"
43#include "base/trace.hh"
44#include "debug/StackDist.hh"
45
46namespace gem5
47{
48
50 : index(0),
51 verifyStack(verify_stack)
52{
53 // Instantiate a new root and leaf layer
54 // Map type variable, representing a layer in the tree
55 IndexNodeMap tree_level;
56
57 // Initialize tree count for leaves
58 nextIndex.push_back(0);
59
60 // Add the initial leaf layer to the tree
61 tree.push_back(tree_level);
62
63 // Create a root node. Node type variable in the topmost layer
64 Node* root_node = new Node();
65
66 // Initialize tree count for root
67 nextIndex.push_back(1);
68
69 // Add the empty root layer to the tree
70 tree.push_back(tree_level);
71
72 // Add the initial root to the tree
73 tree[1][root_node->nodeIndex] = root_node;
74}
75
77{
78 // Walk through each layer and destroy the nodes
79 for (auto& layer : tree) {
80 for (auto& index_node : layer) {
81 // each map entry contains an index and a node
82 delete index_node.second;
83 }
84 // Clear each layer in the tree
85 layer.clear();
86 }
87
88 // Clear the tree
89 tree.clear();
90 aiMap.clear();
91 nextIndex.clear();
92
93 // For verification
94 stack.clear();
95}
96
97// The updateSum method is a recursive function which updates
98// the node sums till the root. It also deletes the nodes that
99// are not used anymore.
100uint64_t
101StackDistCalc::updateSum(Node* node, bool from_left,
102 uint64_t sum_from_below, uint64_t level,
103 uint64_t stack_dist, bool discard_node)
104{
105 ++level;
106
107 // Make a copy of the node variables and work on them
108 // as a node may be deleted by this function
109 uint64_t node_sum_l = node->sumLeft;
110 uint64_t node_sum_r = node->sumRight;
111 bool node_left = node->isLeftNode;
112 bool node_discard_left = node->discardLeft;
113 bool node_discard_right = node->discardRight;
114 uint64_t node_n_index = node->nodeIndex;
115 Node* node_parent_ptr = node->parent;
116
117 // For verification
118 if (verifyStack) {
119 // This sanity check makes sure that the left_sum and
120 // right_sum of the node is not greater than the
121 // maximum possible value given by the leaves below it
122 // for example a node in layer 3 (tree[3]) can at most
123 // have 8 leaves (4 to the left and 4 to the right)
124 // thus left_sum and right_sum should be <= 4
125 panic_if(node_sum_l > (1 << (level - 1)),
126 "Error in sum left of level %ul, node index %ull, "
127 "Sum = %ull \n", level, node_n_index, node_sum_l);
128
129 panic_if(node_sum_r > (1 << (level - 1)),
130 "Error in sum right of level %ul, node index %ull, "
131 "Sum = %ull \n", level, node_n_index, node_sum_r);
132 }
133
134 // Update the left sum or the right sum depending on the
135 // from_left flag. Variable stack_dist is updated only
136 // when arriving from Left.
137 if (from_left) {
138 // update sumLeft
139 node_sum_l = sum_from_below;
140 stack_dist += node_sum_r;
141 } else {
142 // update sum_r
143 node_sum_r = sum_from_below;
144 }
145
146 // sum_from_below == 0 can be a leaf discard operation
147 if (discard_node && !sum_from_below) {
148 if (from_left)
149 node_discard_left = true;
150 else
151 node_discard_right = true;
152 }
153
154 // Update the node variables with new values
155 node->nodeIndex = node_n_index;
156 node->sumLeft = node_sum_l;
157 node->sumRight = node_sum_r;
158 node->isLeftNode = node_left;
159 node->discardLeft = node_discard_left;
160 node->discardRight = node_discard_right;
161
162 // Delete the node if it is not required anymore
163 if (node_discard_left && node_discard_right &&
164 discard_node && node_parent_ptr && !sum_from_below) {
165 delete node;
166 tree[level].erase(node_n_index);
167 discard_node = true;
168 } else {
169 // propogate discard_node as false upwards if the
170 // above conditions are not met.
171 discard_node = false;
172 }
173
174 // Recursively call the updateSum operation till the
175 // root node is reached
176 if (node_parent_ptr) {
177 stack_dist = updateSum(node_parent_ptr, node_left,
178 node_sum_l + node_sum_r,
179 level, stack_dist, discard_node);
180 }
181
182 return stack_dist;
183}
184
185// This function is called by the calcStackDistAndUpdate function
186// If is_new_leaf is true then a new leaf is added otherwise a leaf
187// removed from the tree. In both cases the tree is updated using
188// the updateSum operation.
189uint64_t
191{
192 uint64_t level = 0;
193 uint64_t stack_dist = 0;
194
195 if (is_new_leaf) {
196 node->sumLeft = 1;
197 updateSum(node->parent,
198 node->isLeftNode, node->sumLeft,
199 level, 0, false);
200
201 stack_dist = Infinity;
202 } else {
203 node->sumLeft = 0;
204 stack_dist = updateSum(node->parent,
205 node->isLeftNode, 0,
206 level, stack_dist, true);
207 }
208
209 return stack_dist;
210}
211
212// This method is a recursive function which calculates
213// the node sums till the root.
214uint64_t
215StackDistCalc::getSum(Node* node, bool from_left, uint64_t sum_from_below,
216 uint64_t stack_dist, uint64_t level) const
217{
218 ++level;
219 // Variable stack_dist is updated only
220 // when arriving from Left.
221 if (from_left) {
222 stack_dist += node->sumRight;
223 }
224
225 // Recursively call the getSum operation till the
226 // root node is reached
227 if (node->parent) {
228 stack_dist = getSum(node->parent, node->isLeftNode,
229 node->sumLeft + node->sumRight,
230 stack_dist, level);
231 }
232
233 return stack_dist;
234}
235
236// This function is called by the calcStackDistance function
237uint64_t
239{
240 return getSum(node->parent, node->isLeftNode, 0, 0, 0);
241}
242
243// Update tree is a tree balancing operation which maintains
244// the binary tree structure. This method is called whenever
245// index%2 == 0 (i.e. every alternate cycle)
246// The two main operation are :
247// OP1. moving the root node one layer up if index counter
248// crosses power of 2
249// OP2. Addition of intermediate nodes as and when required
250// and linking them to their parents in the layer above.
251void
253{
254 uint64_t i;
255
256 if (isPowerOf2(index)) {
257 // OP1. moving the root node one layer up if index counter
258 // crosses power of 2
259 // If index counter crosses a power of 2, then add a
260 // new tree layer above and create a new Root node in it.
261 // After the root is created the old node
262 // in the layer below is updated to point to this
263 // newly created root node. The sum_l of this new root node
264 // becomes the sum_l + sum_r of the old node.
265 //
266 // After this root update operation a chain of intermediate
267 // nodes is created from root layer to tree[1](one layer
268 // above the leaf layer)
269
270 // Create a new root node
271 Node* newRootNode = new Node();
272
273 // Update its sum_l as the sum_l+sum_r from below
274 newRootNode->sumLeft = tree[getTreeDepth()][0]->sumRight +
275 tree[getTreeDepth()][0]->sumLeft;
276 // Update its discard left flag if the node below has
277 // has both discardLeft and discardRight set.
278 newRootNode->discardLeft = tree[getTreeDepth()][0]->discardLeft &&
279 tree[getTreeDepth()][0]->discardRight;
280
281 // Map type variable, representing a layer in the tree
282 IndexNodeMap treeLevel;
283 // Add a new layer to the tree
284 tree.push_back(treeLevel);
285 nextIndex.push_back(1);
286 tree[getTreeDepth()][newRootNode->nodeIndex] = newRootNode;
287
288 // Update the parent pointer at lower layer to
289 // point to newly created root node
290 tree[getTreeDepth() - 1][0]->parent = tree[getTreeDepth()][0];
291
292 // Add intermediate nodes from root till bottom (one layer above the
293 // leaf layer)
294 for (i = getTreeDepth() - 1; i >= 1; --i) {
295 Node* newINode = new Node();
296 // newNode is left or right child depending on the number of nodes
297 // in that layer
298 if (nextIndex[i] % 2 == 0) {
299 newINode->isLeftNode = true;
300 } else {
301 newINode->isLeftNode = false;
302 }
303
304 newINode->parent = tree[i + 1][nextIndex[i + 1] - 1];
305 newINode->nodeIndex = ++nextIndex[i] - 1;
306 tree[i][newINode->nodeIndex] = newINode;
307 }
308 } else {
309 // OP2. Addition of intermediate nodes as and when required
310 // and linking them to their parents in the layer above.
311 //
312 // At layer 1 a new INode is added whenever index%(2^1)==0
313 // (multiples of 2)
314 //
315 // At layer 2 a new INode is added whenever index%(2^2)==0
316 // (multiples of 4)
317 //
318 // At layer 3 a new INode is added whenever index%(2^3)==0
319 // (multiples of 8)
320 //...
321 //
322 // At layer N a new INode is added whenever index%(2^N)==0
323 // (multiples of 2^N)
324 for (i = getTreeDepth() - 1; i >= 1; --i) {
325 // Traverse each layer from root to leaves and add a new
326 // intermediate node if required. Link the parent_ptr of
327 // the new node to the parent in the above layer.
328
329 if ((index % (1 << i)) == 0) {
330 // Checks if current (index % 2^treeDepth) == 0 if true
331 // a new node at that layer is created
332 Node* newINode = new Node();
333
334 // newNode is left or right child depending on the
335 // number of nodes in that layer.
336 if (nextIndex[i] % 2 == 0) {
337 newINode->isLeftNode = true;
338 } else {
339 newINode->isLeftNode = false;
340 }
341
342 // Pointing to its parent in the upper layer
343 newINode->parent = tree[i + 1][nextIndex[i + 1] - 1];
344 newINode->nodeIndex = ++nextIndex[i] - 1;
345 tree[i][newINode->nodeIndex] = newINode;
346 }
347 }
348 }
349}
350
351// This function is called everytime to get the stack distance and add
352// a new node. A feature to mark an old node in the tree is
353// added. This is useful if it is required to see the reuse
354// pattern. For example, BackInvalidates from the lower level (Membus)
355// to L2, can be marked (isMarked flag of Node set to True). And then
356// later if this same address is accessed by L1, the value of the
357// isMarked flag would be True. This would give some insight on how
358// the BackInvalidates policy of the lower level affect the read/write
359// accesses in an application.
361StackDistCalc::calcStackDistAndUpdate(const Addr r_address, bool addNewNode)
362{
363 Node* newLeafNode;
364
365 auto ai = aiMap.lower_bound(r_address);
366
367 // Default value of flag indicating as the left or right leaf
368 bool isLeft = true;
369 // Default value of isMarked flag for each node.
370 bool _mark = false;
371 // By default stackDistacne is treated as infinity
372 uint64_t stack_dist;
373
374 // Lookup aiMap by giving address as the key:
375 // If found take address and Lookup in tree
376 // Update tree from leaves by making B(found index) = 0
377 // Add sums to right till root while Updating them
378 // Stack Distance of that address sums to right
379 if (ai != aiMap.end() && !(aiMap.key_comp()(r_address, ai->first))) {
380 // key already exists
381 // save the index counter value when this address was
382 // encountered before and update it to the current index value
383 uint64_t r_index = ai->second;
384
385 if (addNewNode) {
386 // Update aiMap aiMap(Address) = current index
387 ai->second = index;
388 } else {
389 aiMap.erase(r_address);
390 }
391
392 // Call update tree operation on the tree starting with
393 // the r_index value found above. This function would return
394 // the value of the stack distcance.
395 stack_dist = updateSumsLeavesToRoot(tree[0][r_index], false);
396 newLeafNode = tree[0][r_index];
397 // determine if this node was marked earlier
398 _mark = newLeafNode->isMarked;
399 delete newLeafNode;
400 tree[0].erase(r_index);
401 } else {
402 if (addNewNode) {
403 // Update aiMap aiMap(Address) = current index
404 aiMap[r_address] = index;
405 }
406 // Update infinity bin count
407 // By default stackDistacne is treated as infinity
408 stack_dist = Infinity;
409 }
410
411 if (addNewNode) {
412 // If index%2 == 0 then update tree
413 if (index % 2 == 0) {
414 updateTree();
415 } else {
416 // At odd values of index counter, a new right-type node is
417 // added to the leaf layer, else a left-type node is added
418 isLeft = false;
419 }
420
421 // Add new leaf node in the leaf layer (tree[0])
422 // set n_index = current index
423 newLeafNode = new Node();
424 ++nextIndex[0];
425 newLeafNode->nodeIndex=index;
426 newLeafNode->isLeftNode=isLeft;
427 // Point the parent pointer to the intermediate node above
428 newLeafNode->parent = tree[1][nextIndex[1] - 1];
429 tree[0][index] = newLeafNode;
430 // call an update operation which would update the tree after
431 // addition of this new leaf node.
433
434 // For verification
435 if (verifyStack) {
436 // This function checks the sanity of the tree to make sure the
437 // last node in the link of parent pointers is the root node.
438 // It takes a leaf node as an argument and traveses upwards till
439 // the root layer to check if the last parent is null
441
442 // Push the same element in debug stack, and check
443 uint64_t verify_stack_dist = verifyStackDist(r_address, true);
444 panic_if(verify_stack_dist != stack_dist,
445 "Expected stack-distance for address \
446 %#lx is %#lx but found %#lx",
447 r_address, verify_stack_dist, stack_dist);
448 printStack();
449 }
450
451 // The index counter is updated at the end of each transaction
452 // (unique or non-unique)
453 ++index;
454 }
455
456 return (std::make_pair(stack_dist, _mark));
457}
458
459// This function is called everytime to get the stack distance
460// no new node is added. It can be used to mark a previous access
461// and inspect the value of the mark flag.
463StackDistCalc::calcStackDist(const Addr r_address, bool mark)
464{
465 // Default value of isMarked flag for each node.
466 bool _mark = false;
467
468 auto ai = aiMap.lower_bound(r_address);
469
470 // By default stackDistacne is treated as infinity
471 uint64_t stack_dist = 0;
472
473 // Lookup aiMap by giving address as the key:
474 // If found take address and Lookup in tree
475 // Add sums to right till root
476 // Stack Distance of that address sums to right
477 if (ai != aiMap.end() && !(aiMap.key_comp()(r_address, ai->first))) {
478 // key already exists
479 // save the index counter value when this address was
480 // encountered before
481 uint64_t r_index = ai->second;
482
483 // Get the value of mark flag if previously marked
484 _mark = tree[0][r_index]->isMarked;
485 // Mark the leaf node if required
486 tree[0][r_index]->isMarked = mark;
487
488 // Call get sums operation on the tree starting with
489 // the r_index value found above. This function would return
490 // the value of the stack distcance.
491 stack_dist = getSumsLeavesToRoot(tree[0][r_index]);
492 } else {
493 // Update infinity bin count
494 // By default stackDistacne is treated as infinity
495 stack_dist = Infinity;
496 }
497
498 // For verification
499 if (verifyStack) {
500 // Calculate the SD of the same address in the debug stack
501 uint64_t verify_stack_dist = verifyStackDist(r_address);
502 panic_if(verify_stack_dist != stack_dist,
503 "Expected stack-distance for address \
504 %#lx is %#lx but found %#lx",
505 r_address, verify_stack_dist, stack_dist);
506
507 printStack();
508 }
509
510 return std::make_pair(stack_dist, _mark);
511}
512
513// For verification
514// Simple sanity check for the tree
515void
516StackDistCalc::sanityCheckTree(const Node* node, uint64_t level) const
517{
518 const Node* next_up = node->parent;
519
520 for (uint64_t i = level + 1; i < getTreeDepth() - level; ++i) {
521 next_up = next_up->parent;
522 panic_if(!next_up, "Sanity check failed for node %ull \n",
523 node->nodeIndex);
524 }
525
526 // At the root layer the parent_ptr should be null
527 panic_if(next_up->parent, "Sanity check failed for node %ull \n",
528 node->nodeIndex);
529}
530
531// This method can be called to compute the stack distance in a naive
532// way It can be used to verify the functionality of the stack
533// distance calculator. It uses std::vector to compute the stack
534// distance using a naive stack.
535uint64_t
536StackDistCalc::verifyStackDist(const Addr r_address, bool update_stack)
537{
538 bool found = false;
539 uint64_t stack_dist = 0;
540 auto a = stack.rbegin();
541
542 for (; a != stack.rend(); ++a) {
543 if (*a == r_address) {
544 found = true;
545 break;
546 } else {
547 ++stack_dist;
548 }
549 }
550
551 if (found) {
552 ++a;
553 if (update_stack)
554 stack.erase(a.base());
555 } else {
556 stack_dist = Infinity;
557 }
558
559 if (update_stack)
560 stack.push_back(r_address);
561
562 return stack_dist;
563}
564
565// This method is useful to print top n entities in the stack.
566void
568{
569 Node* node;
570 int count = 0;
571
572 DPRINTF(StackDist, "Printing last %d entries in tree\n", n);
573
574 // Walk through leaf layer to display the last n nodes
575 for (auto it = tree[0].rbegin(); (count < n) && (it != tree[0].rend());
576 ++it, ++count) {
577 node = it->second;
578 uint64_t r_index = node->nodeIndex;
579
580 // Lookup aiMap using the index returned by the leaf iterator
581 for (auto ai = aiMap.rbegin(); ai != aiMap.rend(); ++ai) {
582 if (ai->second == r_index) {
583 DPRINTF(StackDist,"Tree leaves, Rightmost-[%d] = %#lx\n",
584 count, ai->first);
585 break;
586 }
587 }
588 }
589
590 DPRINTF(StackDist,"Tree depth = %#ld\n", getTreeDepth());
591
592 if (verifyStack) {
593 DPRINTF(StackDist,"Printing Last %d entries in VerifStack \n", n);
594 count = 0;
595 for (auto a = stack.rbegin(); (count < n) && (a != stack.rend());
596 ++a, ++count) {
597 DPRINTF(StackDist, "Verif Stack, Top-[%d] = %#lx\n", count, *a);
598 }
599 }
600}
601
602} // namespace gem5
#define DPRINTF(x,...)
Definition trace.hh:210
Declaration and inline definition of ChunkGenerator object.
std::map< uint64_t, Node * > IndexNodeMap
std::vector< uint64_t > nextIndex
void updateTree()
updateTree is a tree balancing operation, which maintains the binary tree structure.
uint64_t getTreeDepth() const
Query depth of the tree (tree[0] represents leaf layer while tree[treeDepth] represents the root laye...
std::pair< uint64_t, bool > calcStackDist(const Addr r_address, bool mark=false)
Process the given address.
uint64_t getSumsLeavesToRoot(Node *node) const
Gets the sum from the leaf node specified.
AddressIndexMap aiMap
static constexpr uint64_t Infinity
A convenient way of refering to infinity.
uint64_t getSum(Node *node, bool from_left, uint64_t sum_from_below, uint64_t stack_dist, uint64_t level) const
Gets sum from the node upwards recursively till the root.
uint64_t updateSumsLeavesToRoot(Node *node, bool is_new_leaf)
Updates the leaf nodes and nodes above.
std::pair< uint64_t, bool > calcStackDistAndUpdate(const Addr r_address, bool addNewNode=true)
Process the given address:
uint64_t verifyStackDist(const Addr r_address, bool update_stack=false)
This is an alternative implementation of the stack-distance in a naive way.
void sanityCheckTree(const Node *node, uint64_t level=0) const
This method is used for verification purposes It recursively traverses upwards from the given node ti...
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 nodes upwards recursively till the root.
StackDistCalc(bool verify_stack=false)
std::vector< uint64_t > stack
void printStack(int n=5) const
Print the last n items on the stack.
uint64_t index
Internal counter for address accesses (unique and non-unique) This counter increments everytime the c...
STL pair class.
Definition stl.hh:58
static constexpr bool isPowerOf2(const T &n)
Definition intmath.hh:98
#define panic_if(cond,...)
Conditional panic macro that checks the supplied condition and only panics if the condition is true a...
Definition logging.hh:214
Bitfield< 31 > n
Bitfield< 7 > i
Definition misc_types.hh:67
Bitfield< 8 > a
Definition misc_types.hh:66
Bitfield< 30, 0 > index
Bitfield< 20 > level
Definition intmessage.hh:51
Copyright (c) 2024 - Pranith Kumar Copyright (c) 2020 Inria All rights reserved.
Definition binary32.hh:36
uint64_t Addr
Address type This will probably be moved somewhere else in the near future.
Definition types.hh:147
Node which takes form of Leaf, INode or Root.
bool isMarked
Flag to indicate if this address is marked.

Generated on Tue Jun 18 2024 16:24:05 for gem5 by doxygen 1.11.0