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
Add 'noinit' support to initializers #8792
Comments
A handful of existing noinit tests fail under
|
I think I'd be OK with futurizing |
While designing this, we should keep in mind that if we're using a comm layer that can allocate memory and need to register that memory for best performance (currently just ugni), we want the registration to follow the first-touch so that we get the desired NUMA locality. As of this writing the first touch is always our default initialization, so we can do the registration call right after that. If in the future we don't do the default initialization then we'll want to delay the registration call until after whatever does the first touch. For use cases where the declaration includes a user-written initial value that obviates the need for default init it seems like it ought to be straightforward for the compiler to insert (however indirectly) the registration call. But for cases where the first touch is done elsewhere we'll need to think about what to do. Note that there's no functional effect from not registering, but when program performance is driven by the cost of remote references the difference between registering and not can be quite dramatic. |
I think we have recently been thinking a record author would write An interesting alternative (that might make sense to the compiler but maybe not to humans) would be to express the noinit as copy-initialization from a special type, e.g. Besides the exact naming for the initializer run on Supposing a record is initialized with What happens with
What does
What happens when a no-inited variable reaches end of scope? Here I understand the options to be:
|
The problem that I see with this is that the compiler could easily lose track of a variable being {
var x: MyRecord = noinit;
acceptInIntent(x); // copy-elision applies
}
proc acceptInIntent(in arg: MyRecord) {
// compiler runs arg.deinit() here at the end of this function,
// but that might not make sense... e.g. MyRecord might have some
// key fields not set.
} This kind of pattern currently comes up in compiler-generated initializers for classes and records. |
I think that case is generally better served by split-init. However, issue #15808 describes a case where one might wish to do something like split-init in a case where it is not currently implemented. If we do not change the split-init rule for on blocks, the situation will be that the programmer will need to opt in in some way to moveing the variable across locales. While This causes me to lean away from the option of leaving these values uninitialized. |
I understand that we have been reserving In particular, suppose a record has a buffer that it manages and the record author would like to provide a feature where the buffer is allocated but the elements are not initialized. We have been thinking that the record author would write this: record Container {
type eltType;
var buffer: [1..n] eltType;
proc noinit(type eltType) {
this.eltType = eltType;
this.buffer = noinit;
}
} and then the user could write var c : Container(int) = noinit; But, is that really better than having the record author write this: record Container {
type eltType;
var buffer;
proc init(type eltType, param initElts=true) {
this.eltType = eltType;
this.buffer = {1..n}.buildArray(int, initElts=initElts);
}
} and then the user could write var c = new Container(int, initElts=false); ? (Either way, as I understand it, the user of the container will have to do other relatively involved things: explicitly move any non-pod elements into the storage & indicate to the data structure when all elements are initialized). I don't really see why this feature needs language support. I think it could be implemented at the library level. |
This may be unreasonable on my part, but I have a different reaction to exposing aspects of ordinary array initialization to the user/record author versus exposing noinit-specific created methods. |
I'm not trying to propose that |
I think we (@benharsh and I) discussed this when we were introducing
That's an interesting question. I'd expect them to
I would expect:
I would expect:
I would expect:
|
Did you see #8792 (comment) ? I think the problem shown in that comment makes this strategy unworkable. The reason is that a
Do you know of any use cases where this is useful? At the moment I feel I understand the purpose of no-init for arrays but am less confident that no-initializing a stack variable or field is useful (as compared to split initialization). It could help with an explicit way to write #15808 - but similarly to #15703 (comment) we have the problem that the way of eventually setting it differs depending on whether or not If we consider the case where somebody might want to opt-in to something like a split init pattern across an on statement - if {
var A:[D] eltType = noinit;
on AnotherLocale {
forall i in D {
moveInitialize(A[i], something());
}
}
} But what if they wanted this code to be generic on the type? Meaning they don't know it's an array? Then would they write: {
var A: SomeType = noinit;
on AnotherLocale {
moveInitialize(A, something());
}
} and expect Or, should |
After a discussion with @bradcray the plan for now is to allow |
PR #16064 helps with array no-init. I am currently thinking that array no-init should leave the array memory totally uninitialized and if we want to have records that also support some kind of no-initialization of storage that they should do so with a |
Adjust domain map implementations to no longer require pragma For issue #15673. Also for issues #15703 and #8792. This PR: * adjusts the domain map interface to include `dsiElementDeinitializationComplete` * removes `pragma "no auto destroy"` from domain map implementations * adds a user-facing capability to `noinit` arrays of POD elements The goal of this PR is to resolve issue #15673 by adjusting the domain map implementations to no longer require the use of a `pragma "no auto destroy"`. Originally I was expecting to do that with a `noinit` syntactic construction but it turns out that `noinit` is not strictly necessary in this case since the `buildArray(..., initElts=false)` pattern already covers it. Either way, the array in question has memory allocated for elements but the elements are totally uninitialized. In particular, to remove the need for `pragma "no auto destroy"`, this PR adds a `deinitElts:bool` field to DefaultRectangular to indicate if the elements should be deinitialized when the array is destroyed. It adjusts `dsiElementInitializationComplete` to set `deinitElts` to `true`. It adds `dsiElementDeinitializationComplete` to set `deinitElts` to `false` (and also allow similar behavior for other array types). It adjusts `dsiDestroyArr` for to check `this.deinitElts`. Even though `noinit` is not used in the distribution implementations, this PR implements noinit for arrays of POD elements. For example, ``` chapel var A:[1..10] int = noinit; // allocates space for elements but does not initialize them for i in 1..10 { A[i] = i; // `=` is sufficient for initializing trivially copyable types } ``` Users should also indicate when (if ever) the array's elements are completely initialized so that the memory can be registered to support communication. That is the subject of issue #16173. In order to easily test no-init of arrays, this PR adds a flag `--allow-noinit-array-not-pod` that will allow noinit of arrays of non-POD elements. It uses this in several tests along with a version of a low-level move module added to the test system. Issue #16172 discusses the design of a user-facing low-level move module. Reviewed by @vasslitvinov - thanks! - [x] full local futures testing - [x] primers pass with verify/valgrind and do not leak
Add noinit technote Follow-up to PR #16064. The 1.23 release includes a very basic and restricted version of `noinit` because we were able to agree on the behavior of that case. The `noinit` feature is discussed in #15703 and #8792. The future work is discussed in #16172, #16173. Reviewed by @lydia-duncan - thanks!
As a Chapel Programmer, I want to be able to use
noinit
to squash default initialization of certain types, particularly large arrays, and to be able to define my own initializers that respond tonoinit
such that fields within them can be left uninitialized as well because sometimes the speed of avoiding initialization trumps the safety benefits that initialization brings.Acceptance criteria:
noinit is supported for arrays and users can write their own initializers that respond to
noinit
For reference, CHIP 10 and CHIP 12 have a bit of information on the vision for this feature, though I think we've also worked up some more detailed examples at times that don't seem to be reflected there.
The text was updated successfully, but these errors were encountered: