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

Performance RPG Figurative Constants versus Literals

72 views
Skip to first unread message

edavi...@gmail.com

unread,
Sep 19, 2005, 3:14:22 PM9/19/05
to
If I have a line of code as below, which method is the best for
performance?

@Blanks=*blanks;
.....
#1)
If @Variable=' ';
dosomething();
EndIf;

#2)
If @Variable=*blanks;
dosomething();
EndIf;

#3)
If @Variable=@blanks;
dosomething();
EndIf;


My thought is that #2 would be the best for performance. We have some
jobs that run for tens of hours. We ask this for tuning guidance.
There is another in my group that thinks that option #1 would be the
quickest and best for memory usage.

Thanks;

Edwin Davidson.

Ken

unread,
Sep 19, 2005, 6:41:41 PM9/19/05
to
Hi Edwin -

On 19 Sep 2005 12:14:22 -0700, edavi...@gmail.com wrote:

>My thought is that #2 would be the best for performance. We have some
>jobs that run for tens of hours. We ask this for tuning guidance.
>There is another in my group that thinks that option #1 would be the
>quickest and best for memory usage.

Tweaking those calculations is highly unlikely to make any measurable
difference.

That said, #3 would be worst because @blanks is a variable whose
contents could change.

#1 and #2 would most likely generate identical program code. If not
identical, #2 would have the edge because the compiler recognizes
*blanks as a figurative constant of an undefined length.

So I don't think it's going to make any real difference, but #2 is
what I would use.

--
Ken
http://www.ke9nr.net/
Opinions expressed are my own and do not necessarily represent the views
of my employer or anyone in their right mind.

Saml

unread,
Sep 19, 2005, 7:42:54 PM9/19/05
to
Probably only the compiler writers can say for sure. Or you could run a
test over a million iterations. My guess is that you'll see very little
difference. (If you do run a test, you might want to post the results.)

My expeience of long running jobs is that they ofter are not contstrained by
the CPU but by IO. If you job is IO bound and you can split it into two
jobs that run in parallel, each processing half the records, you may manage
to make it run in 50% of the time. Or at least knock off a significant chunk
of elapsed time.

Sam

<edavi...@gmail.com> wrote in message
news:1127157262....@g43g2000cwa.googlegroups.com...

DBDriver

unread,
Sep 19, 2005, 8:33:17 PM9/19/05
to

"Saml" <none@no_such_isp.com> wrote in message
news:UqidnfG_PNy...@comcast.com...

> Probably only the compiler writers can say for sure. Or you could run a
> test over a million iterations. My guess is that you'll see very little
> difference. (If you do run a test, you might want to post the results.)
>
> My expeience of long running jobs is that they ofter are not contstrained
> by the CPU but by IO. If you job is IO bound and you can split it into
> two jobs that run in parallel, each processing half the records, you may
> manage to make it run in 50% of the time. Or at least knock off a
> significant chunk of elapsed time.
>
> Sam
>

Also don't discount using SQL Script in lieu of hard coded algorithms in
programming languages. The optimisation techniques used for execution plan
generation can be quite clever. You will need to profile each statement
though to ensure your SQL scripting is appropriate to glean the best
performance.

If a full SQL script replacement is not possible then look at the
possibility of invoking SQL Scripts at selected points where a single SQL
script can do the equivalent of many lines language code. In effect this
would be a hybrid solution leveraging the best programming solution at each
step.


RJ.


edavi...@gmail.com

unread,
Sep 20, 2005, 10:41:16 AM9/20/05
to
It is difficult to test this in my environment. I've tested it in
other language such as visual basic, and the results are very
different. On the AS/400 there are so many users and jobs running it
would be diffucult to gauge the results.

I guess #4 would be ;

If @Variable=@blanks;
dosomething();
EndIf;

Where @blanks is a constant and not a variable. I do see from IBM's
site that a constant yields better performance than a variable.

VB6 generates different code between
if @variable = " "
vs.
if @variable = vbnullstring

The speed difference is very dramatic when doing millions of
iterations.

Is the RPG compiler is smart enough to yield the same machine language
(micro code?) is the question then. I have found that ' ' takes more
space than blanks when compiled per IBM's site, but not enough to
matter. However, that does lead me to think that performance would
vary as well.

Jonathan Bailey

unread,
Sep 20, 2005, 11:18:08 AM9/20/05
to
I would make a test & check the cpu seconds used for a batch job to
run. That should be reasonably consistent regardless of the load on the
achine from other users - but further tools are available.
If you are testing @variable = some string - either constant or
variable then the compiler will most likely generate a byte by byte
compare of 2 memory spaces starting at given locations & extending as
far as possible followed by any required padding with blanks - it may
well figure if the string is too short, create a long enough string
either at compile or runtime (maybe once or for every test) & copy with
padding. I dont know.
If you compare to *blanks I would expect the compiler generates a byte
by byte test of x'40' , ie the space character, for a given length
which may depend on the field at runtie if it is varlen.
I would expect the *blanks to be faster in that case as the length of
only 1 string needs be calculated, but the compiler may realise a fixed
blank or empty string is the same as *blanks.
I cant beleive this will in fact have any reasonable impact on your
performance though - I think like the others that your disk access is a
far greater concern.

I dont know VB6 - just 'some' .net but your 2 lines of vb code in .net
would not be equivalent. The 1st says is the string equal to a single
blank - which will fail if it is equal to a string of none or two
blanks ie "" <> " " <> " "
The 2nd say is the string object not pointing to anything - which is
like the null pointer in c, or rpg. .net however seems to regard a null
pointer for some items to be equivalent to a newly created empty item &
has caused me a number of problems in the past.

Jonathan

Karl Hanson

unread,
Sep 20, 2005, 11:24:28 AM9/20/05
to
edavi...@gmail.com wrote:
> It is difficult to test this in my environment. I've tested it in
> other language such as visual basic, and the results are very
> different. On the AS/400 there are so many users and jobs running it
> would be diffucult to gauge the results.
>

See the Retrieve Thread Attribute (QWTRTVTA) API:
http://publib.boulder.ibm.com/infocenter/iseries/v5r3/ic2924/index.htm?info/apis/qwtrtvta.htm

Among the retrievable values are "Processing unit time used - total for
the thread". It should be possible to instrument tests by making API
calls, to determine the processor time used, independent of other system
workload.

As noted by others, if measuring an existing I/O bound application, you
may not see much difference between various implementations (although I
am not conversant in RPG; just wanted to point out the API).

--
Karl Hanson

Jonathan Ball

unread,
Sep 20, 2005, 11:32:27 AM9/20/05
to
edavi...@gmail.com wrote:

> It is difficult to test this in my environment. I've tested it in
> other language such as visual basic, and the results are very
> different. On the AS/400 there are so many users and jobs running it
> would be diffucult to gauge the results.
>
> I guess #4 would be ;
>
> If @Variable=@blanks;
> dosomething();
> EndIf;
>
> Where @blanks is a constant and not a variable. I do see from IBM's
> site that a constant yields better performance than a variable.

Way back in the 1970s when I first got into
programming, in an IBM mainframe COBOL environment,
they taught us to use variables with a constant value
rather than literals, because it was supposed to be
better performing, and cycles were really important
back then. The explanation was that under the covers
for literals, at the assembler instruction level, the
compiler generated extra code to move the value to some
storage location, and this extra code was executed each
time you did the evaluation. I expect this is still
true, and on just about any platform.

In iSeries RPGLE, a defined constant is just defining a
memory location with a value that the program code
can't change, so in terms of evaluations, it's probably
going to be exactly like using a variable.


>
> VB6 generates different code between
> if @variable = " "
> vs.
> if @variable = vbnullstring

But nulls is very different from blanks or zeros. Null
is "not a value".

edavi...@gmail.com

unread,
Sep 21, 2005, 6:24:46 PM9/21/05
to
Okay, here is the program;

D x s 5s 0 inz

D y s 5s 0 inz

D @blanks c const(' ')

D @Cookie s 200 inz

/Free

For x = 1 to 9999;

For y = 1 to 9999;

Eval @cookie=@blanks;

EndFor;

EndFor;

/End-Free

c call 'TESTING'

c eval *inlr=*on

It does 99980001 iterations. I submit this to batch. The program
TESTING does not exist, so it errors out in batch here and asks for a
reply. I have ran this 4 different ways and here is the results;


Eval @cookie=*BLANKS;
62

Constant defined as a single blank (as shown in the program above)
73.4

Eval @cookie=' ';
73.5

Using a variable named @blanks which is not a constant.
73.8

So obviously *blanks is a performance winner in this case, while the
others are nearly identical to each other but not as quick as *blanks.
The variable appears to the slowest slower, but just barely. I would
have expected this to be faster than the ' ' test.

I ran these more than once and sometimes saw .1 CPU difference on
occasion.

