Recent

Author Topic: How is compared for Lazarus from speed to C programming ?  (Read 5611 times)

threedslider

  • New Member
  • *
  • Posts: 29
How is compared for Lazarus from speed to C programming ?
« on: August 11, 2025, 04:06:08 pm »
Hi,

Lazarus is speed as C programming ? Or more fast than C? Or more less than C?

Thank you.


marcov

  • Administrator
  • Hero Member
  • *
  • Posts: 12863
  • FPC developer.
Re: How is compared for Lazarus from speed to C programming ?
« Reply #1 on: August 11, 2025, 04:44:58 pm »
Depends on the C .

Warfley

  • Hero Member
  • *****
  • Posts: 2061
Re: How is compared for Lazarus from speed to C programming ?
« Reply #2 on: August 11, 2025, 05:47:01 pm »
Generally speaking the mainline C compilers (gcc, clang, msvc) are much better at optimizations than the fpc is.

A very simple example is if we compare the output of clang with -O3 on the following function:
Code: C  [Select][+][-]
  1. unsigned fib(unsigned i) {
  2.     if (i<2) return i;
  3.     return fib(i-2) + fib(i-1);
  4. }
Which results in the following assembly:
Code: ASM  [Select][+][-]
  1. fib:
  2.         push    rbp
  3.         push    rbx
  4.         push    rax
  5.         mov     ebx, edi
  6.         xor     ebp, ebp
  7.         cmp     edi, 2
  8.         jb      .LBB0_4
  9.         inc     ebx
  10.         xor     ebp, ebp
  11. .LBB0_2:
  12.         lea     edi, [rbx - 3]
  13.         call    fib
  14.         add     ebp, eax
  15.         dec     ebx
  16.         cmp     ebx, 2
  17.         ja      .LBB0_2
  18.         mov     ebx, 1
  19. .LBB0_4:
  20.         add     ebp, ebx
  21.         mov     eax, ebp
  22.         add     rsp, 8
  23.         pop     rbx
  24.         pop     rbp
  25.         ret

With the same function in Pascal:
Code: Pascal  [Select][+][-]
  1. function fib(i: SizeUInt): SizeUInt;
  2. begin
  3.   if i<2 then Exit(i);
  4.   Result:=fib(i-2)+fib(i-1);
  5. end;
Also compiled on -O3 resulting in:
Code: ASM  [Select][+][-]
  1. fib(qword):
  2.         pushq   %rbx
  3.         pushq   %r12
  4.         pushq   %r13
  5.         movq    %rdi,%rbx
  6.         cmpq    $2,%rbx
  7.         jnb     .Lj6
  8.         movq    %rbx,%r12
  9.         jmp     .Lj3
  10. .Lj6:
  11.         leaq    -2(%rbx),%rdi
  12.         call    fib(qword)
  13.         movq    %rax,%r13
  14.         leaq    -1(%rbx),%rdi
  15.         call    fib(qword)
  16.         leaq    (%rax,%r13),%r12
  17. .Lj3:
  18.         movq    %r12,%rax
  19.         popq    %r13
  20.         popq    %r12
  21.         popq    %rbx
  22.         ret
While clang does a lot of smaller optimizations, the most obvious is that clang resolved the tail recursion, compared to the fpc code that kept both recursive calls.

Additionally C as a language is simpler with less features and requires less runtime code to execute, while pascal has some higher level language concepts where the compiler does more stuff in the background. This means C code is often simpler doing less stuff (but also being less flexible and more error prone), but because it's simpler it's also faster and better optimizable.

But on the other hand, some things are harder in C, so for example making dynamic arrays in C is kinda annoying, so most C developers resort to linked lists, which are generally slower than array based lists, so you can have a program written in C where the compiler does much more optimization, but the program in the end will still be slower than a comparable pascal program because in Pascal you'd use an array list where in C you'd use a linked list

marcov

  • Administrator
  • Hero Member
  • *
  • Posts: 12863
  • FPC developer.
Re: How is compared for Lazarus from speed to C programming ?
« Reply #3 on: August 11, 2025, 08:01:28 pm »
Also such compiler benchmarks are often math problems in a single source file, which might not actually not be what you would typically do in an application.

Things like cross-unit inlining are for many applications much more important.

domasz

  • Hero Member
  • *****
  • Posts: 629
Re: How is compared for Lazarus from speed to C programming ?
« Reply #4 on: August 11, 2025, 09:01:43 pm »
Lazarus (FPC) is faster than most languages. Not necessarily C or C++ but faster than all those popular ones: PHP, Python, JavaScript, Java.

