Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: manage call stacks using a tree #6791

Open
wants to merge 16 commits into
base: master
Choose a base branch
from
Open

Conversation

guipublic
Copy link
Contributor

Description

Problem*

Resolves #6603

Summary*

Call stacks are stored inside a big tree, which allows to share identical prefixes between call stacks

Additional Context

The only drawback is that we need to re-create the trees among function contexts during inlining

Documentation*

Check one:

  • No documentation needed.
  • Documentation included in this PR.
  • [For Experimental Features] Documentation to be submitted in a separate PR.

PR Checklist*

  • I have tested the changes locally.
  • I have formatted the changes with Prettier and/or cargo fmt on default settings.

Copy link
Contributor

github-actions bot commented Dec 12, 2024

Peak Memory Sample

Program Peak Memory %
keccak256 77.72M -2%
workspace 121.91M -1%
regression_4709 273.51M -5%
ram_blowup_regression 1.61G 0%
private-kernel-tail 202.33M -4%
private-kernel-reset 744.53M -13%
private-kernel-inner 308.49M 1%
parity-root 168.40M -4%

Copy link
Contributor

github-actions bot commented Dec 12, 2024

Compilation Sample

Program Compilation Time %
sha256_regression 0m1.490s 1%
regression_4709 0m0.811s 2%
ram_blowup_regression 0m15.972s -3%
rollup-base-public 6m51.466s 39%
rollup-base-private 3m38.207s 11%
private-kernel-tail 0m1.230s -13%
private-kernel-reset 0m8.276s -7%
private-kernel-inner 0m2.241s -12%
parity-root 0m0.919s -7%
noir-contracts 2m38.298s -9%

@TomAFrench
Copy link
Member

Looks like this is an improvement over #6747 and gets us closer to the optimal #6753 (comment)

@TomAFrench
Copy link
Member

We are eating a performance penalty however.

Copy link
Contributor

@jfecher jfecher left a comment

Choose a reason for hiding this comment

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

Some good improvements here - I wonder why regression_4709 increased so much in compilation time though. From the description it sounds like inlining could take longer but regression_4709 seems to be dominated by a large loop instead.

compiler/noirc_evaluator/src/ssa/ir/dfg.rs Outdated Show resolved Hide resolved
@guipublic
Copy link
Contributor Author

I wonder why regression_4709 increased so much in compilation time though. From the description it sounds like inlining could take longer but regression_4709 seems to be dominated by a large loop instead.

My guess is that it is due to getting a big list of flattened call stacks; not too deep but very wide, which means some elements have a lot of children and searching among them would be significant. I will try to use some sorted container for the children, like a btree.

Comment on lines 57 to 61
fn add_location(&self, location: Location, locations: &mut Vec<LocationNode>) -> CallStackId {
if let Some(result) = locations[self.index()]
.children
.iter()
.find(|child| locations[child.index()].value == location)
Copy link
Contributor

Choose a reason for hiding this comment

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

There are quite a few invariants assumed about the locations vector, e.g. that self is in it, and that the children of a LocationNode are all in it as well; it would be worth creating a newtype to wrap the Vec and make sure these invariants hold, and you're not dealing with just any odd vec! someone made.

Comment on lines 580 to 585
if self.location_array.is_empty() {
self.location_array.push(LocationNode {
parent: None,
children: vec![],
value: location,
});
Copy link
Contributor

Choose a reason for hiding this comment

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

I think the fact that here we have to think about the array being empty is a sign that the array itself should be a newtype that holds these methods, like self.location_array.add_location_to_root would establish the root ID, and then self.location_array.add_location(parent_id, location) would be an example of adding more stuff, rather than the IDs manipulating the collection.

Copy link
Contributor

@aakoshh aakoshh Dec 12, 2024

Choose a reason for hiding this comment

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

I mean the sign that something is not right is that a person cannot just safely do CallStackId::root().add_location(location, &mut self.location_array) because it might panic, so CallStackId alone is not responsible for the invariants, although it could special case add_location for when self.is_root() is true and the target is empty.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I tried to refactor this.

@@ -85,6 +86,8 @@ impl Function {
/// Note that any parameters or attributes of the function must be manually added later.
pub(crate) fn new(name: String, id: FunctionId) -> Self {
let mut dfg = DataFlowGraph::default();
// Adds root node for the location tree
dfg.add_location_to_root(Location::dummy());
Copy link
Contributor

Choose a reason for hiding this comment

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

Is this something that could be done in DataFlowGraph::default() itself?

Copy link
Contributor

@jfecher jfecher left a comment

Choose a reason for hiding this comment

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

LGTM - we may still want to change call stacks back to Vecs from lists now that we no longer need the sharing there

Copy link
Contributor

github-actions bot commented Dec 13, 2024

Changes to Brillig bytecode sizes

Generated at commit: 79abe7c0caf997b4cff3847c7fdc1b764dcacd34, compared to commit: f065c6682e2c896a346716cf88ac285f1d4bf846

🧾 Summary (10% most significant diffs)

Program Brillig opcodes (+/-) %
poseidonsponge_x5_254 +3 ❌ +0.07%
sha256_regression +3 ❌ +0.04%

Full diff report 👇
Program Brillig opcodes (+/-) %
poseidonsponge_x5_254 4,254 (+3) +0.07%
sha256_regression 6,920 (+3) +0.04%

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.

Reduce memory usage of tracking instruction callstacks in dfg.locations
4 participants