Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Timely destruction and TRACE_SYSTEM_AREAS

9 views
Skip to first unread message

Leopold Toetsch

unread,
Jun 26, 2003, 3:59:18 AM6/26/03
to P6I
t/pmc/io_2 is failing on some tinderboxen that don't have memalign and
therefore don't have ARENA_DOD_FLAGS set. Besides the wrong count of DOD
runs, the primary problem is:

The ParrotIO object is found to be alive in some system areas (probably
processor registers). Due to the conservative approach of the DOD
strategy this always might happen.

I think, we have a problem.

leo

Leopold Toetsch

unread,
Jul 7, 2003, 4:55:30 AM7/7/03
to Leopold Toetsch, perl6-i...@perl.org, Dan Sugalski

I have a (partial?) solution for this. What AFAIK is going on is
something like this:

C-stack: Parrot_open() ... later ... do_dod_run()
... ...
$1 = pmc_new sub $0x44, %esp
...
IO-PMC ----------------------->
...
trace_system_stack()

So during a DOD run the trails of an IO PMC are found on the system
stack during trace_mem_block. The main problem seems to be, that gcc
uses 16-byte aligned stack frames by default. So there are "holes" in
the stack, where it is not unlikely, that we find trails of PMCs used
in earlier functions calls.

I did compile parrot with:

-mpreferred-stack-boundary=2

and the t/pmc/io_2.pasm test succeeds with all run loops then.

As we don't pass around mmx/sse memory locations above option should be
safe.

For i386 JIT/CGP we need another options for gcc 3.x (with some x)
(s. "[perl #22353] JIT!")

-mno-accumulate-outgoing-args

But I don't know, in which config file these should go.

leo

Juergen Boemmels

unread,
Jul 8, 2003, 2:54:41 PM7/8/03
to l...@toetsch.at, Perl6 Internals
Leopold Toetsch <l...@toetsch.at> writes:

> I have a (partial?) solution for this. What AFAIK is going on is
> something like this:
>
> C-stack: Parrot_open() ... later ... do_dod_run()
> ... ...
> $1 = pmc_new sub $0x44, %esp
> ...
> IO-PMC ----------------------->
> ...
> trace_system_stack()
>
> So during a DOD run the trails of an IO PMC are found on the system
> stack during trace_mem_block. The main problem seems to be, that gcc
> uses 16-byte aligned stack frames by default. So there are "holes" in
> the stack, where it is not unlikely, that we find trails of PMCs used
> in earlier functions calls.

*Ouch* I spend the whole Friday searching this unbound PMCs, but
failed to find them, they seemed to be nowhere in the
stack-frames. Now you found out that they aren't in a stack-frame.

> I did compile parrot with:
>
> -mpreferred-stack-boundary=2
>
> and the t/pmc/io_2.pasm test succeeds with all run loops then.
>
> As we don't pass around mmx/sse memory locations above option should be
> safe.

[...]

We should really rethink the statement "We will always walking the
stack". The timely destruction needs to know for sure if an object is
alive or not. The conservative stack-walking will not give you this
information.

The stackwalking was introduced to solve the infant mortality
problem. One of its big advatage was its convinience for the
C-programmer: Just use a PMC, and you are done. But with timely
this convinience suddenly has vanished: The programmer has to make
sure that every local variable is initialized, and that the program is
compiled with the right options. This may not be a problem in the
Parrot-core, but in an extension module this is a big problem. The
wrong stack boundarys e.g. may cost performance.

Ok, then we need another solution for the infant mortality
problem. The requirments for this are:
- PMC should be traced exact (timely destruction requieres this)
- allows recursive calls of run_core
- should not be fooled by longjmp
Furthermore the system should be simple and fast. For bonus points it
should be portable.

Some ideas solving this problem:

Not discussing the solutions of docs/dev/infant.dev here.

