-
Notifications
You must be signed in to change notification settings - Fork 104
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
#17754: Lower Indestructible to Metal, add guidance on using static vars with non-trivial destructors #17899
Conversation
@@ -1,4 +1,4 @@ | |||
# Best Practices for C++20 Repository | |||
# Best Practices for Contributing to TT Metal |
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.
Dropping "C++20" part. This is misleading in some cases, for example, the doc suggests to use tt:stl::Span
while C++20 has std::span
contributing/BestPractices.md
Outdated
|
||
// Option 2: If dynamic initialization is required, use function-local statics with `Indestructible`. | ||
const auto& get_data() { | ||
static Indestructible<std::string> kData("Disabled destructor! Good!"); |
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.
mb provide another example as seems like static std::string is always bad anyway.
// Bad: Using a static object with a non-trivial destructor. | ||
static const std::map<int, std::string> kDeviceConfigFiles = { | ||
{1, "n150.yaml"}, | ||
{2, "n300.yaml"}, | ||
{8, "t3000.yaml"} | ||
}; | ||
``` |
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 can go wrong in this example? Is it better to include an example with custom destructor like device?
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.
If you retain references to either key/value in another static singleton, that other destructor might access it after the memory is freed. This is of course overly simplistic and in isolation looks unrealistic, but just to illustrate the point. Easier to always be safe than to think of when / how things might break.
|
||
// Destructor does NOT call T's destructor. | ||
// This leaves the object "indestructible." | ||
~Indestructible() = default; |
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.
So the moment we start leveraging LeakSanitizer we're going to get flooded with reports?
Why can't we just enforce proper scopes and avoid globals/leaks/UB?
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.
AFAIK asan and leak sanitizers would be happy about it - as memory remains reachable at program exit, while we never run into use-after-free because all dtors are disabled. Having said that, I don't know for sure, but I would be very surprised if sanitizers don't understand this very common pattern.
Why can't we just enforce proper scopes and avoid globals/leaks/UB?
Sometimes it is way easier to use this pattern, basically wherever singleton pattern actually applies, but safer and more efficient.
|
||
namespace tt::stl { | ||
|
||
// `Indestructible` is a wrapper around `T` that behaves like `T` but does not call the destructor of `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.
While we're deliberately not calling destructor forT
, doesn't this break RAII gurantees if T holds resources like file handles or mutexes and ~T()
was supposed to execute some cleanup subroutine?
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.
Thats the point:) Static vars shouldn't be responsible for this, as the stuff they are cleaning up (or other dependencies that are needed for this) might be gone already.
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.
Approving to unblock as it's clearly a step better than the status quo. Later (unknown timeframe) I intend to circle back to all the ASan/TSan/etc goodness. This may or may not get revisited at that time.
1391409
to
bb2dee1
Compare
Ticket
#17754, #17607
Problem description
Variables with static storage duration should have trivial destructors. Add guidance on why this so, and lower
Indestructible
utility to Metal, as the suggested alternative.What's changed
Indestructible
from tt-train to Metal.Indestructible
.Checklist