I'll try replacing the eval with an IF statement tommorow and see if
the results are the same.

Jonathan Ball

unread,
Sep 21, 2005, 8:00:31 PM9/21/05
to
I did something similar, and found no appreciable difference between
any of the four (constant, variable, literal, or figurative constant):

d @blankc c const(' ')
d @blankv s 1 inz(' ')
d charfld s 1 inz(' ')
d strtime s t
d ctr s 9b 0
d display s 52
/free
strtime = %time();
for ctr = 1 to 50000000;
if charfld = @blankc; // alternately @blankv, ' ' or *blanks
endif;
endfor;
display = 'Elapsed time: ' +
%triml(%editc(%diff(%time():strtime:*s):'3')) +
' seconds';
dsply display;
*inlr = *on;
/end-free


They all took about 24 seconds for the 50,000,000 iterations. I don't
know what the physical characteristics of the machine are.

Jonathan Bailey

unread,
Sep 22, 2005, 6:51:36 AM9/22/05
to
I had similar results for all scenarios 20 seconds - except if I
increased the length of @blank as a variable to 200, when I got 25 !! A
200 long const gave 20 as well. I did see up to .3 or so variation in
results on consecutive runs of a given job. I did think that fixing the
lengths to be equal would result in quicker processing due to no
padding required. This is on a partition of an i520 I think.

Jonathan

gb

unread,
Jun 21, 2006, 5:33:49 PM6/21/06
to
I would suggest that the run time of each of the three possibilities would
be either identical or so little different as not to matter (Barbara Morris
might like to educate us on the nitty-gritty just for the fun of knowing.).
If you have performance problems on a job that runs for hours it almost
certainly won't be CPU (does the job push the CPU to 100% utilisation? No? -
then its not CPU bound). I/O is almost certainly the problem - possibly i/o
caused by paging if the memory pool is way too small. More likely caused by
too much synchronous I/O (with attendant "waits"). Difficult to say with so
little to go on - but it isn't comparisons in RPG code...

Tell us some more about the symptoms of your problem rather than asking for
detailed help on what you think may be the resolution. It will allow many
more people to constructively aid you...

HTH

GB

<edavi...@gmail.com> wrote in message
news:1127157262....@g43g2000cwa.googlegroups.com...

edavi...@gmail.com

unread,
Jun 22, 2006, 9:54:21 AM6/22/06
to
> Tell us some more about the symptoms of your problem rather than asking for
> detailed help on what you think may be the resolution. It will allow many
> more people to constructively aid you...

The symptoms are that we want to write our programs efficiently and we
have disputes about the use of *blanks versus ' ' amoung a few of us.
I seem to recall that *blanks is better for performance, but can't
recall my source. Another thinks ' ' is better.

its me

unread,
Jun 22, 2006, 2:37:08 PM6/22/06
to
Re the performance:
I suspect that there may be a few microseconds difference
in compilation times between the two methods,
but I also suspect that the compiled code will be
identical, so no performance difference when
running the resulting program.

<edavi...@gmail.com> wrote in message
news:1150984461.0...@p79g2000cwp.googlegroups.com...

gb

unread,
Jun 22, 2006, 5:04:15 PM6/22/06
to
<edavi...@gmail.com> wrote in message
news:1150984461.0...@p79g2000cwp.googlegroups.com...

Ah well if thats all you want to know, write three programs to execute the
code in the three different ways and put in a loop to do the code 1,000,000
times (or 10,000,000 or 100,000,000) until you get a difference in run
time... Then divide the difference in run time by the number of times round
the loop to get the difference - you might need a lot of decimal places on
your calculator though... :-)

I would suggest that if there is any difference between the comparisons, you
could save a thousand times the difference by elimination of just one
database i/o during the run time of a program.

If you really do have programs that take hours, this is not repeat not where
the time is going.

HTH

GB


edavi...@gmail.com

unread,
Jun 22, 2006, 5:52:49 PM6/22/06
to
> Ah well if thats all you want to know, write three programs to execute the
> code in the three different ways and put in a loop to do the code 1,000,000
> times (or 10,000,000 or 100,000,000) until you get a difference in run
> time... Then divide the difference in run time by the number of times round
> the loop to get the difference - you might need a lot of decimal places on
> your calculator though... :-)

Yea, already did that. Posted the results too;