Warfley

  • Hero Member
  • *****
  • Posts: 2061
Re: How is compared for Lazarus from speed to C programming ?
« Reply #5 on: August 11, 2025, 10:46:47 pm »
Lazarus (FPC) is faster than most languages. Not necessarily C or C++ but faster than all those popular ones: PHP, Python, JavaScript, Java.
Thats not necessarily true, I guess you base that on the idea that pascal is natively compiled while these others are interpreted/emulated? But thats not really true, first these languages use JIT compilation, so code that is run frequently is as much compiled to machine code as your pascal code is, often with better optimization because it's based on observed behavior. Second those languages use different architectures with different design decisions that make certain things faster and others slower. Take the following two equivalent programs, one in Java:
Code: Java  [Select][+][-]
  1. public class Main {
  2.  
  3.     private final int adder;
  4.  
  5.     Main(int a) {
  6.         adder = a;
  7.     }
  8.  
  9.     int add(int i) {
  10.         return i+adder;
  11.     }
  12.  
  13.     public static void main(String args[]) {
  14.         long startTime = System.currentTimeMillis();
  15.         int accum = 0;
  16.         for (long i=0;i<1000000000l; ++i) {
  17.             Main m = new Main((int)i);
  18.             accum=m.add(accum);
  19.         }
  20.         long endTime = System.currentTimeMillis();
  21.         System.out.println("Total execution time: " + (endTime-startTime) + "ms");
  22.     }
  23. }
  24.  
And one in Pascal:
Code: Pascal  [Select][+][-]
  1. program Project1;
  2.  
  3. {$mode objfpc}{$H+}
  4. uses SysUtils;
  5.  
  6. type
  7.   TTest = class
  8.   private
  9.     adder: Integer;
  10.   public
  11.     function Add(i: Integer): Integer;
  12.     constructor Create(a: Integer);
  13.   end;
  14.  
  15. function TTest.Add(i: Integer): Integer;
  16. begin
  17.   Result:=i+adder;
  18. end;
  19.  
  20. constructor TTest.Create(a: Integer);
  21. begin
  22.   adder:=a;
  23. end;
  24.  
  25. var
  26.   i: Int64;
  27.   accum: Integer;
  28.   start: QWord;
  29.   t: TTest;
  30. begin
  31.   start:=GetTickCount64;
  32.   accum:=0;
  33.   i:=0;
  34.   while i<1000000000 do
  35.   begin
  36.     t:=TTest.Create(Integer(i));
  37.     accum:=t.Add(accum);
  38.     t.Free;
  39.     Inc(i);
  40.   end;
  41.   WriteLn('Total execution time: ', GetTickCount64-start, 'ms');
  42.   ReadLn;
  43. end.
  44.  
Let's run them:
Code: Text  [Select][+][-]
  1. Java:         Total execution time: 200ms
  2. Pascal (-O3): Total execution time: 22657ms
So java is around a factor 100 faster.

The reason for that is the garbage collector. Java uses a generational mark and sweep garbage collection, so (VERY OVERSIMPLIFIED) when a new object is created it is just pushed on a stack, which is just a single pointer operation (add stackptr, sizeof(object)). Then the function is called on that object and the object is left alone. When the stack is full, the garbage collector will jump in and do a quick reachability analysis, which in the example above is trivial because they all were local variables. The garbage collector will move all the objects that are still reachable to the next generation stack, which in this example are none, and then clear the gen1 stack, which also is just a single operation (set stackptr, 0).
So for each iteration there is one add and after a certain number of iterations there will be a single reset. Thats really fast.

Take the pascal code on the other hand. With each allocation the memory manager is called, which performs some rather complex allocation lookup. It's not like crazy much effort, but it's certainly orders of magnitude more operations than 1. Then the instantiation code needs to be executed (See TObject.InitInstace) which besides this function also contains a few virtual function calls with need to chase pointers, potentialy have cache invalidation and all that fun stuff.
After the method is called on the object, it is freed, which contains a call to the destructor, then the deinitalization code (see TObject.CleanupInstance) before calling the memory manager again.

When it comes to creating a lot of small objects Java is much faster than Pascal, if we assume that in this very simple example above the JIT kicks in reasonably early, so the code executed is natively compiled as the FPC code, we can see that initiating and freeing a class in Pascal is roughly 100 times slower than it is in Java.

