Recent

Author Topic: Lazarus / delphi loop efficiency: continue or begin..end?  (Read 13013 times)

JernejL

  • Jr. Member
  • **
  • Posts: 92
Re: Lazarus / delphi loop efficiency: continue or begin..end?
« Reply #15 on: March 14, 2018, 08:42:52 am »
One is array of pointers and other an array of booleans to see which contain objects.
 
I think this is clearly a bad design (had good intentions), the list grows and shrinks a lot, and i will change this to a linked list.
 
Still the original question.. There is no clear info on how any pascal compilers will handle such continues in loops?
 
i'm still wondering if "with TActor(Actors.Data) do" / or "pActor:=PActor(@Actors.Data);" method is faster..
 

SymbolicFrank

  • Hero Member
  • *****
  • Posts: 1313
Re: Lazarus / delphi loop efficiency: continue or begin..end?
« Reply #16 on: March 14, 2018, 09:16:12 am »
I agree with Nitorami: just write it in the way that makes it the most readable to you. And if turns out to be too slow, come up with a totally different (smarter) approach.

For example, I like to break up actions into separate steps as much as possible. I don't like deep nesting:

Code: Pascal  [Select][+][-]
  1. function Test(Amount, Match: Integer): Boolean;
  2. var
  3.   x: Integer;
  4. begin
  5.   Result := False;  // Initial value
  6.  
  7.   if (Amount < 0) or (Amount > SomeValue) then Exit;  // Test parameters
  8.  
  9.   for x := 0 to Amount - 1 do
  10.   begin
  11.     if (Amount mod x = 0) then Continue;  // Not this one
  12.  
  13.     if (SomeArray[x] = Match) then // Found one, do something
  14.     begin
  15.       Result := True;
  16.       Break;  // We're done
  17.     end;
  18.  
  19.     // if something else ....
  20.   end;
  21.  
  22.   // Do cleanup
  23. end;

But I would probably use an Exit instead of the Break, and a try .. finally for cleanup.

Handoko

  • Hero Member
  • *****
  • Posts: 5131
  • My goal: build my own game engine using Lazarus
Re: Lazarus / delphi loop efficiency: continue or begin..end?
« Reply #17 on: March 14, 2018, 09:22:08 am »
Still the original question.. There is no clear info on how any pascal compilers will handle such continues in loops?

Hi JernejL. I think you will never get the answer. As Martin already said the FPC compiler changes between versions and the optimization may perform better on certain machines but not on the others. Also for you information FPC has 4 levels of optimization (0-4):

https://www.freepascal.org/docs-html/prog/progse49.html

i'm still wondering if "with TActor(Actors.Data) do" / or "pActor:=PActor(@Actors.Data);" method is faster..

It's easy you can simply set some benchmark tests as suggested by RayoGlauco.

Thaddy

  • Hero Member
  • *****
  • Posts: 14213
  • Probably until I exterminate Putin.
Re: Lazarus / delphi loop efficiency: continue or begin..end?
« Reply #18 on: March 14, 2018, 12:04:30 pm »
@Handoko
Note that there are two things that are important:
- Continue is a procedure... See the documentation (RTFM) https://www.freepascal.org/docs-html/rtl/system/continue.html
- A simple in-place boolean evaluation is usually faster than a procedure call by definition.

So from an algorithmic point of view the first (one less continue) should be faster, although the compiler can optimize it to be about the same code.
BTW: I have hardly ever seen code where continue could not be rewritten in a better way. It is basically a shortcut for lousy lazy programmers.

And if you are curious: always examine the generated assembler as someone mentioned before. And with different optimizations: that can make a huge difference.
But it starts with a good algorithm.
« Last Edit: March 14, 2018, 12:08:00 pm by Thaddy »
Specialize a type, not a var.

Mr.Madguy

  • Hero Member
  • *****
  • Posts: 844
Re: Lazarus / delphi loop efficiency: continue or begin..end?
« Reply #19 on: March 14, 2018, 06:21:50 pm »
I mean... Why can you just see, what asm code compiler generates?
Code: Pascal  [Select][+][-]
  1. function Test1:Integer;
  2.   var I:Integer;
  3. begin
  4.   Result := 0;
  5.   for I := 0 to 100 do begin
  6.     if Random(100) >= 50 then begin
  7.       if Random(100) >= 50 then begin
  8.         Inc(Result);
  9.       end;
  10.     end;
  11.   end;
  12. end;
  13.  
  14. function Test2:Integer;
  15.   var I:Integer;
  16. begin
  17.   Result := 0;
  18.   for I := 0 to 100 do begin
  19.     if Random(100) < 50 then Continue;
  20.     if Random(100) < 50 then Continue;
  21.     Inc(Result);
  22.   end;
  23. end;  
  24.  
