Re: [sv-ec] fork..join_none/join_any and automatic variables


Subject: Re: [sv-ec] fork..join_none/join_any and automatic variables
From: Steven Sharp (sharp@cadence.com)
Date: Wed May 21 2003 - 17:21:56 PDT


>>This is relevant to fork-join used inside an automatic task or function
>>in 1364-2001. That behavior is well defined. If SV comes up with a
>>different answer, then it is incompatible.
>>
>>
>What do you mean by "well defined"? I couldn't find anything that
>directly addressed the topic of the effect of a fork on automatic
>variables defined in an enclosing scope. Perhaps you know of a place
>this is addressed? Or perhaps you're inferring that a lack of discussion
>of this topic is tantamount to defining that this behavior should be the
>same as with static variables?

Unfortunately, what I mean isn't the same thing as "well documented."
I mean that the conceptual model of automatic scopes in 1364-2001 is
not the kind of vague, open-to-interpretation thing that has been
implied by some of this email. The conceptual model is precise and
complete, and I and some others who worked on 1364-2001 have a full
understanding of it, even if the description in the standard may not
be as clear as it could be.

There is no discussion of the effect of fork on automatic variables in
an enclosing scope, because it has no effect. It is no more relevant
than a discussion of the effect of if-then-else or a repeat-loop on
automatic variables in an enclosing scope. I would never claim that
the LRM is complete, but in this case the lack of discussion is because
there is no special behavior. The LRM cannot specify the individual
interactions between all features, but must rely on a general assumption
that they are orthogonal unless specified otherwise.

Note that Jamie already directed a question about this to the IEEE
1364 Errata Task Force. You can see the response at:

http://www.boyd.com/1364_btf/report/full_pr/281.html

>>A subprocess created inside the scope will not.
>>
>Why not? (Oops, never mind. I guess that's what we're debating ;^).

First of all, because the LRM text does not specify that it is. Second,
because the conceptual model that the LRM text is based on says that it
isn't (and we have the IEEE ETF ruling on that). And third, because it
wouldn't be desirable.

We aren't talking about another unrelated process coming into the scope
and getting its own variables for that scope. We are talking about the
existing process breaking itself into subprocesses that continue executing
from the split point as extensions of the parent. Even in the incorrect
interpretation, you are automatically assuming that the newly allocated
variables will start out inheriting an initial value from the parent
variable (acknowledging that you want them to have the same value).
Or perhaps the term "copy" led you into thinking this.

This is not the case; automatic variables are always initialized to their
default value (X for non-reals) when allocated. This should tell you that
there is a mismatch between your conceptual model and the one that 1364-2001
is based on.

It should also tell you that it won't work the way you seem to want. Since
newly allocated automatic variables always start out X, allocating new ones
for each subprocess would cut the subprocess off from the automatic variables
in its surrounding scopes and make it work in isolation. This is not
desirable. You want to maintain access to the surrounding environment. If
you need some newly allocated and initialized automatic variables in the
subprocess, you can already get those by declaring them in the subprocess.

Yes, you can make up a different scheme, such as allocating new variables
for each subprocess, initialized to the value in the parent, but it would
not be consistent with 1364-2001. It would be unnecessarily inefficient
also. Nor would it match the scoping rules of Verilog or any other
language I know.

