Jump to content
IGNORED

IntyBASIC - THEN IF vs AND, and performance


freewheel

Recommended Posts

I've noticed an interesting quirk, and I'm sure the experts here will see this and say "duh!":

 

When using SCROLL - and the offset_ syntax nanochess has in his examples - I'm noticing performance is absolutely essential to keep tabs on. Do too much work before your next SCROLL/WAIT, and you start to get jittery sprites. I suspect that doing enough "work" on the CPU causes it to get behind somewhat, so it has to eventually "catch up" and this is what causes my MOBs to occasionally jump around. A big offender? Using AND in IF statements. Example:

 

IF a=1 AND b=2 AND c=3 THEN do_something

 

Due to complex logic (and good old spaghetti code), I have a lot of this sort of thing going on. Well, if I convert all of these to this:

 

IF a=1 THEN IF b=2 THEN IF c=3 THEN do_something

 

It's remarkable how much calmer things are. MOBs don't jitter, and everything is smooth again. Intuitively my brain thinks that the latter is going to be "worse" - it sure is worse to read - but I guess it's only doing the first comparison much of the time and ignoring the rest, whereas the former example does all 3 comparisons every single time. Multiply this by a dozen or more of these kind of statements, and it's remarkable how much of an impact it has.

 

A warning for budding IntyBASIC programmers - limit your comparisons as much as possible :)

 

Is cmp really that processor intensive?

Link to comment
Share on other sites

I've noticed an interesting quirk, and I'm sure the experts here will see this and say "duh!":

 

When using SCROLL - and the offset_ syntax nanochess has in his examples - I'm noticing performance is absolutely essential to keep tabs on. Do too much work before your next SCROLL/WAIT, and you start to get jittery sprites. I suspect that doing enough "work" on the CPU causes it to get behind somewhat, so it has to eventually "catch up" and this is what causes my MOBs to occasionally jump around. A big offender? Using AND in IF statements. Example:

 

IF a=1 AND b=2 AND c=3 THEN do_something

 

Due to complex logic (and good old spaghetti code), I have a lot of this sort of thing going on. Well, if I convert all of these to this:

 

IF a=1 THEN IF b=2 THEN IF c=3 THEN do_something

 

It's remarkable how much calmer things are. MOBs don't jitter, and everything is smooth again. Intuitively my brain thinks that the latter is going to be "worse" - it sure is worse to read - but I guess it's only doing the first comparison much of the time and ignoring the rest, whereas the former example does all 3 comparisons every single time. Multiply this by a dozen or more of these kind of statements, and it's remarkable how much of an impact it has.

 

A warning for budding IntyBASIC programmers - limit your comparisons as much as possible :)

 

Is cmp really that processor intensive?

 

 