Find 10 differences. Ignore beginning of procedure Test1, as broken debugger starts disassembling from $004253AF, not from $004253B0, as it should.
Is it healthy for project not to have regular stable releases?
Just for fun: Code::Blocks, GCC 13 and DOS - is it possible?

Thaddy

  • Hero Member
  • *****
  • Posts: 14213
  • Probably until I exterminate Putin.
Re: Lazarus / delphi loop efficiency: continue or begin..end?
« Reply #20 on: March 14, 2018, 06:31:10 pm »
well, do like I do and compile from the command line with -a and subsequently examine the .s file(s)

Don't say that that doesn't work, because that is the real assembler code.
Unless you are on a platform that uses the internal assembler  and do not have an external assembler installed: then you might get confused. Trust me: that's the generated (and as such compilable) assembler code. Instruction by instruction. Internal or external.
« Last Edit: March 14, 2018, 06:39:28 pm by Thaddy »
Specialize a type, not a var.

WooBean

  • Full Member
  • ***
  • Posts: 229
Re: Lazarus / delphi loop efficiency: continue or begin..end?
« Reply #21 on: March 14, 2018, 08:12:31 pm »
@Mr.Madguy

I mean... Why can you just see, what asm code compiler generates?
Code: Pascal  [Select][+][-]
  1. function Test1:Integer;
  2.   var I:Integer;
  3. begin
  4.   Result := 0;
  5.   for I := 0 to 100 do begin
  6.     if Random(100) >= 50 then begin
  7.       if Random(100) >= 50 then begin
  8.         Inc(Result);
  9.       end;
  10.     end;
  11.   end;
  12. end;
  13.  
  14. function Test2:Integer;
  15.   var I:Integer;
  16. begin
  17.   Result := 0;
  18.   for I := 0 to 100 do begin
  19.     if Random(100) < 50 then Continue;
  20.     if Random(100) < 50 then Continue;
  21.     Inc(Result);
  22.   end;
  23. end;  
  24.  
Find 10 differences. Ignore beginning of procedure Test1, as broken debugger starts disassembling from $004253AF, not from $004253B0, as it should.
Your pascal code of procedure Test1 and procedure Test2 are exactly equivalent and its compiled by FPC and then disassembled code seems too. Conclusion from code efficiency point of view - there is no difference between presented Test1 and Test2. I guess that using "continue" (or "break") is a C-people habit and may lead to errors when chosen to be used in nested iterations.

@Thaddy

well, do like .....
Nothing understood, OK - my personal limits.
@Handoko
Note that there are two things that are important:
- Continue is a procedure... See the documentation (RTFM) https://www.freepascal.org/docs-html/rtl/system/continue.html
- A simple in-place boolean evaluation is usually faster than a procedure call by definition.

So from an algorithmic point of view the first (one less continue) should be faster, although the compiler can optimize it to be about the same code.
BTW: I have hardly ever seen code where continue could not be rewritten in a better way. It is basically a shortcut for lousy lazy programmers.

And if you are curious: always examine the generated assembler as someone mentioned before. And with different optimizations: that can make a huge difference.
But it starts with a good algorithm.
1. "continue" is not a reserved pascal word, we can declare "procedure continue;" and compile it with no problem (I know - a bad idea but possible);
2. local help to Lazarus 1.8.0 describing "continue" is misleading as it states:
Continue jumps to the end of the current repetitive statement. The code between the Continue call and the end of the repetitive statement is skipped. The condition of the repetitive statement is then checked again.
This can be used with For, repeat and While statements.
Note that while this is a procedure, Continue is a reserved word and hence cannot be redefined.


WooBean
 
« Last Edit: March 14, 2018, 08:33:17 pm by WooBean »
Platforms: Win7/64, Linux Mint Ulyssa/64

Thaddy

  • Hero Member
  • *****
  • Posts: 14213
  • Probably until I exterminate Putin.
Re: Lazarus / delphi loop efficiency: continue or begin..end?
« Reply #22 on: March 14, 2018, 08:43:23 pm »
1. "continue" is not a reserved pascal word, we can declare "procedure continue;" and compile it with no problem (I know - a bad idea but possible);
Well: https://www.freepascal.org/docs-html/rtl/system/continue.html
More specific:
"Note that while this is a procedure, Continue is a reserved word and hence cannot be redefined."

I don't know what you were smoking, but otherwise file a bug report. Seems pretty obvious to me......<slightly grumpy  >:D >:D>
If it CAN be redefined it is a bug.
And it is a bug against documentation...
See:
Code: Pascal  [Select][+][-]
  1. program Project1;
  2. {$ifdef mswindows}{$apptype console}{$endif}
  3. procedure continue;
  4. begin
  5.   writeln('this is not continue');
  6. end;
  7. var
  8.   i:integer;
  9. begin
  10.   for i := 0 to 3 do
  11.     continue;
  12.   readln; // for feedback.
  13. end.

