Skip to content

i#7731: Optimize reuse distance collection using splay tree#7732

Open
artur-abd wants to merge 36 commits intoDynamoRIO:masterfrom
artur-abd:i7731-optimize-reuse-distance
Open

i#7731: Optimize reuse distance collection using splay tree#7732
artur-abd wants to merge 36 commits intoDynamoRIO:masterfrom
artur-abd:i7731-optimize-reuse-distance

Conversation

@artur-abd
Copy link
Copy Markdown

@artur-abd artur-abd commented Nov 26, 2025

Improve reuse distance using splay tree instead of linked list. Splay tree have asymptotic O(log n) amortizated time for all operations instead of O(n / const) for linked list with skip list.
Perfomance improve achives in avarage 10-40% based on different benchmarks.

Fixes #7731

@artur-abd artur-abd changed the title i#7731: Replace linked list with splay tree i#7731: Optimize reuse distance collection using splay tree Nov 26, 2025
@artur-abd artur-abd marked this pull request as draft November 27, 2025 05:35
@artur-abd artur-abd force-pushed the i7731-optimize-reuse-distance branch 2 times, most recently from 4b6bffb to 3961c95 Compare November 27, 2025 13:24
Improve reuse distance using splay tree instead of linked list. Splay tree have asymptotic O(log n) amortizated time for all operations instead of O(n / const) for linked list with skip list.
Perfomance improve achives in avarage 10-40% based on different benchmarks.

Fixes DynamoRIO#7731
@artur-abd artur-abd force-pushed the i7731-optimize-reuse-distance branch from 3961c95 to 1b8aa74 Compare November 27, 2025 13:26
@artur-abd artur-abd marked this pull request as ready for review November 27, 2025 13:37
@derekbruening
Copy link
Copy Markdown
Contributor

Thank you for contributing. Please mark for review when ready. Also, please don't force-push a shared branch: see https://dynamorio.org/page_code_reviews.html about squash-and-merge, where the final merge commit message comes from, and how force pushes break the review process. Use separate incremental commits with commit messages that describe what each one is doing (and not just repeating the merge message).

Fixes description for line_ref_splay_t and it's methods

Fixes: DynamoRIO#7731
@artur-abd
Copy link
Copy Markdown
Author

artur-abd commented Dec 1, 2025

Thanks for your comments. PR is ready for review.
Tests for ci-windows / vs2022-64 (pull_request) is failed due to a timeout in other modules. Self triggered tests passed.

@abhinav92003 abhinav92003 self-requested a review December 2, 2025 19:47
Comment thread clients/drcachesim/tools/reuse_distance.h Outdated
Comment thread clients/drcachesim/tools/reuse_distance.h Outdated
Comment thread clients/drcachesim/tools/reuse_distance.h Outdated
Comment thread clients/drcachesim/tools/reuse_distance.h Outdated
Comment thread clients/drcachesim/tools/reuse_distance.h Outdated
Comment thread clients/drcachesim/tools/reuse_distance.h Outdated
Copilot AI review requested due to automatic review settings January 23, 2026 12:30
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Optimizes drcachesim’s reuse-distance collection by replacing the linked-list (+skip list) data structure with a splay tree to reduce per-access overhead.

Changes:

  • Replaced the internal reuse-distance tracking structure with a splay tree implementation.
  • Updated reuse-distance tool/shard wiring to use the new node type and tree container.
  • Added unit tests for the splay tree and marked skip-list-related CLI options as deprecated.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 9 comments.

Show a summary per file
File Description
clients/drcachesim/tools/reuse_distance.h Replaces list/skip-list logic with a splay tree, adds splay operations and subtree-size tracking.
clients/drcachesim/tools/reuse_distance.cpp Updates shard initialization and reuse-distance processing to use the new node/tree types.
clients/drcachesim/tests/reuse_distance_test.cpp Adds a dedicated splay-tree correctness/invariant test.
clients/drcachesim/common/options.h Renames the skip-list distance option variable to reflect deprecation.
clients/drcachesim/common/options.cpp Deprecates skip-list-related option help text (and keeps CLI flag name).
clients/drcachesim/analyzer_multi.cpp Updates option wiring to use the renamed deprecated option variable.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread clients/drcachesim/tools/reuse_distance.h
Comment thread clients/drcachesim/tools/reuse_distance.h Outdated
Comment thread clients/drcachesim/common/options.cpp Outdated
Comment thread clients/drcachesim/tools/reuse_distance.h
Comment thread clients/drcachesim/tools/reuse_distance.h Outdated
Comment thread clients/drcachesim/tools/reuse_distance.h
Comment thread clients/drcachesim/tools/reuse_distance.h Outdated
Comment thread clients/drcachesim/common/options.cpp Outdated
Comment thread clients/drcachesim/tests/reuse_distance_test.cpp Outdated
@artur-abd
Copy link
Copy Markdown
Author

@abhinav92003, thanks for review.
I've added tests and marked the skip list options as deprecated.
However, I'm not sure that extracting this splay tree implementation into ext is a good idea, for the reason I mentioned above.

@artur-abd
Copy link
Copy Markdown
Author

