-
Notifications
You must be signed in to change notification settings - Fork 426
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
Use workaround to enable lifetime checking for lists of borrowed classes #15575
Use workaround to enable lifetime checking for lists of borrowed classes #15575
Conversation
compiler/resolution/lifetime.cpp
Outdated
bool bothFormalsContainBorrowedOrAreBorrowed = false; | ||
|
||
if (isOrRefersBorrowedClass(formal1->getValType())) { | ||
bothFormalsContainBorrowedOrAreBorrowed = true; |
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.
Nothing's going to set this to false
when formal2
isn't borrowed.
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.
Good point!
Hi @mppf, would you mind reviewing this? I added debugging info I found helpful but let me know if that is too much for you. |
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.
It looks good but I'd like you to remove the debug code. Most of that information is stuff I would gather from the debugger and tracing the checking of a particular call. It's enough code that I worry about it making the control flow of the program logic harder to see.
compiler/AST/FnSymbol.cpp
Outdated
if (isResolved() && _this != NULL) { | ||
return toAggregateType(_this->getValType()); | ||
} else { | ||
if (numFormals() >= 2) { |
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.
Let's fold else { if {
into else if {
Thought so. I'll go ahead and remove the debugging code. I'm not sure how to step through in the way you do with a debugger yet, I'll have to practice. |
Adjust list futures affected by merge of 15575 (#15608) This PR adjusts list lifetime checker futures that were not addressed by #15575. Some have been changed to normals tests. The test `listAppendBorrow` was broken up into two smaller, more concise tests. --- Testing: - [x] Adjusted tests on `linux64` when `CHPL_COMM=none` --- Reviewed by @ben-albrecht.
for x in iterable do | ||
append(x); | ||
|
||
for x in iterable do { |
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.
@ronawho So after profiling this PR this is trivially the reason comm counts changed in test/library/packages/Sort/performance/dist-performance.chpl
. The only thing I don't understand is why. Do you think it's worth trying to figure out why this diff caused comm counts to change so drastically? Or should I just revert it and call it a day?
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.
Do you remember the motivation for this change? I don't think I understand what's going on here well enough to have an opinion.
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.
My rationale for this change was that since _commonInitFromIterable
is only called in an initializer, I might as well write the loop using internal methods to avoid taking a lock (list.append
may take a lock if parSafe=true
).
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.
I see. That makes sense, though I still don't grok the "no auto destroy"s. Can we make an internal version of append that doesn't take the lock?
proc ref _appendNoLock(pragma "no auto destroy" in x: this.eltType) lifetime this < x {
_appendByRef(x);
}
Or does that still have the comm issue?
If that still has the problem, I'd probably just revert and keep the lock. That lock has very little overhead when used uncontested/serially
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.
The pragma "no auto destroy"
exist because the list assumes ownership of the lifetime of the element. It controls when the element is destroyed as long as it contains it. (The element is moved into place instead of assigned, so only one deep copy is made.)
I can try _appendNoLock
but honestly it's probably not worth adding a whole new method, as you say the overhead is not much when uncontested.
I was just curious about whether or not this is worth investigating (as a separate issue or something), as to me it doesn't really seem like the changes should cause such a massive increase in GETs. But maybe it is trivially obvious to you why GETs would increase?
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.
I suspect that the pragma code confuses the compile enough that it doesn't remove a copy for the case that the iterator is returning by value. You could check the AST logs around after pass 20 callDestructors for differences to see if that's the case.
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.
Awesome! I'll give that a try.
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 luck, seems more or less the same sans an initCopy
for the formal tmp in the append
version vs an init=
for the variable in the _appendByRef
version. Iterator was returning refs.
Revert changes to `list._commonInitFromIterable` (#15943) In #15575 I decided to modify `list._commonInitFromIterable` to append elements without taking a lock. Such a small optimization seemed reasonable since that method is only called by initializers. The change ended up causing a fairly large increase (30270 -> 34410) in GETs for `library/packages/Sort/performance/dist-performance`, so revert it. Add a lifetime constraint to `_commonInitFromIterable` so that old code can function correctly. --- Testing: - [x] ALL on linux64 when CHPL_COMM=none --- Reviewed by @ronawho. Thanks!
Revert changes to `list._commonInitFromIterable` (chapel-lang#15943) In chapel-lang#15575 I decided to modify `list._commonInitFromIterable` to append elements without taking a lock. Such a small optimization seemed reasonable since that method is only called by initializers. The change ended up causing a fairly large increase (30270 -> 34410) in GETs for `library/packages/Sort/performance/dist-performance`, so revert it. Add a lifetime constraint to `_commonInitFromIterable` so that old code can function correctly. --- Testing: - [x] ALL on linux64 when CHPL_COMM=none --- Reviewed by @ronawho. Thanks!
This PR adds a small workaround to the
List
module that "encourages" the compiler to perform lifetime checking for methods such aslist.append()
.This workaround is required because lists use
_ddata
for their backing store instead of an array. When it comes time for the compiler to evaluate lifetime clauses, a lifetime clause is only considered for evaluation if both formals in the clause are or refer to a borrowed class (the relevant function incompiler/resolution/lifetime.cpp
isisOrRefersBorrowedClass
). The_ddata
type is marked as unsafe by the compiler, and is skipped. Because of this the compiler is unable to infer that alist(borrowed C)
contains a borrowed class, and lifetime clauses with the list as a receiver such asthis < x
are not evaluated.To resolve this issue, I added a dummy field to the
list
type. If theeltType
of a list is a borrowed class, this field will have the typeeltType?
(a nilableeltType
) and is default initialized tonil
. Otherwise this field has the typenothing
and is folded away.Testing:
ALL
onlinux64
whenCHPL_COMM=none
ALL
onlinux64
whenCHPL_COMM=gasnet