Got a very nice improvement idea which is now implemented in "p3_makestring_method.rex", i.e. inserting the thread number in the trace prefix as suggested by Mike F. Cowlishaw, cf. <https://sourceforge.net/p/oorexx/mailman/oorexx-devel/thread/69B32C0CD99749A59516F36250A992E4%40MFC5/#msg37777673>.

This is the code added to "p3_makestring_method.rex" that implements Mike's 
idea:

   ::method myMakeString03
      use arg traceObj
      parse value traceObj~traceline with line 7 prefix rest
      prefixT = prefix~left(2) || traceObj["THREAD"] || prefix~right(1)
      return line prefixT rest

---rony

P.S.: <wi.wu.ac.at/rgf/rexx/tmp/20240128_mt> got already the updated version such that you can download and experiment for yourself (and with your own Rexx programs).


On 04.02.2024 16:48, Rony G. Flatscher wrote:

There is a new version available at <wi.wu.ac.at/rgf/rexx/tmp/20240128_mt>, which is regarded to be the final version for the time being.

The web page allows for downloading a portable 64-bit Windows debug version of ooRexx 5.1.0beta that implements the TraceObject class which gets used by the Rexx scripts stored in the test_scripts.zip archive.

Some changes, additions:

  * ability to save the trace into a JSON or CSV file
      o allows one to load the trace into e.g. Excel, scalc and use the 
spreadsheet's feature to
        further analyze
  * ability to load the stored trace and reinstate the collection of 
TraceObjects for further
    analysis from Rexx
  * traceutil.cls includes now a few utility routines, e.g. for saving, loading 
JSON/CSV files
    making it easy for any Rexx programmer to take advantage of this feature
  * ...

Here the updated readme.txt:

    Multithreaded tracing, TraceObject class
    ----------------------------------------

    This readme.txt file accompanies a portable Windows version of ooRexx 
5.1beta
    that implements multithreaded trace prefixes and makes it possible to create
    one own's trace line renderings as well as to use the infrastructure for
    profiling (analyzing) the execution of Rexx programs.

    - unzip the ooRexx portable version, go into the directory and run
       "setupoorexx.cmd" which creates batch files, e.g.:

       - setenv2rxenv.cmd ... run to change PATH to first point to the
                              portable version of ooRexx; run Rexx programs
                              with "rexx myProgram.rex" such that the
                              operating system looks and finds for rexx.exe

    - the following files can be found in test_scripts.zip

        - there are a few test Rexx programs (you can use your own Rexx 
programs):

          - test01.rex ... a simple test Rexx program

          - test02.rex ... a multithreaded test Rexx program to test guarded and
                           unguarded method routines

          - test03.rex ... this is test01.rex with an intenional syntax error 
at the
                           end

          - traceutil.cls ... WIP: a little set of utilities for .TraceObject, 
e.g.
                              the routines toJsonFile(collection[, 
Minimal|Crlf|Human])
                              and toCsvFile(collection[,createTitle?]), 
fromJsonFile(filename),
                              fromCsvFile(filename), comparators for sorting 
collections
                              of traceObjects in different manners 
(.sortByThreadInvocationNr,
                              .sortByInvocationNr, .sortByAttributePoolNr)

        - there are three Rexx programs that exploit the new infrastructure:

          - p1_traceRunner.rex ... executes the Rexx program (name supplied via 
the
                                   command line argument) four times, once with
                                   .TraceObject~option set to 'N' (normal),
                                   'S' (standard), 'F' (full), 'P' (profiling 
mode);
                                   each run will have the generated TraceObjects
                                   collected in an array that could be used to 
analyze
                                   the runs afterwards

          - p2_traceInterceptor.rex ... like p1_traceRunner.rex in addition:
                                   demonstrates how to intercept each 
TraceObject

          - p3_makestring_method.rex ... demonstrates defining a makeString 
method
                                   (from a floating method or a resource) to 
replace
                                   the TraceObject's default implementation

          - p4_traceEditingPrefix.rex ... like p2_traceInterceptor.rex in 
addition:
                                   - demonstrates how to change the trace line 
information
                                   - demonstrates sorting the TraceObjects in 
different
                                     ways using comparators 
(sortByThreadInvocationNr,
                                     sortByInvocationNr) and using the default 
sort order
                                     (by NR)
                                   - demonstrates how to fetch the total 
TraceObjects created
                                     so far

          - p5_create_tracefiles.rex ... runs the supplied Rexx program and 
creates three
                                     JSON files (minimal, crlf, human legible) 
and two
                                     CSV files (with header and without header)

          - p6_recreate_from_tracefiles.rex ... recreates the traceObject 
collection from
                                    the supplied JSON or CSV file

          - p7_annotate_effective_state.rex ... WIP: runs the supplied Rexx 
program and then
                                    annotates the traceObjects with isRunning 
