On 11.02.2023 20:11, Mike Cowlishaw
wrote:
Similar
comments: this extra information seems to be aimed at
'developers', not users. A user seeing the proposed output
would have no idea what it means or what it's about. It's
astonishing, in every sense.
Not sure what you mean when writing "developers" or "users" in
this context.
Just to be clear about the meanings in this e-mail context:
"developer" means the "developer of an ooRexx program" and "user"
means "user of an ooRexx program (probably not a programmer)".
This is about the TRACE instruction that gets usually used for
debugging when developing programs, users of programs usually do
not get to see TRACE output (with the single exception that a
command causing a failure will be traced by default).
To me this seems absolutely contrary to the Rexx
principles. If developers need this kind of information,
cannot this be achieved by other, less visible and less
ugly, means?
There may be a misunderstanding here.
Multithreaded tracing is meant to help the *developers* of an
ooRexx program to trace ooRexx programs that execute in different
threads for debugging purposes (there is no need for this in
classic Rexx). The next context is that the execution environment
are method routines, i.e. method routines usually defined in
classes and being executed on behalf of an ooRexx object (as
classic Rexx has no classes/methods there is no reason to trace
them).
The ooRexx reference, rexxref.pdf, documents concurrency in
ooRexx in chapter "12. Concurrency" such that one can expect that
there are ooRexx programmers who will apply/exploit it.
---
The ooRexx TRACE is modeled after the classic Rexx trace and
currently does unfortunately not have the ability to gain insight
of what happens when ooRexx programs execute in a mulithreaded
fashion.
Take a look at this ooRexx program taking advantage of ooRexx'
concurrency:
c1 = .c~new
call syssleep 0.5
c1~m2 -- wake-up m1
say "done"
::class C
::method init
expose s
s = 0
reply
self~m1
::method m1
expose s
s = 1
guard off
say "before guard" -- here, no lock
guard on when s <> 1 -- but here, is locked while waiting...
say "after guard"
::method m2
expose s
s = 2
-- ::options trace a
If you run this program it will hang (run into a deadlock), here
the output thanks to some say-statements for debugging:
G:\test\orx\trace>jlf_dl1.rex
before guard
The program just hangs, one must CTL-C to break the running
program.
So where is the problem? The current TRACE does not help to shed
any light on the (concurrent) ooRexx context.
This is where the MT tracing enhancement comes into play,
following the "Rexx principles" to make the programmers better
understand what happens and how the Rexx program gets executed.
After all, this is the motivation that you came up with TRACE,
right?
So in the post-classic Rexx, ooRexx, allowing for exploiting OO,
concurrency, messaging etc., TRACE needs to be enhanced
accordingly to help and ease the ooRexx program developer with his
work when hitting problems because of the complex environment
concurrently executing ooRexx programs have to relate to. It is
about making debugging in this application area easier than is
currently possible.
To illustrate, firstly here a TRACE A in "classic Rexx style" as
currently implemented in ooRexx 5.0 (by uncommenting the options
directive at the end of the above program which will set TRACE A
for the entire package, i.e. for all routines in that program):
G:\test\orx\trace>jlf_dl1.rex
1 *-* c1 = .c~new
>I> Method "INIT" with scope "C" in package "G:\test\orx\trace\jlf_dl1.rex".
8 *-* expose s
9 *-* s = 0
10 *-* reply
2 *-* call syssleep 0.5
>I> Method "INIT" with scope "C" in package "G:\test\orx\trace\jlf_dl1.rex".
12 *-* self~m1
>I> Method "M1" with scope "C" in package "G:\test\orx\trace\jlf_dl1.rex".
15 *-* expose s
16 *-* s = 1
17 *-* guard off
18 *-* say "before guard" -- here, no lock
before guard
19 *-* guard on when s <> 1 -- but here, is locked while waiting...
3 *-* c1~m2 -- wake-up m1
>I> Method "M2" with scope "C" in package "G:\test\orx\trace\jlf_dl1.rex".
Now, if you are not Rick or Erich or any other deeply acquainted
ooRexx programmer you have a problem: why is this deadlock
occurring, or maybe formulated differently: where is the deadlock
occurring and why?
This is a relative simple concurrency ooRexx program, and still
one can see immediately the challenge. Of course, over time, if
gaining more and more (and more and more time-consuming)
experience one may become able to eventually find the problem. But
using classic TRACE A is not as helpful and not as human-centric
in such concurrency cases that ooRexx allows for.
---
The proposed multithreaded (MT) enhancement to TRACE (not meant
for users of a Rexx program, but meant for humans who use ooRexx
to develop powerful ooRexx programs for which they see a need to
debug), when turning on multithreaded tracing, then you get the
following TRACE output with concurrency related additional
important information:
G:\test\orx\trace>jlf_dl1.rex
R1 T1 A1 1 *-* c1 = .c~new
R1 T1 A2 V1 >I> Method "INIT" with scope "C" in package "G:\test\orx\trace\jlf_dl1.rex".
R1 T1 A2 V1 1* 8 *-* expose s
R1 T1 A2 V1 1* 9 *-* s = 0
R1 T1 A2 V1 1* 10 *-* reply
R1 T1 A1 2 *-* call syssleep 0.5
R1 T2 A2 V1 1* >I> Method "INIT" with scope "C" in package "G:\test\orx\trace\jlf_dl1.rex".
R1 T2 A2 V1 1* 12 *-* self~m1
R1 T2 A3 V1 1 >I> Method "M1" with scope "C" in package "G:\test\orx\trace\jlf_dl1.rex".
R1 T2 A3 V1 2* 15 *-* expose s
R1 T2 A3 V1 2* 16 *-* s = 1
R1 T2 A3 V1 2* 17 *-* guard off
R1 T2 A3 V1 1 18 *-* say "before guard" -- here, no lock
before guard
R1 T2 A3 V1 1 19 *-* guard on when s <> 1 -- but here, is locked while waiting...
R1 T1 A1 3 *-* c1~m2 -- wake-up m1
R1 T1 A4 V1 1 >I> Method "M2" with scope "C" in package "G:\test\orx\trace\jlf_dl1.rex".
If you look at this output, for the first time you get
concurrency context information and real insights of what happens
when ooRexx executes this multithreaded ooRexx program. There is
so much more helpful information in this concurrency trace making
it much easier for a human to find and figure out the problem at
hand!
This is the example that Jean-Louis has already posted here
<https://github.com/jlfaucher/executor/blob/master/sandbox/jlf/samples/concurrency/deadlock1.rex>
to allow discussion about debugging and the importance of MT
TRACE.
If you follow the above link you will see his explanations and
how one can resolve that particular deadlock.
---
About the "Rexx principles" extended to ooRexx: the additional
(compared to classic Rexx new) concepts and abilities need to be
made available as human-friendly as possible when using trace for
debugging, with the least astonishment possible. The MT TRACE is
meant for exactly that very purpose: make tracing more
human-friendly in concurrency contexts for ooRexx programmers!
Help the ooRexx programmers save a lot of time in analyzing,
debugging and fixing MT problems!
Together with the companion Rexx script "tracer.rex" one can get
excellently edited debug data prepared in a CSV file that one can
import into a spreadsheet and then use the means of a spreadsheet
to analyze the dynamics and interdependencies of concurrently
executing ooRexx programs making even huge MT traces manageable,
inspectable and debuggable. Jean-Louis has given an example in one
of his e-mails.
---
A last remark: as with classic TRACE it should be the case that
the programmer of ooRexx programs is in full control when he
wishes multithreaded TRACE output for debugging and when not.
As you write the user of an ooRexx program should never have to
see TRACE output, which would be irritating and distracting.
---rony
_______________________________________________