* Use C++ for the PMCs
This would give a very convienient way of handling this. The
constructors and destructors are emitted by the compiler. Therefor a
simple explicit neonate-flag can be handlet correctly. Even PMC
assignments are no problem because of operator overloading. The
disadvatage of this: its C++.

* mark all PMC values on the stack
All creations of PMCs are recorded and only these PMCs are
traced. This could be handled by a macro like
#define NEW_PMC(var) PMC *var = register_pmc(&var)
A longjmp can use some wrapper-code which cleans up the stack above
the current stacktop. But this will only work if there is reliable way
to detect when an end of scope, otherwise the above problem can bite
us again. If the programmer has to take care of the scope exit this is
not more than a clever neonate-flag which takes care of longjmps.

* use a liked list of frames
Every call to a parrot function gets an extra parameter of the type
struct gc_frame {
struct gc_frame *prev;
Pobj *pobj;
} *
A function not allocating anything just pass on the previous gc_frame
foo(struct ParrotInterp *interpreter, struct gc_frame *frame, ...)
{
bar(interpreter, frame, ...);
}
whereas a function using a temporary is working this way
foo(struct ParrotInterp *interpreter, struct gc_frame *frame, ...)
{
struct gc_frame temp = { frame, NULL };
temp.pobj = bar(interpreter, frame);
baz(interpreter, &temp);
}
This scheme is exact, works thru longjumps and recursive run_cores and
only the active objects are traced, but it has the problem that it
changes the signatur of every parrot-function.

Comments?
boe
--
Juergen Boemmels boem...@physik.uni-kl.de
Fachbereich Physik Tel: ++49-(0)631-205-2817
Universitaet Kaiserslautern Fax: ++49-(0)631-205-3906
PGP Key fingerprint = 9F 56 54 3D 45 C1 32 6F 23 F6 C7 2F 85 93 DD 47

Leopold Toetsch

unread,
Jul 8, 2003, 5:24:53 PM7/8/03
to Juergen Boemmels, Perl6 Internals
Juergen Boemmels wrote:

> Leopold Toetsch <l...@toetsch.at> writes:
>
>>So during a DOD run the trails of an IO PMC are found on the system
>>stack during trace_mem_block. The main problem seems to be, that gcc
>>uses 16-byte aligned stack frames by default.

> *Ouch* I spend the whole Friday searching this unbound PMCs, but


> failed to find them, they seemed to be nowhere in the
> stack-frames. Now you found out that they aren't in a stack-frame.

Mainly the "solution"

-mpreferred-stack-boundary=2

indicates, that these PMCs are not alive in the current stack frame(s),
which is good, but they shine through holes in uninitialized area out
from previous frames into the current. So physically they are in the frame.


> We should really rethink the statement "We will always walking the
> stack". The timely destruction needs to know for sure if an object is
> alive or not. The conservative stack-walking will not give you this
> information.

Thanks for this statement. My words :-)


> The stackwalking was introduced to solve the infant mortality
> problem.

Conclusion: Timely destruction and solving infant mortatility don't play
together or are mutually exclusive - in the current approach.


> Ok, then we need another solution for the infant mortality
> problem. The requirments for this are:
> - PMC should be traced exact (timely destruction requieres this)
> - allows recursive calls of run_core
> - should not be fooled by longjmp
> Furthermore the system should be simple and fast. For bonus points it
> should be portable.

Yep. Good summary. With one addition (that covers Benjamin's approach:
PMC, that need timely destruction, should be traced exactly, which
implies of course, that aggregates or such where these go in have the
same requirements ...)


> * Use C++ for the PMCs

> * mark all PMC values on the stack

> * use a liked list of frames

Mine still are:
* anchor early, anchor often (Larry Loffer)
meaning place e.g. new PMCs first in register, then initialize it
* if that's to cumbersome, disable DOD
* if that's suboptimal, use active anchoring to some root set linked
list for temp PMCs (this is probably your second point above)
* hide this hacks for external/XS code inside some macros


> Comments?

Always;-)


> boe

leo

0 new messages