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?
> 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".
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)
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.
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,
> 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".
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
Regina is Classic Rexx, not Object Rexx.
�R
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".
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)
> 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.)
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:
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".
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)
> 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".
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.
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
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.