So you were right on that point. I will file the bug report.
[edit]
Done. Issue 0033429 on Mantis.

Well spotted. But it also means you did not read the manuals....... :o :D :D :D

I hope you will forgive me, but that's how my brain works: if I have read it, it won't go away...
« Last Edit: March 14, 2018, 09:13:14 pm by Thaddy »
Specialize a type, not a var.

JernejL

  • Jr. Member
  • **
  • Posts: 92
Re: Lazarus / delphi loop efficiency: continue or begin..end?
« Reply #23 on: March 15, 2018, 08:57:11 am »
Your pascal code of procedure Test1 and procedure Test2 are exactly equivalent and its compiled by FPC and then disassembled code seems too. Conclusion from code efficiency point of view - there is no difference between presented Test1 and Test2. I guess that using "continue" (or "break") is a C-people habit and may lead to errors when chosen to be used in nested iterations.

This is good news and bad news - So it's good that compiler / optimization does its job, but sadly i can't benefit to switching to a specific style to get extra few instructions :)
 
This is what i was wondering the most, thanks for clarifying this.
 

Thaddy

  • Hero Member
  • *****
  • Posts: 14213
  • Probably until I exterminate Putin.
Re: Lazarus / delphi loop efficiency: continue or begin..end?
« Reply #24 on: March 15, 2018, 09:15:15 am »
There are plenty of cases where it matters and the compiler can not find the shortest code path just not in this case.
E.g. at this point in time the compiler is not very good at loop optimizations and not capable of bringing loop variables that do not change inside the loop outside of the loop.
So you still need to optimize the algorithm first. That is always the case. And for any compiler, not just FPC. And you always need to examine the generated assembler to see if it actually matters.
Specialize a type, not a var.

egsuh

  • Hero Member
  • *****
  • Posts: 1273
Re: Lazarus / delphi loop efficiency: continue or begin..end?
« Reply #25 on: March 15, 2018, 01:18:08 pm »
Regarding "continue",  I find "continue" useful when the logic requires many nested if..else structures. For example,

Code: Pascal  [Select][+][-]
  1. if cond1 then
  2. else begin
  3.     //  do something;
  4.     if cond2 then
  5.     else begin
  6.          // do other things;
  7.          if cond3 then
  8.          else begin
  9.               // do something more
  10.               //... and so on.
  11.          end;
  12.     end;
  13.  end;
  14.  
         

I can use "continue" instead of if..else structure as following.

Code: Pascal  [Select][+][-]
  1. if cond1 then Continue;
  2. // do something
  3.  
  4. if cond2 then continue;
  5. // do other things;
  6.  
  7. if cond3 then continue;
  8. // do something more
  9. //... and so on.
  10.  


It's for readability instead of performance.

Thaddy

  • Hero Member
  • *****
  • Posts: 14213
  • Probably until I exterminate Putin.
Re: Lazarus / delphi loop efficiency: continue or begin..end?
« Reply #26 on: March 15, 2018, 01:25:14 pm »
Well, I must have an eyesight problem because such coding style is horrible....
(Anyway Michael fixed the documentation bug)
Specialize a type, not a var.

Paul_

  • Full Member
  • ***
  • Posts: 143
Re: Lazarus / delphi loop efficiency: continue or begin..end?
« Reply #27 on: March 15, 2018, 03:44:18 pm »
@egsuh

Code: Pascal  [Select][+][-]
  1. then else

It makes no sense to me, why you don't use logical operators instead of such unreadable constructions?

Handoko

  • Hero Member
  • *****
  • Posts: 5131
  • My goal: build my own game engine using Lazarus
Re: Lazarus / delphi loop efficiency: continue or begin..end?
« Reply #28 on: March 15, 2018, 04:54:41 pm »
I prefer not(cond), which looks better in my eyes:

Code: Pascal  [Select][+][-]
  1.   if not(cond1) then
  2.   begin
  3.     //  do something;
  4.     if not(cond2) then
  5.     begin
  6.       // do other things;
  7.       if not(cond3) then
  8.       begin
  9.         // do something more
  10.         //... and so on.
  11.       end;
  12.     end;
  13.   end;

Thaddy

  • Hero Member
  • *****
  • Posts: 14213
  • Probably until I exterminate Putin.
Re: Lazarus / delphi loop efficiency: continue or begin..end?
« Reply #29 on: March 15, 2018, 05:46:59 pm »
Yes. And it is probably faster too.
Also note begin/end doesn't generate instructions by itself. That also seems to confuse OP. begin begin begin end end end is the same as begin end
« Last Edit: March 15, 2018, 05:54:40 pm by Thaddy »
Specialize a type, not a var.

 

TinyPortal © 2005-2018