>>The new types of nonblocking forks would fall under the description in
>>10.2.3 of 1364-2001 that says "Because variables declared in automatic
>>tasks are deallocated at the end of the task invocation, they shall not
>>be used in certain constructs that might refer to them after that point."
>>Since a subprocess of such a fork might refer to the variable after it
>>had been deallocated, such a subprocess would not be allowed to reference
>>the automatic variable. Of course these forks are not listed in the
>>specific examples in 1364-2001 since they are not part of the language,
>>but they are in the same category as those examples.
>>
>>These forks do create a new wrinkle. The subprocesses in 1364-2001
>>cannot themselves introduce new scopes and automatic variables, while
>>the new fork types can. A subprocess of a fork-join_any could contain
>>a begin-end block that declares some automatic variables. There is no
>>reason why this would not be legal and why the subprocess could not
>>refer to these variables. The subprocess cannot out-survive the variables
>>in this situation. The restriction would become more complex: instead of
>>not being allowed to refer to any automatic variables, the subprocesses
>>would not be allowed to refer to any automatic variable in a scope outside
>>the subprocess. Note that such automatic variables declared inside of a
>>fork-join_any subprocess would be allocated each time execution entered
>>their scope, so that if the subprocess were executed multiple times
>>concurrently, each subprocess would have its own copies.
>>
>>
>Go Steve! I presume you mean "join_none" in the above (I misspoke the
>same thing in my original post, so this is undoubtably my fault).

Doesn't join_any allow the parent process to continue as soon as any
child completes, leaving the other children running? If not, then my
mistake. If so, then it has the same problem as join_none of leaving
child subprocesses that could outlive the parent process, which will
be allocating and deallocating its automatic variables. At any rate,
join_none has this problem, whether join_any does or not.

The general solution in 1364-2001 for types of subprocesses that could
outlive automatic variables in the scope around them is to disallow such
subprocesses from accessing automatic variables. Since most of these
subprocesses are things you wouldn't tend to use in a reentrant task or
function anyway, this doesn't create any hardship. This rule could be
extended to cover these new fork subprocesses, but this is admittedly
more likely to be inconvenient.

>Additionally, I seem to have this strong desire to define automatic
>tasks and functions in terms of a traditional execution stack model.
>This is a proven high-performance path to achieving reentrancy. The
>largest obstacle (that I've so far considered) to this is this fork-join
>strangeness. I'd hate for a lack of thoughful consideration of the
>ramifications of this to be the blocking issue to a nice implementation.
>Of course, this desire in me is probably curable.

Verilog designs generally involve such a large number of separate
threads of execution that traditional mechanisms are impractical.
High performance requires using a mechanism that handles that well
first, and then fitting reentrant calls into it.

At any rate, I don't understand what a traditional execution stack model
has to do with what you are suggesting. Traditional programming languages
do not make new copies of the variables in a stack frame when entering a
nested scope or calling another subroutine. When they allow access to the
caller's variables from a subroutine, they use a link to the original
stack frame containing the variables, rather than making a copy.

Nor does making a copy of the parent's stack frame for each of the child
processes so they can continue to access their copy after the original
is deallocated (if that is what you are suggesting) sound like a
high-performance path to anything. It may be desirable to provide some
mechanism for passing selected values that were in automatic variables
in the parent process into automatic variables in the child process, but
I don't think this is the way to do it. It is inefficient and inconsistent.

>I can't tell where your last paragraph is leading. Are you suggesting,
>similar to Dave Rich, that fork-join_none ought to treat outer-scoped
>automatic variables differently than other forms of fork or are you
>starting to argue for the removal of fork-join_none?

I acknowledged that fork-join_none (and possibly fork-join_any) have a
problem that does not occur for fork-join. I pointed out that this could
be prevented by interpreting a rule in 1364-2001 to apply to these
subprocesses as well, which would prevent them from accessing automatic
variables and having this problem. Applying the spirit rather than the
letter of the rule would still allow them to declare and use automatic
variables in scopes local to the subprocess. However, this still provides
no mechanism by which they can access the values of automatic variables in
scopes around them, even to copy them into their own local automatic variables
when they are first forked off. I think this would be desirable, but I
don't see a simple way of adding this in the existing proposal without a
major kludge of some kind.

Aside from applying this restriction from 1364-2001 only to the problematic
forms of fork, I haven't suggested making the different forms of fork behave
differently. I think they should work as similarly as possible.

Steven Sharp
sharp@cadence.com



This archive was generated by hypermail 2b28 : Wed May 21 2003 - 17:27:40 PDT