and hasGuardState
                                    entries


    To use the infrastructure:

        - unzip the portable ooRexx version, run setupoorexx.cmd, then the 
generated
          script setenv2rxenv.cmd and remain in that session to run the above
          programs (PATH got set in it), e.g.

             rexx p1_traceRunner.rex        test01.rex (or any other Rexx 
program)
             rexx p2_traceInterceptor.rex   test02.rex (or any other Rexx 
program)
             rexx p3_traceEditingPrefix.rex test03.rex (or any other Rexx 
program)
             ...

    Please note: the test programs are artificial and got created to test and
    demonstrate the infrastructure.


    ---

    What follows are drafts for rexxref.pdf.


    ---------------------------------------------------------------------

    Starting out with the current documentation the nomenclature is kept the 
same,
    possibly with additional information meant for the debugging section in
    rexxref.pdf.

    --- draft (rexxref.pdf) - begin ---

         15.4 Debugging Multithreaded Programs

         ooRexx allows for executing different parts of ooRexx programs on 
multiple
         threads of execution using different Rexx interpreter within a single
         operating system process.  This makes it difficult and at times even
         impossible to debug such multithreaded programs without any additional
         information about the specific execution context.  Relevant information
         for debugging multithreaded programs may be: the Rexx interpreter 
instance
         that executes an invocation ("activation") running on which operating
         system thread and whether a lock is held for exclusive access of an
         object's attribute ("object variable") pool.

         To ease debugging of multithreaded programs the execution context can 
be
         indicated with a "multithreaded trace prefix" ("OPTION") string in the
         following form "[R1 T2 I3 G A4 L5 *]", where

           - "R1": "R" stands for Rexx interpreter instance and the number (a
              counter) indicates which of the instances executes the current
              invocation (activation).

           - "T2": "T" stands for (operating system) thread and the number (a
              counter) indicates on which of the currently existing threads the
              activity gets executed

           - "I3": "I" stands for invocation (activation) and the number (a 
counter)
               indicates which invocation gets executed on that thread 
