@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.
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.
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...
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.
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.
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
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
> 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".
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.
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
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...
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.
<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
Yea, already did that. Posted the results too;
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
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.)