Ok, so I tried a dirt simple experiment with IntyBASIC 1.0. (I haven't downloaded 1.0.1 yet.) The short answer is that IntyBASIC doesn't perform short-circuit evaluation such as what C does for && and || operators. It evaluates AND and OR more like C's & and |, neither of which imply short-circuit evaluation.

 

Here's the simple test I ran:

.

if a = 1 AND b = 1 AND c = 1 then print "foo"

if a = 1 then if b = 1 then if c = 1 then print "foo"


.

For the first IF statement, you can see IntyBASIC building up the condition in the assembly code:

.

    ;[4] if a = 1 AND b = 1 AND c = 1 then print "foo"
    SRCFILE "/tmp/and.bas",4
    MVI V1,R0
    CMPI #1,R0
    MVII #-1,R0
    BEQ T2
    INCR R0
T2:
    MVI V2,R1
    CMPI #1,R1
    MVII #-1,R1
    BEQ T3
    INCR R1
T3:
    ANDR R1,R0
    MVI V3,R1
    CMPI #1,R1
    MVII #-1,R1
    BEQ T4
    INCR R1
T4:
    ANDR R1,R0
    BEQ T1
    MVI _screen,R4
    MVII #560,R0
    XOR _color,R0
    MVO@ R0,R4
    XORI #72,R0
    MVO@ R0,R4
    MVO@ R0,R4
    MVO R4,_screen
T1:

.

The code literally turns each comparison into a 0 or -1 value, and then ANDs them all together. The final result of the AND determines whether the 'THEN' or 'ELSE' condition gets evaluated.

 

With the multiple 'if' code, you can see that each IF statement jumps out of the entire evaluation once the condition's proved false. That stops the entire comparison process as soon as one of the terms compares false:

.

    ;[6] if a = 1 then if b = 1 then if c = 1 then print "foo"
    SRCFILE "/tmp/and.bas",6
    MVI V1,R0
    CMPI #1,R0
    BNE T5
    MVI V2,R0
    CMPI #1,R0
    BNE T7
    MVI V3,R0
    CMPI #1,R0
    BNE T9
    MVI _screen,R4
    MVII #560,R0
    XOR _color,R0
    MVO@ R0,R4
    XORI #72,R0
    MVO@ R0,R4
    MVO@ R0,R4
    MVO R4,_screen
T9:
T7:
T5:

.

Because the code isn't trying to compute the arithmetic AND of the test conditions, it also ends up being shorter overall.

 

So that's the reason why the latter construct ends up being more efficient.

 

Does it make sense for IntyBASIC to recognize the special case where the left-hand-side and right-hand-side of an AND or and OR are both boolean-valued expressions, and optimize it in some way? Even without short-circuiting, perhaps it could do better than it does today.

Edited by intvnut
  • Like 2
Link to comment
Share on other sites

My god, I had forgotten than C (and a ton of other languages) even did that. With so much horsepower at the table, and so much other overhead, I just don't even think of this stuff anymore. Plus I usually don't have to write so many conditionals in a single line, thanks to blocked code. The only way to simulate than in IntyBASIC is through yet another GOSUB, and that gets even more spaghetti-fied.

 

Incidentally, I've also noticed a case where unrolling a FOR loop suffered a huge performance hit with similar effects re: MOB jitter. Not sure what he hell was going on there; I was trained that the opposite behaviour is almost entirely the case.

Link to comment
Share on other sites

My god, I had forgotten than C (and a ton of other languages) even did that. With so much horsepower at the table, and so much other overhead, I just don't even think of this stuff anymore. Plus I usually don't have to write so many conditionals in a single line, thanks to blocked code. The only way to simulate than in IntyBASIC is through yet another GOSUB, and that gets even more spaghetti-fied.

 

Incidentally, I've also noticed a case where unrolling a FOR loop suffered a huge performance hit with similar effects re: MOB jitter. Not sure what he hell was going on there; I was trained that the opposite behaviour is almost entirely the case.

 

That definitely seems odd. But, if your 'rolled' loop has simpler expressions than your unrolled loop, then that makes a certain amount of sense. ie. if your 'rolled' loop looks like this:

 

.

     FOR I = 1 TO 10
     ... do something with I
     NEXT I

.

 

while your unrolled loop looks like this:

 

.

     FOR I = 1 TO 5
     ... do something with 2*I - 1
     ... do something with 2*I
     NEXT I

.

then those extra computations for 2*I - 1 and 2*I would slow you down.

 

This is a place where fancier higher-level optimizations would help, but don't really fit IntyBASIC's line-by-line, all variables live in RAM model. Induction variable elimination, strength reduction, common subexpression elimination, register allocation (as in making a variable a purely register variable) and loop rotation all apply here. Of course, compiler loop unrolling could turn the first one into the second one for you ;-) , but that's another higher-level optimization that I'm not sure works in an IntyBASIC context.

 

You might try benchmarking your IntyBASIC code in jzIntv's debugger. It prints cycle counts at the far right. See this post for some more details of how do enable IntyBASIC source-level debugging in jzIntv, if you haven't played with it already.

 

You will have to peek at the IntyBASIC compiler output, though, to find the assembler labels used for two points in your code that you want to measure between.

Edited by intvnut
  • Like 1
Link to comment
Share on other sites

My god, I had forgotten than C (and a ton of other languages) even did that.

 

Also, short-circuit evaluation is important to correctness in C. Consider the idiom: if ( p && p->something ). Without short-circuit evaluation, you could end up dereferencing a NULL pointer. IntyBASIC doesn't make such a guarantee, though.

Link to comment
Share on other sites

.

The code literally turns each comparison into a 0 or -1 value, and then ANDs them all together. The final result of the AND determines whether the 'THEN' or 'ELSE' condition gets evaluated.

 

 

Thanks for the explanation. That definitely explains the behaviour. It also elucidates why some programming languages would choose not to offer short-circuit evaluation of expressions. I always thought that short-circuit evaluation came for free, since in Assembly, you basically jump out the moment a test fails; and I always wondered why some languages like BASIC tended not to do this. Still, the code generator could be smart enough to handle it. I guess it is a lot more effort on the compiler to do so, which is why so many versions of BASIC avoid it.

 

-dZ.

Link to comment
Share on other sites

 

Thanks for the explanation. That definitely explains the behaviour. It also elucidates why some programming languages would choose not to offer short-circuit evaluation of expressions. I always thought that short-circuit evaluation came for free, since in Assembly, you basically jump out the moment a test fails; and I always wondered why some languages like BASIC tended not to do this. Still, the code generator could be smart enough to handle it. I guess it is a lot more effort on the compiler to do so, which is why so many versions of BASIC avoid it.

 

Interestingly, C has both. Short-circuit evaluation came late to the language. Originally, K&R used the same boolean operators for logical evaluation as for bitwise evaluation, which explains why the precedence of & and | is so low in C. That's also why foo & MASK == 0 is unlikely to do what you want in C.

 

Ironically, with modern processors, short-circuit evaluation actually can hurt you, as branches are expensive (particularly mispredicted branches) but math is cheap. So, modern compilers have additional tests to determine if they can turn short-circuit operators (which require a branch) into the non-short-circuiting operators safely. For my 'guard' example above, if ( p && p->something ), it can't. But for if ( a == 3 && b == 2 ), it can.

 

In the context of IntyBASIC, I suppose it would be possible for the compiler to detect that an entire expression is, say, a chain of ANDs or a chain of ORs on 0/-1 valued subexpressions and add short-circuit evaluation there as an optimization. Otherwise, AND and OR in IntyBASIC are bitwise operators, with all that implies.

