Announcement

Collapse
No announcement yet.

Strange problem in PB/CC 4

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

  • Michael Bell
    replied
    Originally posted by john gleason View Post
    if you're using integer exponents, it's usually faster to multiply than to raise to a power
    Very interesting John. I am pretty random about coding this sort of thing. For example, I am as likely to type
    Code:
    distance=SQR(x^2##+y^2##)
    as
    Code:
    distance=SQR(x*x+y*y)
    From running your code it would seem that the latter might run about 8 times faster - definitely worth knowing for computer-intensive applications.

    Originally posted by john gleason
    almost always faster to multiply by the reciprocal than divide by a constant
    About 3.5 times faster in your example. Again, not something that would have occurred to me, and definitely worth knowing. I might also try noticing more when other chunks of expressions don't change between iterations of a loop, and so perform calculations once rather than many times.

    Originally posted by paul dixon
    Try adding #REGISTER NONE to the start of your code to stop registers being used and the speed using EXT variables should fall.
    Tried that - code using EXT variables took almost three times as long to run with #REGISTER NONE. From this I conclude that I should think carefully about the precision of large arrays that get moved around.

    Thanks for the useful suggestions guys!
    Last edited by Michael Bell; 13 May 2009, 05:10 AM. Reason: missed out something...

    Leave a comment:


  • John Gleason
    replied
    Originally posted by Michael Bell View Post
    e.g. x!/2! calculates much quicker than x!/2## - again, perhaps not too surprising.

    MCB
    This brings up an optimization idea: Even tho division by 2 doesn't benefit as much as other divisors, It's almost always faster to multiply by the reciprocal than divide by a constant:
    Code:
    #COMPILE EXE
    #DIM ALL
    
    FUNCTION PBMAIN () AS LONG
        LOCAL t, t2 AS QUAD, ii, x, y, constDiv AS EXT
        
        '------------------- x / 2 -----------------------
           TIX t
        FOR ii = 1 TO 10000000
           x = ii / 21
        NEXT
           TIX END t
        
           TIX t2
           constDiv = 1 / 21
        FOR ii = 1 TO 10000000
           y = ii * constDiv
        NEXT
           TIX END t2
        
        ? STR$(t / t2, 4) & " x faster"
        WAITKEY$   
    END FUNCTION

    Leave a comment:


  • Paul Dixon
    replied
    Michael,
    for large arrays of data SINGLE is fastest then DOUBLE then EXT because the limit is usually the rate at which you can read the data from memory and larger data types take longer to read.

    For single values then EXT is fastest because the compiler will store up to 4 EXT variables in the FPU registers but it will always access SINGLE and DOUBLE from memory.

    Try adding #REGISTER NONE to the start of your code to stop registers being used and the speed using EXT variables should fall.

    Paul.

    Leave a comment:


  • Michael Bell
    replied
    Thanks for that RC. I've just tried a benchmark with +, -, / and * operations, and also found EXT to be the fastest (by about 28% in my test). If the values are passed to a separate function, then the advantage goes the other way (in my test, passing an EXT was about 25% slower than passing a SINGLE if passed BYVAL, and about 37% slower if passed BYREF) - not too surprising perhaps.

    Incidentally, I accidentally found that matching the variable types makes a big difference, e.g. x!/2! calculates much quicker than x!/2## - again, perhaps not too surprising.

    MCB

    Leave a comment:


  • John Gleason
    replied
    MCB, If you're using integer exponents, it's usually faster to multiply than to raise to a power as shown in this code:
    Code:
    #COMPILE EXE
    #DIM ALL
    
    FUNCTION PBMAIN () AS LONG
        LOCAL t, t2 AS QUAD, ii, x AS EXT
        '------------------- x^4 -----------------------
           TIX t
        FOR ii = 1 TO 10000000
           x = ii ^ 4
        NEXT
           TIX END t
        
           TIX t2
        FOR ii = 1 TO 10000000
           x = ii * ii
           x = x * x
        NEXT
           TIX END t2
        
        ? STR$(t / t2, 4) & " x faster"
        '===============================================
    
        '------------------- x^2 -----------------------
           TIX t
        FOR ii = 1 TO 10000000
           x = ii ^ 2
        NEXT
           TIX END t
    
           TIX t2
        FOR ii = 1 TO 10000000
           x = ii * ii
        NEXT
           TIX END t2
    
        ? STR$(t / t2, 4) & " x faster"
        '===============================================
        WAITKEY$
    END FUNCTION
    If possible, try to make calculations integer types. You may be able to pre-calculate values that you reuse, even transcendental ones. How you temporarily store your intermediate values can matter too. If you'd like to post example code from an "innermost loop", I'd bet someone here could recommend significant optimization possibilities.

    Leave a comment:


  • RC Santore
    replied
    Michael,

    I suspect that exponentiation and transcendental functions do not depend as much on the variable type being used. I thought I'd do a quick test to verify that, and found that is indeed the case.

    However I also discovered a real eye opener for me - for multiplication extended precision is the fastest (not slowest) variable type in PBCC. This probably will sound like an obvious statement to many others, but I will say it anyway to remind myself - it pays to do benchmarks with the compiler you are using and don't assume behavior will be consistent from one to another.

    Depending on the values being multiplied, using extended precision was either much faster or just slightly faster.

    As noted above, I did also find that there was much less difference with exponentiation than with multiplication operations.

    So I take back everything I said about a performance penalty from using extended precision.

    By the way, I am also use PBCC for scientific programming (coincidentally also somewhat related to fisheries).

    - R

    Leave a comment:


  • Michael Bell
    replied
    Precision and performance

    Originally posted by RC Santore View Post
    I generally try to use a sensible mix of single and double precision based on the range of expected values. But I suppose that tendency comes from a background in fortran, at a time when memory wasn't as plentiful as it is now. Although memory might not be an issue there is still a considerable performance hit when comparing single to double (about 4x the time required) to extended (about 7x to 8x) that would argue for not using more precision than needed.
    - R
    Your comment about performance interested me, as I have performance issues of my own (programming performance, that is...!). I've been running some fishery simulations, written in PB/CC5.01, and so far it's taken ten days to run 12 scenarios out of 26 - not much use when I want to explore a much wider parameter space. I tend to work in extended precision for numerical processing, but I wondered how much quicker it might run if I could get away with single precision. No much, as it turns out. I didn't let it run for long, but I couldn't notice the difference in terms of the speed of results reported to the screen.

    I tried writing some test code using different floating point types (SQR, ^, LOG and EXP operations within loops of 100,000,000 values), and I find that the same operations are in fact running up to 2% faster in extended than in single precision, which is not what I was expecting...

    Any thoughts? I'd certainly appreciate any hints for faster running code. I'm aware of #OPTIMIZE SPEED, not updating the screen too often, not having unnecessary function calls, ... As background, I use PB/CC as a tool for scientific modelling and analysis, and I'm certainly no professional programmer, so it's quite easy for comments in these forums to go right over my head.

    -MCB

    Leave a comment:


  • Michael Mattias
    replied
    If you get a numeric overflow, who knows what happens?

    However, since the compiler does not provide the intrinsic options to even know if an overflow occurred, it's probably beating a dead horse to pursue it.

    Stick with the 'usual suspects' - the kinds of errors you CAN trap by using TRY..CATCH, ON ERROR GOTO or just testing the system ERR variable.

    MCM

    Leave a comment:


  • RC Santore
    replied
    Kev - yes I know, that's not my code, the example was from the other post that Michael mentioned and was intended to create an overflow. I was just trying to see if I was following what he was trying to tell me.

    - R

    Leave a comment:


  • Kev Peel
    replied
    That would cause an infinite loop - B would never get to 256, the range is 0-255.

    Use the following:

    Code:
     
    DO
        B = B + 1
    LOOP UNTIL (B = 255)

    Leave a comment:


  • RC Santore
    replied
    Ok, I found it.

    So do I understand that you are suggesting that a numeric overflow such as what could result from:

    Code:
       LOCAL B AS BYTE
       DO WHILE B  < 256 
            B = B + 1
       LOOP
    might be causing this behavior (or just general bad things), and hence moving to EXT . . .?

    - R

    Leave a comment:


  • RC Santore
    replied
    Yes of course, with "ON ERROR GOTO" in each subroutine.

    But the first trap that trips occurs after the above, and the error doesn't make sense to me (Error 52 - Bad file name or number) so I think it to be unrelated (just another symptom but still not the disease?).

    The way I found the above is tracing backwards (figuratively speaking - although a debugger that ran backwards would be pretty neat) from where I see the Error 52. Then after looking at the above behavior for a while I started thinking that there really must be something happening even prior to all of that.

    I'll look for the Cliff Nichols post.

    Thanks again,

    - R

    Leave a comment:


  • Michael Mattias
    replied
    #DEBUG ERROR ON will do what it says it will... on bounds violation set error 9 and not attempt the statement. You still have to create code to to actually "do something" when this occurs.

    #DEBUG OVERFLOW ON is not supported. i.e, "Let Z = X/0" ==> protection fault and nothing you can do about it using only compiler intrinsics.

    (See SetUnhandledExceptionFilter() winapi function if you want to trap. There is a current thread here started by Cliff Nichols on this very topic).

    MCM

    Leave a comment:


  • RC Santore
    replied
    Thank you Michael. I should have specified that I have run this with #DEBUG ERROR ON and #DIM ALL as part of this debugging effort.

    Maybe I don't understand your last sentence, but should #DEBUG ERROR ON catch out-of-bounds subscripts? This code uses many arrays of many different types of variables. I am not sure the distinction between "trappable" and "not trappable". Can you elaborate?

    - R

    Leave a comment:


  • Michael Mattias
    replied
    always turned out to be related to over- or underflows occurring somewhere else entirely. You mention "complex math"
    I note the original code uses an array subscript. You don't need arithmetic overflow to get funky results if you refer to an out-of-bounds subscript somewhere and don't 'do something' about that.

    Or, an out-of-bounds reference (trappable) could be causing overflows (not trappable using only compiler intrinsics) because the compiler skips statements causing same (#DEBUG ERROR ON), or provides "undefined" results (#DEBUG ERROR OFF).
    Last edited by Michael Mattias; 4 May 2009, 09:23 AM.

    Leave a comment:


  • RC Santore
    replied
    Your comment about under- and over-flows is in line with my suspicion that the behavior I'm seeing here is just the symptom of some as yet undiscovered issue.

    I generally try to use a sensible mix of single and double precision based on the range of expected values. But I suppose that tendency comes from a background in fortran, at a time when memory wasn't as plentiful as it is now. Although memory might not be an issue there is still a considerable performance hit when comparing single to double (about 4x the time required) to extended (about 7x to 8x) that would argue for not using more precision than needed.

    However, I am so far at a loss to figure out what's going wrong here and I appreciate your suggestions for new approaches to try out. I'll start converting to extended and see if something turns up.

    Although I generally keep current in my PBCC and PBWIN versions, I am currently using version 4. Does anyone think version 5 would provide any new debugging aids or diagnostics for this sort of problem?

    Again, I appreciate everyone's help so far.

    - R

    Leave a comment:


  • Michael Bell
    replied
    RC
    I've had similar problems before with apparently impossible program behaviour, and they've (almost) always turned out to be related to over- or underflows occurring somewhere else entirely. You mention "complex math" - therein may lie the problem.

    If checking your dims gives no joy, then I would suggest locating all the mathematical operations that may be sensitive to inadmissible arguments - such as divisions and logs - and replace the relevant lines with code that: (i) checks the argument; (ii) performs the operation if the argument is admissible; and (iii) flags inadmissible values.

    For example, replace
    Code:
    x = y / z
    with
    Code:
    IF z <> 0## THEN
      x = y / z
    ELSE
      PRINT "ERROR: z is zero!"
      WAITKEY$
      EXIT FUNCTION ' or whatever other action is appropriate
    END IF
    Obviously, I'm only suggesting this for debugging rather than a final solution...

    As John says, it would also be a good idea to work with EXT rather than single precision - some arguments may become inadmissible simply because of precision. Working with EXT would in any case be better for complex math.

    Leave a comment:


  • John Gleason
    replied
    RC, try making the variables EXT (possibly DOUBLE would work too but I'd try EXT first), and to be sure your values are exactly entered, eg. for .000001 use either VAL(".000001") or 1 / 1000000. Perhaps some internal calc needs the extra precision.

    Leave a comment:


  • RC Santore
    replied
    I suspect you're right Kev and I am currently in the process of checking all dims - but there are a lot of variables and a lot of code (about 12,000 lines in 78 subs and functions - not sure if that's really a lot, but it isn't small either).

    This behavior is so bizarre that I suspect it won't be reproducible in any smaller program.

    Thanks again,

    - R

    Leave a comment:


  • Kev Peel
    replied
    Any chance you could draw up an example program to demonstrate? Maybe something that will also auto-generate some sample data. If the problem cannot be reproduced in a sample then more than likely (IMO) you have an issue occurring elsewhere which is corrupting or overwriting the stack. If that's the case then there is no easy option to resolve it, except combing over the code. Cutting down on the amount of globals and using parameters may also make this easier to do.

    Leave a comment:

Working...
X