(activity)

         Information in the OPTION if currently tracing statements of method
         routines (otherwise the remainder of the prefix will be blank):

           - "G" or "U": this character indicates whether the method routine is
              defined to be guarded or unguarded.

           - "A4" : "A" stands for "attribute pool" ("object variable 
dictionary")
             and the number (a counter) indicates which object variable 
dictionary
             gets used in this invocation of the method routine.  Each object 
will
             have its own attribute pool which can be directly accessed by 
method
             routines of the same scope, i.e.  method routines that are defined 
in
             the same class from which the object got created.  Therefore the A
             indicator will refer to the same object if the number is the same.

           - "L5": "L" stands for object lock count and the number (a counter)
             indicates how many object lock reservations have taken place at 
that
             point in time. Whenever another method routine of the same scope 
gets
             invoked the object lock count increases by one, upon return the 
object
             lock count decreases by one.

           - "*" or " ": the asterisk indicates that the activity holds the 
object
             lock. Guarded methods are blocked, if they do not hold the object 
lock.
             Methods in the unguarded state will never block.

         Notes:

           - The GUARD keyword instruction can be used within a method routine 
to
             change the state from guarded (synchronize on the object lock) to
             unguarded (ignore the object lock) using unconditionally the 
keyword
             statement GUARD OFF and vice versa (using unconditionally the 
keyword
             statement GUARD ON).

           - The keyword instructions "GUARD ON someAttribute=someValue" and 
"GUARD
             OFF someAttribute=someValue" allow changing the state of the method
             routine to guarded or to unguarded depending on the value of an 
exposed
             attribute "someAttribute" which needs to get changed in another
             concurrently running method routine of the same (class) scope. Such
             attributes are known to be used as "control variables" to 
synchronize
             activities on different threads.

           - If you wish to directly change the value of any exposed attribute 
then
             make sure that the changes take place in the guarded state to 
inhibit
             concurrent updates from other threads to inhibit inconsistent 
states.

           - The object variable dictionary number represents a specific object.

           - Methods in the guarded state that do not possess the trailing 
asterisk
             are blocked, they are waiting for the object lock.

           - Methods in the unguarded state get never blocked.

           - The standard layout of the OPTION is intentionally designed to make
             parsing easy such that analyzing the trace output of complex
             multithreaded ooRexx programs becomes easy.


         Starting with ooRexx 5.1, each traced line will be represented with an
         instance of the class TraceObject. Its class attribute OPTION (see the
         documentation of the class TraceObject) is set to N (normal) by 
default.
         If one needs additional, multithreaded trace information prefixed
         then changing the class attribute OPTION to S (standard) or
         to F (full, for complex multithreaded programs) prepends it to each
         traced line. Each TraceObject will be sent as argument to the LINEOUT
         message to the .traceOutput monitor object.

         This makes it possible to intercept these trace LINEOUT messages with
         the TraceObject argument by adding one own's Rexx object as a 
destination
         object which implements the LINEOUT method (if doing so, one should
         also implement the UNKNOWN method to forward all unknown messages).

    --- draft (rexxref.pdf) - end ---


    --- draft for class TraceObject (rexxref.pdf) - begin ---

    5.3.x TraceObject Class

    A TraceObject is a subclass of StringTable and therefore is a MapCollection
    using unique character string indexes.  The items of a StringTable can be 
any
    valid Rexx object.  See also the Directory Class, a MapCollection similar to
    StringTable, but with additional methods setMethod and unsetMethod.

    The trace infrastructure of ooRexx will create an instance for each trace 
line
    and store the following information with the following indexes:

         Index               Item

         "ATTRIBUTEPOOL"     a number, makeString prepends it with the letter A
         "HASOBJECTLOCK"     .true/.false, makeString uses an asterisk, if 
.true,
                             a blank character else
         "INTERPRETER"       a number, makeString prepends it with the letter R
         "INVOCATION"        a number, makeString prepends it with the letter I
         "ISGUARDED"         .true/.false, makeString uses the letter G, if 
.true,
                             the letter U else
         "NR"                indicates the sequential creation position (used
                             for the default sorting)
         "OBJECTLOCKCOUNT"   a number, makeString prepends it with the letter L
         "OPTION"            the option at creation time, e.g. N or S
         "THREAD"            a number, makeString prepends it with the letter T
         "TIMESTAMP"         the creation .DateTime
         "TRACELINE"         the trace line string

    The section "15.4 Debugging Multithreaded Programs" gives more information
    about debugging multithreaded programs.


    r.3.x.1. collector (Class Attribute)

    This attribute controls whether created TraceObjects get collected or not.
    If its value is set to .nil (default) then the created TraceObjects are not
    collected. This attribute can be set to anything else, if the object can
    understand the APPEND message, which is the case for all OrderedCollections
    like Array.

    r.3.x.1. counter (Class Getter Attribute)

    This attribute gets used to number the TraceObjects. Its value represents
    the total number of TraceObjects created so far.

    r.3.x.2. option (Class Attribute)

    This attribute controls whether a traced line gets displayed and how
    makeString renders the traced line. The following values are defined for 
this
    attribute:

             Letter
             N       "normal", the trace line gets displayed without any
                     multithreaded prefix information.

             S       "standard", the trace line gets prefixed with a
                     bracketed string that indicates the thread and the
                     invocation number, e.g. "[T1   I2  ]" or if a method
                     routine gets traced in addition whether it was defined
                     guarded or unguarded, the object lock count and whether
                     the object lock is reserved (indicated by an asterisk),
                     e.g. "[T1   I2   G L3   *] ".

             F       "full", the trace line with a bracketed string that adds
                     the Rexx instance and the activity pool number, e.g.
                     "[R1   T2   I3  ]" or if a method routine gets traced adds
                     the attribute pool number, e.g. "R1   T2   I3   G A4   L5
                     *]".

             P       "profiling", no trace line will be shown, yet, each created
                     TraceObject will get appended to the class attribute 
COLLECTOR
                     if not .nil. This allows analyzing the execution of traced
                     Rexx programs for many purposes.


    r.3.x.3. makeStringImpl (Class Method)

    This method implements the traceline formatting according to the current
    setting of the class attribute OPTION:

             N or P          normal trace line
             S               standard prefix prepended to trace line
             F               full prefix prepended to trace line

    This method requires a single TraceObject as its argument and returns a
    string representing the traceline. Using setMakeString one is able to
    replace this method with a customized method.

    For more information see class attribute OPTION and section "15.4 Debugging
    Multithreaded Programs".

    r.3.x.4. setMakeString (Class Method)

    This method allows the Rexx programmer to supply a customized makeStringImpl
    method that will be used to replace makeStringImpl. The supplied method 
receives
    a single TraceObject as an argument and must return a string.

    r.3.x.5. compareTo

    Implements the default sort order using the value of the NR entry which is 
the
    creation sequence number.

    r.3.x.6. makeString

    This method will invoke the class method makeStringImpl supplying the 
TraceObject
    pointed to by its self variable as argument and returns the resulting 
string.

    --- draft for class TraceObject (rexxref.pdf) - end   ---



    If there are questions, comments please use the ooRexx developer list on
    sourceforge (https://sourceforge.net/p/oorexx/mailman/oorexx-devel/).

    Temporary location:<https://wi.wu.ac.at/rgf/rexx/tmp/20240128_mt/>

    2024-02-04, rgf

Note, you could use the p* scripts to run your own Rexx programs.

Any feedback is appreciated.

---rony

_______________________________________________
Oorexx-devel mailing list
Oorexx-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/oorexx-devel

Reply via email to