New Issue: Memory.Initialize: proposal for 'moveArrayElements'

20338, "benharsh", "Memory.Initialize: proposal for 'moveArrayElements'", "2022-07-29T23:54:29Z"

This issue serves to propose replacements for the functions named moveInitializeArrayElements. I am proposing a replacement for moveInitializeArrayElements because:

  • it halts when given invalid arguments that can be easily checked ( to some degree )
  • it uses start indices and a number of elements to represent the region of the array to be moved.
    • this is not Chapel-tastic (compared to ranges/domains)
    • this limits the possible arrays to 1D arrays

I believe the intention behind moveInitializeArrayElements is to provide potential bulk-movement optimizations compared to a loop that users could write:

forall (d, s) in zip(dest, src) do
  moveInitialize(d, moveToValue(s));

// Or...
forall(di, si) in zip(destDomain, srcDomain) do
  moveInitialize(dest[di], moveToValue(src[si]));

I propose two new functions named moveArrayElements that conceptually implement these loops, but also perform some basic error checking and have the option to bulk-optimize movement:

// A more elegant/convenient version for slices like "A[SomeDomain]" or "B[0..#10]"
proc moveArrayElements(ref dst:[] ?eltType, const ref src:[] eltType) : void throws

// A version for unsliced arrays, where slicing is too costly or not convenient
proc moveArrayElements(ref dst:[] ?eltType, const dstRegion,
                       const ref src:[] eltType, const srcRegion) : void throws
where (isDomain(dstRegion) || isRange(dstRegion)) && (isDomain(srcRegion) || isRange(srcRegion))

Concerning constraints:

  • The dst and src arrays must have the same element type, but otherwise they could have different distributions/domains.
    • we can optimize when the dist/dom types match, or are "known" to each other (a la bulk transfer)
  • Regions may be domains, or ranges in the case of 1D Arrays
  • Regions must have indices in their corresponding arrays
  • I'm not sure if we have a good way of expressing this today, but I believe it would make sense to require that the arguments are "zip-able" (with the dst as the leader?):
    • zip(dst,src)
    • zip(dst[dstRegion], src[srcRegion]

Throwing vs. Halting

Here are some situations in which we might want to throw IllegalArgumentErrors:

  • Aliasing arrays with overlapping slices/regions
  • Regions with sizes that do not match
    • Regions with zero indices
  • Regions with indices that are out of bounds in the array

Detecting aliasing arrays may be difficult, especially with user-defined distributions. Does this imply we need to extend the Domain Standard Interface?

Checking whether indices are in bounds could be expensive. Could toggle such checking with --no-checks? Or perhaps rely on the outcome of the general "halting v. throwing" discussion (#18825) ?

Dedicated aliasing array function

Should we have a function dedicated to the aliasing array case? If we did, would we stop checking for aliasing arrays in the other function(s)?

Naming

I chose the name moveArrayElements initially and primarily to distinguish these functions from the old ones. I am not particularly beholden to this name, but it does feel less cumbersome and more verb-y than moveInitializeArrayElements.

Is there any support for either name?

Worthy for 2.0?

We are undergoing an effort to stabilize modules for Chapel 2.0. While this functionality is certainly useful, users can still implement the essential functionality with moveInitialize and moveToValue.

The function with "Region" arguments exists primarily because slicing can be expensive. It will also be more challenging to implement and support, and has a less appealing function signature. Do we want to support both functions for 2.0? Or should we mark one, or both, of them as "unstable"?

Bonus Topics

Controlling parallelism

In an offline discussion, @vasslitvinov proposed that we might be able to use a context-manager to offer parallelism control within a given scope.

Barring such functionality, should we attempt to provide that control though moveArrayElements in a more direct manner? There are a couple of simple, but inflexible options:

  • const parallel : bool = true
  • const tasksPerLocale : int = dataParTasksPerLocale.