@abhinav92003
Hi, Any more questions for the PR?
I haven't applied a couple of changes you suggested before because I'm not sure the software design would be well. Please look at the detailed description in the commented answer. Let's discuss it in detail if you disagree.

@abhinav92003
Copy link
Copy Markdown
Contributor

@abhinav92003 Hi, Any more questions for the PR? I haven't applied a couple of changes you suggested before because I'm not sure the software design would be well. Please look at the detailed description in the commented answer. Let's discuss it in detail if you disagree.

Ack. I'll review the new changes.

Comment thread clients/drcachesim/common/options.cpp Outdated
Comment thread clients/drcachesim/tests/reuse_distance_test.cpp
Comment thread clients/drcachesim/tools/reuse_distance.h Outdated
Comment thread clients/drcachesim/tests/reuse_distance_test.cpp
Comment thread clients/drcachesim/tools/reuse_distance.h
Comment thread clients/drcachesim/tools/reuse_distance.h Outdated
Comment thread clients/drcachesim/tools/reuse_distance.h
return 0;
splay(ref);
// Get the reuse distance of ref.
int64_t dist = get_size(ref->left);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

get_size(ref->left) is the reuse distance of ref only because we did the splay operation on ref before this correct? Add comment.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, after the splay operation, ref becomes the root of the splay tree, and the index of these elements is exactly equal to the size of the left subtree.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adding this to the code comment would be helpful to a future reader.

struct line_ref_node_t *right; // the right child of the node
struct line_ref_node_t *parent; // the parent of the node
uint64_t size; // Size of the subtree
uint64_t time_stamp; // the most recent reference time stamp on this line
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The splay tree maintains the ordered binary tree invariant on time_stamp right (larger timestamps on the left subtree), right? Add to comment.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The splay tree maintains this invariant, but time_stamp is just additional data to verify that the ref is distant.
The splay tree implicitly supports an array, where the element index is the number of node that are to the left. I took this idea from an implicit treap. I also benchmarked implementation based on implicit treap, but it was slowed by 5-15%.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The splay tree maintains this invariant, but time_stamp is just additional data to verify that the ref is distant.

Add to comment?

Comment thread clients/drcachesim/common/options.cpp
@artur-abd
Copy link
Copy Markdown
Author

@abhinav92003, thanks for your comments, I added an implementation selection using a flag, and also fixed the tests to test both implementations.

@artur-abd artur-abd requested a review from abhinav92003 March 26, 2026 14:51
@abhinav92003
Copy link
Copy Markdown
Contributor

@abhinav92003, thanks for your comments, I added an implementation selection using a flag, and also fixed the tests to test both implementations.

Thanks; will review the new changes.

Copy link
Copy Markdown
Contributor

@abhinav92003 abhinav92003 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have just a few minor comments. LGTM.

Thanks for the contribution. This is a useful optimization. And apologies for the (much) longer than usual turnaround time in my reviews.

DROPTION_SCOPE_FRONTEND, "reuse_splay_tree", false,
"Use splay tree for reuse distance calculation.",
"Uses a splay tree data structure instead of a skip list for tracking reuse "
"distances. Splay tree provide better complexity and consume less memory "
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

s/better complexity/better time complexity/

};

struct line_ref_entry_t {
uint64_t time_stamp; // the most recent reference time stamp on this line
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Either delete the default constructor if we don't need it, or add in-place init for these members. Same for other structs.

}
};

/* A splay tree node for the cache line reference info */
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add banner comment (example at https://dynamorio.org/page_code_style.html) to separate out the splay tree related functions.

{
std::cerr << "Reuse tag list:\n";
line_ref_node_t *node = root_;
// the last visited node
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suppose this is the last visited node in the current node's subtree? Or if there's none such, it's nullptr. Update comment.

// more efficient computation of the depth. Each node in the skip
// list stores its depth from the front.
struct line_ref_list_t {
struct line_ref_list_t : public line_ref_container_t {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As per https://dynamorio.org/page_code_style.html, this should be a class as well because it has methods other than the constructor.

// The splay tree is a binary search tree that uses the splay operation for balancing,
// which allows deleting and inserting an element at any position in O(log n) amortized
// time.
class line_ref_splay_t : public line_ref_container_t {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It will be nicer if the implementation could be moved to the cpp file, instead of the header.

new_parent->parent = node->parent;
}
if (node->parent == nullptr)
root_ = new_parent;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, since splay has the preconditions to call it. Add comment by the assert at L873?

}

if (node->parent == nullptr)
root_ = new_parent;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, since splay has the preconditions to call it. Add comment by the assert at L848?

return 0;
splay(ref);
// Get the reuse distance of ref.
int64_t dist = get_size(ref->left);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adding this to the code comment would be helpful to a future reader.

struct line_ref_node_t *right; // the right child of the node
struct line_ref_node_t *parent; // the parent of the node
uint64_t size; // Size of the subtree
uint64_t time_stamp; // the most recent reference time stamp on this line
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The splay tree maintains this invariant, but time_stamp is just additional data to verify that the ref is distant.

Add to comment?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

drcachecim/reuse_distance Optimize perfomance

4 participants