Link to comment
Share on other sites

 

In the context of IntyBASIC, I suppose it would be possible for the compiler to detect that an entire expression is, say, a chain of ANDs or a chain of ORs on 0/-1 valued subexpressions and add short-circuit evaluation there as an optimization. Otherwise, AND and OR in IntyBASIC are bitwise operators, with all that implies.

 

Or implement the VB.Net kludge: And and Or are short-circuit operators, while AndAlso and OrElse retain the non-short-circuit behaviour of VB 6.0. :P

 

-dZ.

Edited by DZ-Jay
Link to comment
Share on other sites

 

Or implement the VB.Net kludge: And and Or are short-circuit operators, while AndAlso and OrElse retain the non-short-circuit behaviour of VB 6.0. :P

 

-dZ.

 

Isn't it the other way around? And and Or are bitwise, while AndAlso / OrElse are short-circuiting. You could do the same here in IntyBASIC. That'd give you an analog to C's & vs. && and | vs. ||.

 

Perl 6 has a short-circuiting XOR. Maybe that's going a step too far.

Edited by intvnut
Link to comment
Share on other sites

Unless it happens soon, I hope that if nanochess re-writes the behaviour of AND/OR, that he implements new commands for the short-circuiting. Re-writing how existing syntax works can cause a whole host of fun when you re-compile. Given that I'd like to put a large body of code out there eventually, for people to learn on and such, I really don't want to have to have caveats like "this code must be compiled with version x.y.z". That shit drives me nuts. I'm already seeing subtle changes in behaviour here and there whenever IntyBASIC is updated - granted much of that is probably my fault for trying unorthodox things.

 

To be fair, I don't see a lot of people running into what I'm seeing. An awful lot of it is just laziness, over-ambitious code being plunked into poorly-thought out frameworks, and/or spaghetti. Hm. I guess that applies to a heck of a lot of BASIC :P

  • Like 1
Link to comment
Share on other sites

Isn't it the other way around? And and Or are bitwise, while AndAlso / OrElse are short-circuiting. You could do the same here in IntyBASIC. That'd give you an analog to C's & vs. && and | vs. ||.

You are right, of course! DOH!

 

Perl 6 has a short-circuiting XOR. Maybe that's going a step too far.

Bleh. I gave up on Perl 6 right around the time the Year Of Linux On The Desktop didn't happened... :lol:

  • Like 1
Link to comment
Share on other sites

 

That year was 2003 for me. Never looked back ;)

 

Wow. They hadn't even started on an implementation by then. Me? I spent an awful 2 - 3 years with Moose in anticipation that its style would help me with Perl 6. That was awful. Moose is one of those things that draws you in with all sorts of promising features, and then beats you up in a dark alley with leaky abstractions, awful performance, plausible-yet-incorrect-or-incomplete documentation and inscrutable error messages.

 

That 2 - 3 years was about 9 months of thinking "this isn't so bad" and ~2 years of maintaining the result.

 

 

Unless it happens soon, I hope that if nanochess re-writes the behaviour of AND/OR, that he implements new commands for the short-circuiting. Re-writing how existing syntax works can cause a whole host of fun when you re-compile. Given that I'd like to put a large body of code out there eventually, for people to learn on and such, I really don't want to have to have caveats like "this code must be compiled with version x.y.z". That shit drives me nuts. I'm already seeing subtle changes in behaviour here and there whenever IntyBASIC is updated - granted much of that is probably my fault for trying unorthodox things.

 

I personally prefer having separate logical vs. bitwise booleans.

 

Heck, I even have an almost relevant license plate on my car...

 

post-14113-0-58340200-1419372396_thumb.jpg

Edited by intvnut
  • Like 1
Link to comment
Share on other sites

  • 2 weeks later...

You code in VB.NET also? Is there no limit to your powers? :)

 

I got "stuck" on a stint doing VB.NET for a while. I think VB.NET is a big improvement on old VB, but that's like saying pulling off your fingernails is preferable to chopping up an arm. I much prefer C# as an expressive language overall, though I hate the .NET framework implementation.

 

All told, I think I've programmed in over 20 distinct languages, including scripting, database, and systems development languages, in as many platforms; but I've excelled on probably less than half, and truly mastered only a handful that I really enjoyed. Traditionally, my languages of choice have been C for UNIXy things, Pascal/Delphi for DOS/Windowy things, and Perl for playing around. I find the expressiveness of Perl (and its style and philosophy) to match closely the way I think. And Pascal, because it was the first "real" language I used when I "graduated" from BASIC (not counting 6210 Assembly); so it now holds a special place in my heart. :)

 

All that said, as much as I hate VB.NET, and as much as I love Delphi, there is nothing -- NOTHING -- on Hell or Earth that can inflict such utter, excruciating agony as that wretched, demonic spawn known as Delphi.Net. Ugh, I shudder just to think about it. :sad:

 

Thankfully, I moved away from software development a few years ago, so I do my coding for fun now--such as it is. :)

 

-dZ.

Edited by DZ-Jay
  • Like 2
Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...