Does this mean Java is in general faster than Pascal? Well it highly depends on the code you write, as I wrote above with the example of linked lists in C, if you create a bunch of throwaway classes in Pascal it's gonna be slow, not because the compiler is slow, but because your code is slow.
A disadvantage to this is btw that Idiomatic Pascal code often involves creating temporary objects. If we look for example at the EncodeStringBase64 function in the base64 unit:
Code: Pascal  [Select][+][-]
  1. function EncodeStringBase64(const s:string):String;
  2.  
  3. var
  4.   Outstream : TStringStream;
  5.   Encoder   : TBase64EncodingStream;
  6. begin
  7.   if Length(s)=0 then
  8.     Exit('');
  9.   Outstream:=TStringStream.Create('');
  10.   try
  11.     Encoder:=TBase64EncodingStream.create(outstream);
  12.     try
  13.       Encoder.Write(s[1],Length(s));
  14.     finally
  15.       Encoder.Free;
  16.       end;
  17.     Result:=Outstream.DataString;
  18.   finally
  19.     Outstream.free;
  20.     end;
  21. end;
You can see that it creates two temporary objects just to immediately throw them away. So if you call this function in an inner loop, it's gonna be really slow. Meanwhile if you'd do the same in Java it would be blazingly fast.

Lastly, I made a tiny adjustment to the pascal code:
Code: Pascal  [Select][+][-]
  1. program Project1;
  2.  
  3. {$mode objfpc}{$H+}
  4. {$ModeSwitch advancedrecords}
  5. uses SysUtils;
  6.  
  7. type
  8.   TTest = record
  9.     {...}
  10.     function Add(i: Integer): Integer;inline;
  11.     class function Create(a: Integer):TTest;static;inline;
  12.   end;
  13.  
  14. {...}
  15. class function TTest.Create(a: Integer): TTest;
  16. begin
  17.   Result.adder:=a;
  18. end;
  19.  
  20. {...}
  21.     t:=TTest.Create(Integer(i));
  22.     accum:=t.Add(accum);
  23.     //t.free <-- not needed anymore
  24.     Inc(i);
  25. {...}
  26.  
I get:
Code: Text  [Select][+][-]
  1. Total execution time: 359ms
Which is nearly as fast as Java. By changing the class to a record, most of that overhead is now gone. Additionally I made both functions inline because the JIT compiler of Java does this as an optimization as well, so it's just fair if we want to compare those two. It's still not as fast as Java which is simply because Javas JIT compiler is crazy good, like seriously on repetetive tasks it usually produces much more optimized assembly than even most current C compilers, let alone the FPC.

So yeah, Java can easily be faster than FPC

marcov

  • Administrator
  • Hero Member
  • *
  • Posts: 12863
  • FPC developer.
Re: How is compared for Lazarus from speed to C programming ?
« Reply #6 on: August 11, 2025, 11:00:40 pm »
Thats not necessarily true, I guess you base that on the idea that pascal is natively compiled while these others are interpreted/emulated? But thats not really true, first these languages use JIT compilation, so code that is run frequently is as much compiled to machine code as your pascal code is, often with better optimization because it's based on observed behavior.

That is not my experience.  Yes, JITted code can come close and even exceed statically compiled code, specially with crafted benchmark code, but on average in programs that really do something, it doesn't.

It is very hard to measure though, since usually it is not the way of code that is dragging those languages down, but the automatic memory management.


Warfley

  • Hero Member
  • *****
  • Posts: 2061
Re: How is compared for Lazarus from speed to C programming ?
« Reply #7 on: August 11, 2025, 11:08:06 pm »
It is very hard to measure though, since usually it is not the way of code that is dragging those languages down, but the automatic memory management.
It is also very hard to measure because JIT tends to favor simple code thats used for benchmarks, which is why for the example above I even just assumed that the code will be basically as fast if not faster than FPC generated native code, because it is so simple.

Also something from this experiment, when I was using int instead of long for the computation, the jit optimizer just threw the whole loop out of the window making it run in like 3ms independently of the number of iterations because without the cast from int to long which involves runtime overflow handling, it just analythically solves the problem putting this whole example ad absurdum.
So getting an example that fairly compares just the overhead of creating and freeing objects was actually much harder than one might think. So my point that it's really hard to make statements like "x is faster than y" is really really difficult because theres so much coming together when it comes to how those fare in the field.

marcov

  • Administrator
  • Hero Member
  • *
  • Posts: 12863
  • FPC developer.
Re: How is compared for Lazarus from speed to C programming ?
« Reply #8 on: August 11, 2025, 11:40:55 pm »
It is very hard to measure though, since usually it is not the way of code that is dragging those languages down, but the automatic memory management.
It is also very hard to measure because JIT tends to favor simple code thats used for benchmarks, which is why for the example above I even just assumed that the code will be basically as fast if not faster than FPC generated native code, because it is so simple.

