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

Regina Rexx Design Question

18 views
Skip to first unread message

Bullet

unread,
Jan 3, 2010, 2:30:02 PM1/3/10
to
Hello,
I am running Regina Rexx 3.4 (soon 3.5 I expect) on Ubuntu 9.10.

I need some help, direction, or confirmation on designing rexx
routines.
As I understand it general rexx routines called by many rexx routines
should be external programs so you just have to maintain one program
in one place. As a result PROCEDURE EXPOSE is of little use since it
can only be used by internal routines. One should therefore share
information to the calling rexx program from the external rexx routine
(s) via return codes and the program stack using PUSH, PULL, and
QUEUE. Most authors seem to recommend avoiding the use of global
variables so I am left with using the program stack. I have no
problem with that--I just wanted some confirmation that I am on the
right track. I plan to keep the rexx routines in a common directory
or at least include the path to the general routines in PATH or
REGINA_MACROS. I have reached these
conclusions based on some testing I have done. Can anyone help me
with this or confirm my direction?

Jeremy Nicoll - news posts

unread,
Jan 3, 2010, 5:52:07 PM1/3/10
to
Bullet <rc...@fortinedsl.net> wrote:

> Hello,
> I am running Regina Rexx 3.4 (soon 3.5 I expect) on Ubuntu 9.10.
>
> I need some help, direction, or confirmation on designing rexx
> routines.

> As I understand it general rexx routines called by many rexx routines
> should be external programs so you just have to maintain one program
> in one place.

But only if the overhead in calling the external routine is acceptable.

Otherwise you might be better to use a mechanism where you keep one master
copy of each subroutine, but embed it in each program's source using some
sort of #include process. If Regina doesn't support that dynamically, how
about having a regular (overnight?) build process that merges your reference
copies of mainline & subroutines to create tomorrow's version of the code
for each program.

> One should therefore share information to the calling rexx program from
> the external rexx routine (s) via return codes and the program stack using
> PUSH, PULL, and QUEUE.

If you like, but why not pass stuff as parameters? You need to think about
this when you design subroutines.

The main problem with stacks is what happens if data is left on them.


> Most authors seem to recommend avoiding the use of global variables

Do you mean between execs and external subroutines? Are there global vars
in that situation? (Might depend on your OS I suppose.)

> so I am left with using the program stack.

What's wrong with passing parameters back and forth?

--
Jeremy C B Nicoll - my opinions are my own.

Email sent to my from-address will be deleted. Instead, please reply
to newsre...@wingsandbeaks.org.uk replacing "nnn" by "284".

Frank Clarke

unread,
Jan 4, 2010, 8:13:50 AM1/4/10
to
On Sun, 3 Jan 2010 11:30:02 -0800 (PST), Bullet <rc...@fortinedsl.net> wrote:
<e4ba30ea-ba5f-442d...@k23g2000yqa.googlegroups.com>

This is the technique I used very successfully at several companies using
mainframe REXX. I can't imagine it wouldn't work for Regina. Especially when
the volume of data-being-passed is large, unknown, or highly variable, I would
recommend using the stack.


(change Arabic number to Roman numeral to email)

Bullet

unread,
Jan 4, 2010, 12:01:02 PM1/4/10
to
Jeremy,
Thanks for your comments and suggestions. I have inserted responses
below.
On Jan 3, 3:52 pm, Jeremy Nicoll - news posts
<jn.nntp.scrap...@wingsandbeaks.org.uk> wrote:

> Bullet <r...@fortinedsl.net> wrote:
> > Hello,
> > I am running Regina Rexx 3.4 (soon 3.5 I expect) on Ubuntu 9.10.
>
> > I need some help, direction, or confirmation on designing rexx
> > routines.
> > As I understand it general rexx routines called by many rexx routines
> > should be external programs so you just have to maintain one program
> > in one place.
>
> But only if the overhead in calling the external routine is acceptable.
>
> Otherwise you might be better to use a mechanism where you keep one master
> copy of each subroutine, but embed it in each program's source using some
> sort of #include process.  If Regina doesn't support that dynamically, how
> about having a regular (overnight?) build process that merges your reference
> copies of mainline & subroutines to create tomorrow's version of the code
> for each program.
Good idea. I do not think such a macro facility exists for including
routines.
The overnight build would work with some programming. It may exceed
the bit of overhead incurred by calling external routines.

