-
Notifications
You must be signed in to change notification settings - Fork 285
Use small intrusive pointer in irep #786
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
tautschnig
left a comment
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.
A few questions; I overall like this approach, but what we really need for this to move forward is a solid performance testing set up that has long been talked about.
src/util/irep.h
Outdated
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.
What is the rationale for this change?
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.
See following comment.
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.
Same here: keep it simple. We don't need to solve problems we don't have.
src/util/small_shared_ptr.h
Outdated
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.
What's the idea of the separate using directive, instead of just doing std::swap(t_, rhs.t_); ?
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.
In the general case, using std::swap allows you to place a custom swap for your type in a namespace other than std, because manually overloading std::swap isn't allowed. This overload can be found by Koenig lookup, but if not found will fall back to std::swap. In this case, this behaviour isn't strictly required, so I could just use std::swap directly.
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.
Keep it simple.
src/util/small_shared_ptr.h
Outdated
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.
What is the use case of this one?
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.
Like std::make_unique and std::make_shared, this has exception-safety benefits.
In the expression my_func(small_shared_ptr<X>(new X), small_shared_ptr<Y>(new Y)), the compiler is allowed to sequence the operations like so:
new X
new Y <-- This may throw and leak previously-allocated X
construct small_shared_ptr<X>
construct small_shared_ptr<Y>
my_func
Whereas my_func(make_small_shared_ptr<X>(), make_small_shared_ptr<Y>()) cannot leak because the calls to make_small_shared_ptr won't be interleaved.
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.
Shouldn't that be my_func(make_small_shared_ptr<X, Y>()) ?
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.
No, empty parameter packs are valid. You can see at irep.cpp:30 and irep.h:242 how the function is used in practice.
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.
Ok, I think I just misunderstood: your argument was about the order of invoking new vs the construction of small_shared_ptr, and not the order of the small_shared_ptr constructs (which is still unspecified). Fair enough. You may wish to add a comment to the constructor of small_shared_ptr to say that make_small_shared_ptr should be used in case of a new T argument.
What would be a use case where the parameter pack is non-empty? Is this just to support types other than dt that require >= 1 argument in their constructor?
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.
Yes, if you have a type with a constructor like my_type(Foo, Bar, Baz) then you can create a small_shared_ptr to it using make_small_shared_ptr<my_type>(Foo(), Bar(), Baz()) (for example).
This also avoids repetition of the identifier my_type (the alternative would be small_shared_ptr<my_type>(new my_type(Foo(), Bar(), Baz()) which is needlessly repetitive).
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.
Ok, thanks!
|
As said before, this looks good to me, and includes quite a bit of long overdue cleanup. Yet I don't dare setting any approval here in absence of a performance test suite. |
|
With 22170b7 my looks-good-to-me no longer applies. |
|
Yes, sorry about that - I think the copy-on-write implementation currently in irep is buggy because it allows you to make changes which affect copies in unexpected ways: I'm guessing this is why I'll close the PR and re-open when I have something that fixes this bug. |
|
I don't necessarily think you have to go as far as closing this one. How about making |
This commit merges the best aspects of two approaches to hash-based loop identification: - Clean implementation from PR diffblue#732 (bigweaver/clone-cbmc-private-20251130-231902) - Comprehensive testing from PR diffblue#786 (bigweaver/clone-cbmc-private-20251209-144542) Core Implementation (from PR diffblue#732): - Enhanced loop_idt struct with hash support and backward compatibility - compute_loop_hashes() using AST fingerprinting approach - Hash based on source location, loop structure, and body characteristics - Uses hash_combine() and hash_finalize() utilities - Clean separation of concerns with modular design Testing Infrastructure (from PR diffblue#786): - Unit tests: unit/goto-programs/loop_hash.cpp (Catch2-based) - Basic regression: 3 test suites (types, nested, stability) - Comprehensive suite: 21 automated test cases covering: * Position independence (11 tests) * Sensitivity to changes (4 tests) * Determinism (4 tests) * Special cases (2 tests) - Multiple test frameworks: Python (basic + enhanced) and Bash - Test utilities for hash comparison and extraction Key Benefits: - Loop identifiers stable across unrelated code changes - Hashes change appropriately when loop logic changes - Backward compatible with existing loop_number system - Comprehensive test coverage (21+ test cases) - Well-documented with extensive README files Files Modified: - Core: 5 implementation files in src/goto-programs/ - Tests: 52 test files (unit + regression) - Build: unit/Makefile updated See LOOP_HASH_MERGE_SUMMARY.md for detailed documentation.
Follows up #685. Rather than using
std::shared_ptrwhich uses more memory than is strictly necessary (an extra pointer to the control block in the shared_ptr itself, plus the control block memory) we use a customsmall_shared_ptrwhich is based on boost'sintrusive_ptr.This approach uses exactly the same amount of memory as was used previously, but separating the resource management into a separate class makes the logic a bit clearer, and greatly simplifies the copy- and move-assignment operators. It also means we don't need to explicitly redeclare custom move/copy constructors/assignment-ops in
irep.h.