There was an oversight in the test code for the release version (only half of the gc() calls get
carried out, i.e. those with the argument "force"), this version tries to take it into account:
say "version:" .RexxInfo~debug~?("DEBUG", "RELEASE")
d1=.dateTime~new
count=10000
-- in the release version only half of the gc() calls get executed
effectiveCount=count/(.RexxInfo~debug~?(1,2))
len=count~length
t1=test_gc(count)
t2=test_reverse(count)
d2=.dateTime~new
say "test_gc("count") :" t1 "->" t1/effectiveCount "per call (effective calls:"
effectiveCount")"
say "test_reverse("count"):" t2 "->" t2/count "per call"
say "total duration :" d2 - d1
::routine test_gc
use arg count
d1=.dateTime~new
do count/2
call gc -- call the garbage collector
call gc "force" -- call the garbage collector
end
return .dateTime~new - d1
::routine test_reverse
use arg count
d1=.dateTime~new
do count/2
call reverse '' -- call reverse()
call reverse '' -- call reverse()
end
return .dateTime~new - d1
Running this a couple of times yields:
G:\test\orx\gc>test_gc_speed.rex
version: RELEASE
test_gc(10000) : 00:00:00.037000 -> 00:00:00.000007 per call (effective
calls: 5000)
test_reverse(10000): 00:00:00.000000 -> 00:00:00.000000 per call
total duration : 00:00:00.037000
G:\test\orx\gc>test_gc_speed.rex
version: RELEASE
test_gc(10000) : 00:00:00.035000 -> 00:00:00.000007 per call (effective
calls: 5000)
test_reverse(10000): 00:00:00.000000 -> 00:00:00.000000 per call
total duration : 00:00:00.035000
G:\test\orx\gc>test_gc_speed.rex
version: RELEASE
test_gc(10000) : 00:00:00.036000 -> 00:00:00.000007 per call (effective
calls: 5000)
test_reverse(10000): 00:00:00.000000 -> 00:00:00.000000 per call
total duration : 00:00:00.036000
So the speed improvement between the debug and the release version is about a factor of 14. Still,
quite impressive.
---rony
On 30.08.2025 21:55, Rony G. Flatscher wrote:
For the record, running the same speed test on the same machine with the release version makes the
gc() call about twenty-five (!) times faster:
G:\test\orx\gc>rxenv rexx test_gc_speed.rex
test_gc(10000) : 00:00:00.037000 -> 00:00:00.000003 per call
test_reverse(10000): 00:00:00.000000 -> 00:00:00.000000 per call
total duration : 00:00:00.037000
G:\test\orx\gc>rxenv rexx test_gc_speed.rex
test_gc(10000) : 00:00:00.034000 -> 00:00:00.000003 per call
test_reverse(10000): 00:00:00.001000 -> 00:00:00.000000 per call
total duration : 00:00:00.036000
G:\test\orx\gc>rxenv rexx test_gc_speed.rex
test_gc(10000) : 00:00:00.034000 -> 00:00:00.000003 per call
test_reverse(10000): 00:00:00.000000 -> 00:00:00.000000 per call
total duration : 00:00:00.034000
G:\test\orx\gc>rxenv rexx test_gc_speed.rex
test_gc(10000) : 00:00:00.038000 -> 00:00:00.000003 per call
test_reverse(10000): 00:00:00.001000 -> 00:00:00.000000 per call
total duration : 00:00:00.039000
---rony
On 30.08.2025 15:41, Rony G. Flatscher wrote:
This is the planned implementation of gc() which
* always runs in a debug version of ooRexx (.RexxInfo~debug=.true)
* does *not* run in a release version of ooRexx (.RexxInfo~debug=.false) to
cater for Rick's
preoccupation; however, there is an overrule possibility if the argument
"force" is supplied
for edge cases, using it must be deliberate for a release version. This
should at least rule
out using it mistakingly in the release version, if used for debugging, but
not meant for
release.
The planned description of gc() would be:
gc(---+-------------+---)
| |
+---"Force"---+
Returns /.true/ if the garbage collector was called, /.false/ else. This
function should be
used with great care as explicitly invoking the garbage collector imposes
quite a burden on a
running system and can severely affect applications. Therefore, garbage
collection
invocations should be best left to the interpreter. If invoked from a debug
version of ooRexx
(.RexxInfo~debug=.true), the garbage collector will always be called. If
invoked from a
release version of ooRexx (.RexxInfo~debug=.false), the garbage collector
will not be called,
unless the optional argument “force” is supplied.
Enclosed you'll find the diff.
Here a little test program that invokes the garbage collector 10,000 times and compares this to
invoking 10,000 times the reverse() BIF on a debug version of ooRexx:
d1=.dateTime~new
count=10000
t1=test_gc(count)
t2=test_reverse(count)
d2=.dateTime~new
say "test_gc("count") :" t1 "->" t1/count "per call"
say "test_reverse("count"):" t2 "->" t2/count "per call"
say "total duration :" d2 - d1
::routine test_gc
use arg count
d1=.dateTime~new
do count/2
call gc -- call the garbage collector
call gc "force" -- call the garbage collector
end
return .dateTime~new - d1
::routine test_reverse
use arg count
d1=.dateTime~new
do count/2
call reverse '' -- call reverse()
call reverse '' -- call reverse()
end
return .dateTime~new - d1
Running this on a quite old PC yields:
G:\test\orx\gc>rxenv rexx test_gc_speed.rex
test_gc(10000) : 00:00:00.971000 -> 00:00:00.000097 per call
test_reverse(10000): 00:00:00.000000 -> 00:00:00.000000 per call
total duration : 00:00:00.971000
G:\test\orx\gc>rxenv rexx test_gc_speed.rex
test_gc(10000) : 00:00:01.005000 -> 00:00:00.000100 per call
test_reverse(10000): 00:00:00.004000 -> 00:00:00.000000 per call
total duration : 00:00:01.009000
G:\test\orx\gc>rxenv rexx test_gc_speed.rex
test_gc(10000) : 00:00:00.987000 -> 00:00:00.000098 per call
test_reverse(10000): 00:00:00.004000 -> 00:00:00.000000 per call
total duration : 00:00:00.991000
G:\test\orx\gc>rxenv rexx test_gc_speed.rex
test_gc(10000) : 00:00:00.972000 -> 00:00:00.000097 per call
test_reverse(10000): 00:00:00.008000 -> 00:00:00.000000 per call
total duration : 00:00:00.980000
Any comments, feedback?
---rony
On 29.08.2025 11:59, Rony G. Flatscher wrote:
Thank you all very much for your feedback (also to those who reacted with a
direct e-mail to me)!
My take away currently is that
* using a keyword is not really acceptable (it really looks a little bit
awkward)
* restricting the invocation by a predefined number may not be possible if
programs run 7/24
(where this feature might be important in edge cases)
* the hints at popular languages that allow for invoking the garbage
collector freely, making
it the responsibility of the programmer to use it cautiously and only, if
it is needed (e.g.
for unpinning non-Rexx resources that are held in Rexx objects that have
gone out of scope)
* one should clearly document and warn about misusing this feature pointing
out at potential
runtime performance implications (like in other programming languages)
---rony
On 26.08.2025 22:28, Rony G. Flatscher wrote:
There is a new library for ooRexx in development by one of my students, where objects from the
other side get proxied in registries. For debugging, it is necessary to be able to kick off a
garbage collection run.
However, as has been pointed out and discussed, it has been seen as dangerous for the
performance of ooRexx programs if ooRexx programmers use such a feature wrongly (e.g., too many
times at the wrong place, etc.).
My take would be that if programmers are made aware of that potential problem and strongly
advised not to use it for regular programs, only for situations where it becomes important that
external resources get freed that are held by Rexx objects that became garbage but do not get
garbage collected in a timely manner.
Maybe an approach like this can be acceptable?
* define a gc() built-in function that works by default in a debug version of
ooRexx (i.e.,
RexxInfo~debug yields .true) and returns .true to indicate that the BIF got
carried out,
* invoking some gc() on the release version of ooRexx (i.e., RexxInfo~debug
yields .false)
does not invoke the garbage collector and returns therefore .false.
o for very rare, special situations (like freeing external resources as
timely as
possible if Rexx objects pinning them down turn to garbage) it may make
sense to allow
gc() to be run on a release version; in order to make this explicit one
could think of
allowing an argument like "EMERGENCY" (intentionally in uppercase and
spelled out), but
only for the release version, which would indeed invoke the garbage
collection on a
release version as well and then return .true to indicate it. This
would inhibit a
mistakenly usage of gc(). If one leaves the gc() invocation from the
debug version, it
would not run the garbage collector by default on a release version.
If, however, a
programmer needs a garbage collection in the release version, it must be
"cumbersomely"
invoked, such that this can only happen intentionally.
What do you think? Any comments?
---rony
_______________________________________________
Oorexx-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/oorexx-devel