>
> > One should therefore share information to the calling rexx program from
> > the external rexx routine (s) via return codes and the program stack using
> > PUSH, PULL, and QUEUE.
>
> If you like, but why not pass stuff as parameters?  You need to think about
> this when you design subroutines.  
Passing stuff in as parameters is what I normally do. Returning data
has to be done thru the stack or the string RESULT.
Multiple strings contained in RESULT would have to be PARSEd by the
calling routine. It seems simpler to just use the stack.

>
> The main problem with stacks is what happens if data is left on them.
I have never had a problem dealing with the stack. I take care of
what I put in it myself and leave what other programs may have put in
it for them to deal with.

>
> > Most authors seem to recommend avoiding the use of global variables
>
> Do you mean between execs and external subroutines?  Are there global vars
> in that situation?  (Might depend on your OS I suppose.)
I don't think global vars will work for me on linux.

>
> > so I am left with using the program stack.
>
> What's wrong with passing parameters back and forth?
See comment above about ripping apart RESULT.
Thanks again for you comments.

>
> --
> Jeremy C B Nicoll - my opinions are my own.
>
> Email sent to my from-address will be deleted. Instead, please reply
> to newsreply...@wingsandbeaks.org.uk replacing "nnn" by "284".  

Bullet

unread,
Jan 4, 2010, 12:04:17 PM1/4/10
to
On Jan 4, 6:13 am, Frank Clarke <m5sr...@tampabay.rr.com> wrote:
> On Sun, 3 Jan 2010 11:30:02 -0800 (PST), Bullet <r...@fortinedsl.net> wrote:
>
> <e4ba30ea-ba5f-442d-8b46-a678aca6e...@k23g2000yqa.googlegroups.com>

Thanks, Frank

I needed confirmation I was on the right track and had not overlooked
some other technique.
That's what I did on VM/CMS as well. Been a few years. IBM had some
other programs like EXECIO that made life easier as well.

LesK

unread,
Jan 4, 2010, 2:40:25 PM1/4/10
to
You might be interested in the Experimental Include
Facility that I presented at the 2008 Rexx Symposium:

http://www.rexxla.org/events/2008/presentations/les/rexxsymp2008_lesk_experimen.htm


The presentation includes timings for my ancient Gateway
desktop running W2K, rated at 1215067
RexxCPS.

You'll have to modify the code that reads the included
file, as well as the SYNTAX trap, as I wrote it for OORexx.

Note that this technique uses INTERPRET, so all variables
are available to the included code. For performance reasons
there are two routines: INCLUDE and INCLUDE_LOGIC.

Also, don't neglect exploring the capabilities of your
Linux. If it can keep code in storage (like CMS can) that
could make a big performance difference, either positive or
negative depending on the nature of the workload.


Les (Change Arabic to Roman to email me)

Jeremy Nicoll - news posts

unread,
Jan 4, 2010, 6:39:49 PM1/4/10
to
Bullet <rc...@fortinedsl.net> wrote:

> Jeremy,
> Thanks for your comments and suggestions. I have inserted responses
> below.
> On Jan 3, 3:52�pm, Jeremy Nicoll - news posts
> <jn.nntp.scrap...@wingsandbeaks.org.uk> wrote:

> > If you like, but why not pass stuff as parameters? �You need to think
> > about this when you design subroutines.

> Passing stuff in as parameters is what I normally do. Returning data
> has to be done thru the stack or the string RESULT.

> Multiple strings contained in RESULT would have to be PARSEd by the
> calling routine. It seems simpler to just use the stack.

But simpler (if it is) isn't the only issue. If result contains multiple
concatenated strings, it's still immediately available to the caller.

