-
Notifications
You must be signed in to change notification settings - Fork 2.6k
Use Arc instead of Box for internal expression nodes in SymbolExpr #14660
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
Conversation
One or more of the following people are relevant to this code:
|
This commit updates the internal construction of the SymbolExpr struct use a reference counting pointer instead of a regular pointer to a heap allocated object. The way the binary tree gets constructed internally using a normal pointer results in a lot of a copies of elements on the tree. This creates a large performance overhead for the symbol expr as we end up copying and freeing elements on the binary tree a large amount. This was the root cause of the regression reported in Qiskit#14653 as the expression that gets generated by the transpiler internally ends up adding a lot of elements to global phase expression and that results in a lot of memory allocation and deallocation overhead. By using a reference counting pointer instead of creating and freeing copies of the expressions on the tree we instead only keep a single copy and just increment or decrement the reference count. Fixes Qiskit#14653
78283aa
to
1f7619e
Compare
Pull Request Test Coverage Report for Build 15837658367Details
💛 - Coveralls |
Thank you for making this fix. I tried it on my mac environment with script
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks good to me.
I've got one comment for a potential follow-up (hence approval without merge queue).
Value(Value), | ||
Unary { | ||
op: UnaryOp, | ||
expr: Box<SymbolExpr>, | ||
expr: Arc<SymbolExpr>, | ||
}, | ||
Binary { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
At least for Expr
, I put expression variants with multiple inner Expr
s within a single smart pointer, e.g. in this case:
struct Binary {
op: BinaryOp,
lhs: SymbolExpr,
rhs: SymbolExpr,
}
pub enum SymbolExpr {
Symbol(Box<String>),
Symbol(Arc<String>),
Value(Value),
Unary {
op: UnaryOp,
expr: Arc<SymbolExpr>,
},
Binary(Arc<Binary>),
}
I think maybe @doichanj had this as well originally. Perhaps that could help reduce fan-out.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah lets save this for a potential follow up PR. I was thinking this should be backported for a 2.1.1 and I would like to keep the diff minimal for the backport. I think adding a struct like you're proposing and using a single pointer like you're proposing is nice change.
…14660) This commit updates the internal construction of the SymbolExpr struct use a reference counting pointer instead of a regular pointer to a heap allocated object. The way the binary tree gets constructed internally using a normal pointer results in a lot of a copies of elements on the tree. This creates a large performance overhead for the symbol expr as we end up copying and freeing elements on the binary tree a large amount. This was the root cause of the regression reported in #14653 as the expression that gets generated by the transpiler internally ends up adding a lot of elements to global phase expression and that results in a lot of memory allocation and deallocation overhead. By using a reference counting pointer instead of creating and freeing copies of the expressions on the tree we instead only keep a single copy and just increment or decrement the reference count. Fixes #14653 (cherry picked from commit 3b26002)
…14660) (#14665) This commit updates the internal construction of the SymbolExpr struct use a reference counting pointer instead of a regular pointer to a heap allocated object. The way the binary tree gets constructed internally using a normal pointer results in a lot of a copies of elements on the tree. This creates a large performance overhead for the symbol expr as we end up copying and freeing elements on the binary tree a large amount. This was the root cause of the regression reported in #14653 as the expression that gets generated by the transpiler internally ends up adding a lot of elements to global phase expression and that results in a lot of memory allocation and deallocation overhead. By using a reference counting pointer instead of creating and freeing copies of the expressions on the tree we instead only keep a single copy and just increment or decrement the reference count. Fixes #14653 (cherry picked from commit 3b26002) Co-authored-by: Matthew Treinish <mtreinish@kortar.org>
Summary
This commit updates the internal construction of the SymbolExpr struct use a reference counting pointer instead of a regular pointer to a heap allocated object. The way the binary tree gets constructed internally using a normal pointer results in a lot of a copies of elements on the tree. This creates a large performance overhead for the symbol expr as we end up copying and freeing elements on the binary tree a large amount. This was the root cause of the regression reported in #14653 as the expression that gets generated by the transpiler internally ends up adding a lot of elements to global phase expression and that results in a lot of memory allocation and deallocation overhead. By using a reference counting pointer instead of creating and freeing copies of the expressions on the tree we instead only keep a single copy and just increment or decrement the reference count.
Details and comments
Fixes #14653