http://groups.google.com/group/comp.sys.ibm.as400.misc/tree/browse_frm/thread/467cae01dbc70351/6bcd29ebfd5c1d38?rnum=1&q=edavid3001&_done=%2Fgroup%2Fcomp.sys.ibm.as400.misc%2Fbrowse_frm%2Fthread%2F467cae01dbc70351%2F3aaf3a328fbf16cc%3Flnk%3Dst%26q%3Dedavid3001%26rnum%3D1%26#doc_6211c694470782f4

In my case *blanks was a clear winner, but another did something very
simular and had no difference.

>I suspect that there may be a few microseconds difference
>in compilation times between the two methods,
>but I also suspect that the compiled code will be
>identical, so no performance difference when
>running the resulting program.

I'm really after a definitive answer, not guesses. Hope that doesn't
sound harsh.

I would suspect that the compiler would store *blanks as a single byte
since it is a known figurative constant, and ' ' would require more
than a single byte since it has to store a value and a definition. So
it'd compile a byte or so bigger. I would also suspect that comparing
a 132 character string to a figurative constant would be quicker in the
microcode than comparing a 132 character string to another string or
costant. I know in VB it makes a huge difference. I have GB files I
do string comparisons over in VB. Proper string scanning can take a
process from taking a day to taking hours.

Fact is in RPG I don't know the answer, and was wonder if anyone did
know for a fact.

It is a given that going back into thousands of programs and switching
to using whichever is the best; *blanks or ' ' or @blanks, is not going
to make difference worth paying off. But I want to code new programs
with whichever is the best to use.

Last week I sat down with a program that runs every hour for ~400
seconds. I re-wrote pieces of it taking the process down to about 15
seconds to do the exact same work just by optimizing the code. SETLL
vs CHAIN. CHAIN/Update vs. SQL SELECT/Update. The CPU and disk
utilization dropped. Same way of doing the same thing, but different
ways work faster. *blanks versus ' ' will never result in that type
of savings.

The fact that jobs runs for 10 hours isn't the issue I'm asking about.
That 10 hours is tuned. The overhead is on the journal receiver
awaiting a PC to reply on most of these. So the delay causing 10 hours
is in the PC 3rd party software which we cannot touch. They are using
IBM Client Access API's to process journals which suck as they open a
new AS/400 connection each time they write to a journal. Over millions
of transactions the overhead of this is a killer. Many of the RPG
processing lines compare the DS of the results to blanks.

Thanks

bmo...@ca.ibm.com

unread,
Jun 30, 2006, 11:17:49 AM6/30/06
to
edavi...@gmail.com wrote:
> ...

> I would suspect that the compiler would store *blanks as a single byte
> since it is a known figurative constant, and ' ' would require more
> than a single byte since it has to store a value and a definition. So
> it'd compile a byte or so bigger. I would also suspect that comparing
> a 132 character string to a figurative constant would be quicker in the
> microcode than comparing a 132 character string to another string or
> costant. ...

The compiler doesn't necessarily store *BLANKS as a single byte or as a
longer string. It might not store it at all. It depends on the exact
comparison or assignment being done. If the compiler was really
clever, it might notice that ' ' was a blank, and that it could behave
as though *BLANKS had been coded. (I don't know if it actually does
this, though. If not, for the ' ' case, it would take an extra
instruction (assign the blank, then assign *BLANKS to the remainder)
but also the *BLANKS would be one byte shorter.

> ...


> It is a given that going back into thousands of programs and switching
> to using whichever is the best; *blanks or ' ' or @blanks, is not going
> to make difference worth paying off. But I want to code new programs
> with whichever is the best to use.

For something like this, where the specifics of the compiler's code
generation might cause a slight difference in performance, whatever is
slightly faster today might be slightly slower tomorrow, either due to
compiler changes, or system changes. So I would use ' ' or *BLANKS
based on aesthetics rather than possible tiny performance differences.
As a rule of thumb, only remember "rules" about performance that seem
to make sense no matter what the specifics of the system or the
language or the compiler. For things that really do matter, where
there is a difference like 10 hours vs 10 minutes, keep all working
versions, plus the performance test harness, just in case things
change.

When doing performance tests, you have to make sure that your loop runs
long enough to overcome whatever method you are using to do your
timing. Using an exception for a failed call is probably the most
unreliable way to determine a timing, but even using %TIME can add some
variations to the runs. Set up your performance tests so that the
quickest running version takes a good long time, say at least 30
seconds. And repeat the tests several times in different orders, using
the best result for each method for comparison rather than an average.
(At least for cases like this, where you are just interested in how
long a particular calculation takes; for other things like I/O, elapsed
time does matter.)

0 new messages