Stuff in the stack has to be read into a stem or whatever, probably in an
iterative loop, which isn't necessarily as fast as parsing the great big
string.

What's worse is that with a stack you have to read everything that's above
the r'th item before you access the r'th item.

Depending on what you need to pass back to a caller, a subroutine might for
example do things and build various stem arrays, then 'flatten' them (an
overhead that /might/ be avoidable by not using stems in the first place in
the subroutine. Even if you do use stems and have to flatten them so that
you've got one long string per stem, you could then return something like

return length(one) length(two) length(three) one two three

The caller can chop that up into the three separate strings in one parse
statement, very fast.

The caller can then process, say, the contents of 'two' without having to
process 'one' first.

With care in the design I'm sure this is usable.

The alternative I'd use next is (was on MVS), to write large amounts of
passed data to a VIO file, or a ram disk one under linux. Why? because in
debugging if nothing else you can invoke browse/edit on the temporary file
and see the whole of the passed-data in one easy operation. How do you
examine what's on a stack?

--
Jeremy C B Nicoll - my opinions are my own.

Email sent to my from-address will be deleted. Instead, please reply

to newsre...@wingsandbeaks.org.uk replacing "nnn" by "284".

CyberSimian

unread,
Jan 5, 2010, 5:11:40 AM1/5/10
to
Bullet wrote:
> I have reached these
> conclusions based on some testing I have done. Can anyone help me
> with this or confirm my direction?

I am surprised that no one has suggested using the "use arg" instruction (in
place of the "parse arg" instruction). Does Regina not support "use arg"?
Example of use (invoke "usearg" from the command line to see the results):

------------------------------
/* usearg.rex */
stem.1=111
stem.2=222
stem.3=333
stem.0text='This is a string'
say 'before: 'stem.1 stem.2 stem.3 stem.0text
call usearg2 stem.
say 'after: 'stem.1 stem.2 stem.3 stem.0text
exit
------------------------------
/* usearg2.rex */
use arg stem.
stem.2='***'
stem.0text=copies('*',length(stem.0text))
return
------------------------------

Note the use of stem tails that BEGIN with a numeric digit. This forces those
tails to be constants, and so they cannot be misconstrued by the REXX
interpreter as being the names of variables that should be substituted.
Example: this would give a different result:

text='111'
stem.text=copies('*',length(stem.text))

Also, I would not be concerned unduly about performance. Remember that after
the first invocation of a separate REXX subprogram, that subprogram will
reside in the disk cache (RAM) from where it will be read on the next
invocation. If using separate REXX subprograms REALLY has an effect on the
performance of your application, then you have written that application in the
wrong programming language -- you should not be using REXX.

-- from CyberSimian in the UK


Glenn Knickerbocker

unread,
Jan 5, 2010, 2:18:02 PM1/5/10
to
CyberSimian wrote:
> I am surprised that no one has suggested using the "use arg" instruction (in
> place of the "parse arg" instruction). Does Regina not support "use arg"?

Regina is Classic Rexx, not Object Rexx.

�R

Bullet

unread,
Jan 6, 2010, 11:46:07 AM1/6/10
to
On Jan 4, 4:39 pm, Jeremy Nicoll - news posts
<jn.nntp.scrap...@wingsandbeaks.org.uk> wrote:

> Bullet <r...@fortinedsl.net> wrote:
> > Jeremy,
> > Thanks for your comments and suggestions.  I have inserted responses
> > below.
> > On Jan 3, 3:52 pm, Jeremy Nicoll - news posts
> > <jn.nntp.scrap...@wingsandbeaks.org.uk> wrote:
> > > If you like, but why not pass stuff as parameters?  You need to think
> > > about this when you design subroutines.
> > Passing stuff in as parameters is what I normally do.  Returning data
> > has to be done thru the stack or the string RESULT.
> > Multiple strings contained in RESULT would have to be PARSEd by the
> > calling routine.  It seems simpler to just use the stack.
>
> But simpler (if it is) isn't the only issue.  If result contains multiple
> concatenated strings, it's still immediately available to the caller.
>
> Stuff in the stack has to be read into a stem or whatever, probably in an
> iterative loop, which isn't necessarily as fast as parsing the great big
> string.
>
> What's worse is that with a stack you have to read everything that's above
> the r'th item before you access the r'th item.
I simply use PUSH in the called routine and PARSE PULL in the calling
routine. If I know how many lines I put in the stack, it is an easy
matter to get just those lines out.

>
> Depending on what you need to pass back to a caller, a subroutine might for
> example do things and build various stem arrays, then 'flatten' them (an
> overhead that /might/ be avoidable by not using stems in the first place in
> the subroutine.  Even if you do use stems and have to flatten them so that
> you've got one long string per stem, you could then return something like
>
>   return length(one) length(two) length(three) one two three
>
> The caller can chop that up into the three separate strings in one parse
> statement, very fast.
>
> The caller can then process, say, the contents of 'two' without having to
> process 'one' first.
>
> With care in the design I'm sure this is usable.
I understand what you are saying. You may be correct about PARSing
RESULT vs. using the stack. The only way to be certain is to test the
idea. Since I have time I will develop sample routines for each
approach and measure them for efficiency. I do not have a "feel" for
which approach might be more efficient execution wise. Not much
difference programming wise. Many as you seem to feel that I/O is
what makes things less efficient. We are also told not to be
concerned with efficiency b/c of hardware improvements, but some of us
would still like to know the preferred way of doing things given that
programming efforts are somewhat equal. Can anyone point me toward
measurement tools on linux? I have only done it on VM/CMS. I will
report findings back here.

>
> The alternative I'd use next is (was on MVS), to write large amounts of
> passed data to a VIO file, or a ram disk one under linux.  Why?  because in
> debugging if nothing else you can invoke browse/edit on the temporary file
> and see the whole of the passed-data in one easy operation.  How do you
> examine what's on a stack?
Back to I/O again. You can always write the stack to an output file
for testing/debugging purposes.

>
> --
> Jeremy C B Nicoll - my opinions are my own.
>
> Email sent to my from-address will be deleted. Instead, please reply
> to newsreply...@wingsandbeaks.org.uk replacing "nnn" by "284".  

Jeremy Nicoll - news posts

unread,
Jan 6, 2010, 1:33:16 PM1/6/10
to
Bullet <rc...@fortinedsl.net> wrote:

Yes, but doing so destroys the stack, so if other processes need it you;d
have to re-stack all the data.


--
Jeremy C B Nicoll - my opinions are my own.

Email sent to my from-address will be deleted. Instead, please reply

to newsre...@wingsandbeaks.org.uk replacing "nnn" by "284".

LesK

unread,
Jan 6, 2010, 2:19:05 PM1/6/10
to
The stack concept is based on the CMS stack and on CMS the
general user is single threaded. Thus it is up to the
developer to properly manage writing to and reading from
the stack. Also, on CMS there are tools for examining the
stack w/o destroying it. CMS and MVS provide MAKEBUF and
DROPBUF to help isolate groups of stacked data but the
groups still have to be read in the correct order by the
correct recipient, since the groups can't readily be
re-ordered w/o some delicate Pipes.

As for Windows performance, that's trickier to measure. We
know that in ooRexx the performance of PARSE is not
optimized the way it is on CMS (where Rexx was originally
written), so PARSE is not *always* the preferred choice if
absolute performance is a requirement. CMS let's you
measure 'compute time' but I know of no way of doing so
under Windows or any other pc OS.

Les (Change Arabic to Roman to email me)

Jeremy Nicoll - news posts

unread,
Jan 6, 2010, 4:38:47 PM1/6/10
to
LesK <5mr...@tampabay.rr.com> wrote:

> CMS let's you measure 'compute time' but I know of no way of doing so
> under Windows or any other pc OS.

I was reading the website of something called "AnVir Task Manager Pro"
yesterday and they showed displays of info showing process and thread CPU
utilisation, possibly (can't recall) at user and kernel levels.

I did elsewhere read a review of AnVir which said that some of figures it
reported for things were at odds with Windows' own Task Manager displays,
but wasn't it always the case that diferent monitors don't agree...?


SysInternals' Process Explorer and Process Manager might do this too.

Also in XP if you go to Control Panel -> Administrative Tools ->
Performance, there are ways of turning on the collection of performance
data. I have no idea how detailed that can be, though I do know you can
define 'alerts' for a huge range of things hitting arbitrary threshholds.

(This might well be XP Pro only.)

LesK

unread,
Jan 6, 2010, 10:18:35 PM1/6/10
to
On the pc you have to turn on the data collection, collect
all the data, turn it off and then analyze what you
collected to find what you want. You can't use TIME('E')
because you have no way of accounting for 'other stuff'
that the pc is doing.

On CMS you write a simple timing wrapper that collects the
starting numbers, invokes the program, collects the ending
numbers and displays/logs what you want. You can do this
because the underlying CP (which sits just above the
hardware) keeps all the counters for each userid and each
userid is single threaded.

Les (Change Arabic to Roman to email me)

Jeremy Nicoll - news posts wrote:

bullet

unread,
Jan 7, 2010, 12:13:49 PM1/7/10
to
On Jan 6, 11:33 am, Jeremy Nicoll - news posts
<jn.nntp.scrap...@wingsandbeaks.org.uk> wrote:

> Bullet <r...@fortinedsl.net> wrote:
> > On Jan 4, 4:39 pm, Jeremy Nicoll - news posts
> > <jn.nntp.scrap...@wingsandbeaks.org.uk> wrote:
> > > The alternative I'd use next is (was on MVS), to write large amounts of
> > > passed data to a VIO file, or a ram disk one under linux.  Why?  because
> > > in debugging if nothing else you can invoke browse/edit on the temporary
> > > file and see the whole of the passed-data in one easy operation.  How do
> > > you examine what's on a stack?
> > Back to I/O again.  You can always write the stack to an output file
> > for testing/debugging purposes.
>
> Yes, but doing so destroys the stack, so if other processes need it you;d
> have to re-stack all the data.
No the stack is not destroyed. That is the major use of PUSH and
QUEUE. Here's an an example for you. Note I first pull the last item
pushed then pull the first of the 2 items pushed. The queued lines
are preserved.
test1.rexx:
/* Updated 01/04/10 09:50:53 by rob */
queue "queued line 1"
queue "queued line 2"
queue "queued line 3"
say "Queue before pushing to stack = "queued()
call 'test2.rexx' argument1, argument2
say "Queue after pushing to stack = "queued()
say "Lines added to stack = "result
parse pull p2
parse pull p1
say 'p1 = 'p1
say 'p2 = 'p2
say "Queue after parsing pushed lines from stack = "queued()
pull q1
pull q2
pull q3
say 'q1 = 'q1
say 'q2 = 'q2
say 'q3 = 'q3
say "Queue after parsing queued lines from stack = "queued()
exit

test2.rexx:
/* Updated 01/04/10 09:51:22 by rob */
parse arg a1, a2
/*
say a1
say a2
*/
p1 = 'p1 is pushed 1st'
p2 = 'p2 is pushed 2nd'
push p1
push p2
lines_added_to_stack = 2
return lines_added_to_stack

run from a terminal window:
rexx test1.rexx
Queue before pushing to stack = 3
Queue after pushing to stack = 5
Lines added to stack = 2
p1 = p1 is pushed 1st
p2 = p2 is pushed 2nd
Queue after parsing pushed lines from stack = 3
q1 = QUEUED LINE 1
q2 = QUEUED LINE 2
q3 = QUEUED LINE 3
Queue after parsing queued lines from stack = 0
rob@fargo:~$


>
> --
> Jeremy C B Nicoll - my opinions are my own.
>
> Email sent to my from-address will be deleted. Instead, please reply

> to newsreply...@wingsandbeaks.org.uk replacing "nnn" by "284".  

LesK

unread,
Jan 7, 2010, 6:11:55 PM1/7/10
to
Nice example! The thing to remember is that Queue adds
lines to the *bottom* of the stack in so they are read in
the same order and that Push adds lines to the *top* of the
stack so they are read in reverse order. In the example,
after putting all lines in the queue, it looks like this:

Pushed 2
Pushed 1
Queued 1
Queued 2
Queued 3

Thus you can see that the application could test for how
many lines are *already* in the queue (perhaps left by an
earlier application), PUSH the lines it wants processed by
its subroutine and then tell the subroutine to pull that
many lines. On return from the subroutine the paranoid
programmer will test that the correct number of lines are
still in the stack *unless* the subroutine pushes answer
data on the stack, in which case the caller knows how many
lines to pull.

Typically, lines are pushed so that the called routine
doesn't have to cope with queued lines that are earlier in
the stack than the desired lines. In CMS and MVS one uses
MAKEBUF to 'mark' the stacked data. On the pc you have to
take precautions that are specific to the interpreter.
OoRexx, for instance, allows you to 'name' the queue, thus
isolating your data from some parallel process, as long as
the names are unique. Without a methodology like that,
you're reduced to pushing N lines and then pushing (or
passing) N to tell the called routine how many lines to pull.


Les (Change Arabic to Roman to email me)

Jeremy Nicoll - news posts

unread,
Jan 7, 2010, 6:36:17 PM1/7/10
to
bullet <rcbu...@gmail.com> wrote:

> On Jan 6, 11:33�am, Jeremy Nicoll - news posts
> <jn.nntp.scrap...@wingsandbeaks.org.uk> wrote:
> > Bullet <r...@fortinedsl.net> wrote:

> > > Back to I/O again. �You can always write the stack to an output file
> > > for testing/debugging purposes.
> >
> > Yes, but doing so destroys the stack, so if other processes need it
> > you;d have to re-stack all the data.

> No the stack is not destroyed. That is the major use of PUSH and
> QUEUE. Here's an an example for you.

Your example merely shows data being queued/pushed onto a stack and then
taken off it again. That's not the point.

Suppose at some place in your code you wanted to see (for debugging
purposes) the current contents of that stack. Above, you said you could
write the stack's contents to a file - which you could do - but doing so (as
I said) takes all the data off the stack. So if the next part of the code
requires the data you inspected to be on the stack (which it would do
because the code was written to expect the data to be on a stack), you'd
need to put it all back.

If instead you write such data into a temporary file you can at any point
inspect the contents of the file without having to recreate it after you've
looked.

AS an aside, could you include some blank lines in what you post? Whenever
I read your posts I have to go through them and separate the blocks of text,
to make it easy to see what's where. For example I find:

--
Jeremy C B Nicoll - my opinions are my own.

Email sent to my from-address will be deleted. Instead, please reply

to newsre...@wingsandbeaks.org.uk replacing "nnn" by "284".

bullet

unread,
Jan 8, 2010, 11:37:27 AM1/8/10
to
On Jan 7, 4:36 pm, Jeremy Nicoll - news posts
<jn.nntp.scrap...@wingsandbeaks.org.uk> wrote:
> to newsreply...@wingsandbeaks.org.uk replacing "nnn" by "284".  

Good discussion, but I think we may be digressing here. Everyone
seems to be correct in what they are saying. Once I find some decent
metrics for comparing programs on linux I will run some tests
comparing parsing results vs using the program stack.

danfan46

unread,
Jan 8, 2010, 12:05:12 PM1/8/10
to
Hi!

If you prepend a linux commandline with the command time you get some
kind of measurment.

>$ time mycmd.rex
... rex output ...
real 0m46.059s
user 0m5.828s
sys 0m0.236s
See also man time (lots of options)
/dg

bullet

unread,
Jan 10, 2010, 11:39:41 AM1/10/10
to

Thanks, danfan46,
I found the prefix time command just about the same time you made the
suggestion. That's what I will use to compare routines.

0 new messages