It probably will, but such border conditions (oversimplified, crafted code, dynamic memory use can be optimised away due to fairly basic locality ) need to be annotated with your statements about JIT. Somebody might assume that it is a general rule otherwise.

For non trivial usage, personally I'm more interested in Java/C#'s lower threshold to optimise over source file borders. Fairly linear call chains could be integrated and optimised, also in code that does something. 

Quote
So my point that it's really hard to make statements like "x is faster than y" is really really difficult because theres so much coming together when it comes to how those fare in the field.

It is difficult. But in my experience in average code, C#/Java don't generally break even, even less so in threaded applications. Startup benchmarks are often atrocious. But that all is more the memory management related than the way of compilation.

d2010

  • Sr. Member
  • ****
  • Posts: 264
Re: How is compared for Lazarus from speed to C programming ?
« Reply #9 on: August 12, 2025, 12:14:07 am »
The speed of program.exe.,is  cross-linked with the Budget of developers.
For low-cost (and mid costs) of program.exe, the Lazarus speed is more-better C++
++more stability for long terms (after the years ) of programe.lpr.exe.
 :-*
--but for high price of program.exe in C++*.cpp *.c, *.h , the Speed VC++ is more better than Lazarus., work very good of speed , but the price ? ::)?
 :-\
« Last Edit: August 12, 2025, 12:16:46 am by d2010 »

Fred vS

  • Hero Member
  • *****
  • Posts: 3923
    • StrumPract is the musicians best friend
Re: How is compared for Lazarus from speed to C programming ?
« Reply #10 on: August 12, 2025, 01:38:29 am »
It also depends on the memory manager. For example, for fpc, with the mORMot2 memory manager, I get x6 speed for accessing data in multithreaded applications.
I use Lazarus 2.2.0 32/64 and FPC 3.2.2 32/64 on Debian 11 64 bit, Windows 10, Windows 7 32/64, Windows XP 32,  FreeBSD 64.
Widgetset: fpGUI, MSEgui, Win32, GTK2, Qt.

https://github.com/fredvs
https://gitlab.com/fredvs
https://codeberg.org/fredvs

ALLIGATOR

  • Sr. Member
  • ****
  • Posts: 417
  • I use FPC [main] 💪🐯💪
Re: How is compared for Lazarus from speed to C programming ?
« Reply #11 on: August 12, 2025, 04:46:19 am »
...with the mORMot2 memory manager, I get x6 speed...

Oh, that's very interesting!
Have you tried the new versions of FPC? Rika has reworked the memory manager in them, and it seems that it is now better than or on par with mORMot2, but if you could test it on your application, it would be very interesting to see the results.
« Last Edit: March 01, 2026, 02:04:36 pm by ALLIGATOR »
I may seem rude - please don't take it personally

ALLIGATOR

  • Sr. Member
  • ****
  • Posts: 417
  • I use FPC [main] 💪🐯💪
Re: How is compared for Lazarus from speed to C programming ?
« Reply #12 on: August 12, 2025, 04:49:58 am »
The argument in favor of FPC - is compilation speed

And optimization is gradually improving the situation. In any case, there is still the LLVM backend, and I hope that it will eventually allow compilation for Windows as well
I may seem rude - please don't take it personally

domasz

  • Hero Member
  • *****
  • Posts: 629
Re: How is compared for Lazarus from speed to C programming ?
« Reply #13 on: August 12, 2025, 06:37:00 am »
Thats not necessarily true, I guess you base that on the idea that pascal is natively compiled while these others are interpreted/emulated? But thats not really true, first these languages use JIT compilation, so code that is run frequently is as much compiled to machine code
Okay but now let's add startup time. When I want a program to, for example, convert an image to grayscale I want that program to run once, not a milion times. So I am, as a user, interested in how much will it take from the moment I started the program to the moment it closes. In case of a compiled .EXE the startup is super fast while all those interpreters need to first load themselves, then compile a script to JIT.

ALLIGATOR

  • Sr. Member
  • ****
  • Posts: 417
  • I use FPC [main] 💪🐯💪
Re: How is compared for Lazarus from speed to C programming ?
« Reply #14 on: August 12, 2025, 06:50:04 am »
Okay but now let's add startup time.

As far as I know, there is GraalVM, which allows you to compile Java bytecode into native code. And the startup time will be minimal, just like with regular native applications.
But I haven't worked with this technology, just information, judging by the website - it looks pretty serious, i.e. it's not some kind of amateurish hack.
I may seem rude - please don't take it personally

 

TinyPortal © 2005-2018