Hi Chapel Developers --
Here's a semantic question that comes up perennially and is coming up
again for me this week:
Traditionally, Chapel has kept variables that are logically on the stack
alive after their lexical scope ends if there are other asynchronous tasks
referring to them. For example, in code like this:
{
var A: [1..10] real;
begin foo(A);
...
} // A leaves scope here
if foo(A) is long-running and we hit the end of the lexical scope first,
we will not deallocate A, but will keep it alive for foo()'s benefit.
This choice has traditionally been advocated for in order to keep the
programmer's life simple (and when asked in the past, key users have asked
to have the current behavior preserved).
Unfortunately, the effect of this choice is that it makes the
implementation far more complicated, and in many cases has led to
inefficiency and/or incorrectness in the current implementation (e.g.,
memory leaks due to bugs, performance hits due to reference counting,
etc.).
In 1:1 discussions this week, we smacked back into this issue once again,
and I found myself (again) curious whether we could move away from these
semantics and say that if the user has an asynchronous task referring to
data that has been reclaimed through traditional lexical scoping, their
program is incorrect.
To that end, I wanted to ask this group whether anyone had any qualms
about exploring this question again (e.g., reasons that we rely on it, or
will want to, in key cases), or any reasons that we shouldn't put this
question to the user community.
One downside to the proposed change is that incorrect programs might
result in segfaults. My hope would be that a good Chapel implementation
would introduce runtime checks in cases where the compiler can't determine
whether a task will complete before its referenced variables leave scope,
with the option to turn these checks off when performance is desired. I'm
hoping that the current analysis that moves such variables to the heap can
be leveraged to create these checks without much difficulty. That said,
I'm tired enough of this issue that I think I'd be willing to switch the
semantics even if the runtime checks were not yet implemented.
My thinking for why this doesn't seem likely to be the end of the world
for anyone is as follows:
* The only time this case comes up is when using 'begin's, and our
experience so far has been that 'coforall's, 'cobegin's are the
far more used ways of creating parallelism in Chapel programs (and
data parallelism of course, which almost always uses coforalls).
Many cases of 'begin's are surrounded at some scope by 'sync' scopes
which also help guard against such cases.
* It used to be the case that all variables went into tasks by reference,
so even cases like this needed protection:
{
var x: int;
begin { ...compute big block of code using 'x'... }
} // x leaves scope here
However, with the introduction of task intent semantics, scalar types
like this are passed to tasks by 'const in' intent, therefore the
'x' need not be kept alive after its scope closes. Of course, one
could use a 'ref' clause to get back to the old behavior:
{
var x: int;
begin ref(x) { ...compute big block of code using 'x'... }
} // x leaves scope here
but I'm guessing that this is not a common idiom and that even when
it is, it's reasonable to require the user to not rely on Chapel
keeping 'x' alive for them.
As a result, the main types which fall afoul of these issues are those
passed by reference to tasks (e.g., arrays, syncs, atomics, ...).
* As I understand it, the XMT and X10 programming models (both of which
also have asynchronous tasks like Chapel) adopt similar "it's the
user's responsbility" semantics.
So -- does anybody want to argue in favor of keeping the current semantics
rather than trying to make our lives easier as developers by changing
them?
The bonus question is whether we should adopt similar semantics for
operations that alias arrays. E.g., if you slice an array or alias its
elements and that slice/alias outlives the original array, should that be
a user error rather than a means of keeping the array's elements alive
under the covers? I'm also very tempted to adopt this (because it would
remove the need to reference count arrays for correctness purposes), but
haven't thought through the implications enough to feel very confident
about it yet.
Thanks very much for any thoughts,
-Brad
------------------------------------------------------------------------------
Dive into the World of Parallel Programming. The Go Parallel Website,
sponsored by Intel and developed in partnership with Slashdot Media, is your
hub for all things parallel software development, from weekly thought
leadership blogs to news, videos, case studies, tutorials and more. Take a
look and join the conversation now. http://goparallel.sourceforge.net/
_______________________________________________
Chapel-developers mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/chapel-developers