Recent

Author Topic: [SOLVED]Improvement of packages/fcl-image/src/fpcanvas.inc TFPCustomCanvas.Erase  (Read 1192 times)

lagprogramming

  • Sr. Member
  • ****
  • Posts: 405
packages/fcl-image/src/fpcanvas.inc contains the following procedure:
Code: Pascal  [Select][+][-]
  1. procedure TFPCustomCanvas.Erase;
  2. var
  3.   x,y:Integer;
  4. begin
  5.   for x:=0 to Width-1 do
  6.     for y:=0 to Height-1 do
  7.       Colors[x,y]:=colTransparent;
  8. end;
  9.  
The following procedure should be faster. I've switched the for loops.
Code: Pascal  [Select][+][-]
  1. procedure TFPCustomCanvas.Erase;
  2. var
  3.   x,y:Integer;
  4. begin
  5.   for y:=0 to Height-1 do
  6.     for x:=0 to Width-1 do
  7.       Colors[x,y]:=colTransparent;
  8. end;
« Last Edit: April 11, 2023, 11:55:37 am by lagprogramming »

Чебурашка

  • Hero Member
  • *****
  • Posts: 568
  • СЛАВА УКРАЇНІ! / Slava Ukraïni!
packages/fcl-image/src/fpcanvas.inc contains the following procedure:
Code: Pascal  [Select][+][-]
  1. procedure TFPCustomCanvas.Erase;
  2. var
  3.   x,y:Integer;
  4. begin
  5.   for x:=0 to Width-1 do
  6.     for y:=0 to Height-1 do
  7.       Colors[x,y]:=colTransparent;
  8. end;
  9.  
The following procedure should be faster. I've switched the for loops.
Code: Pascal  [Select][+][-]
  1. procedure TFPCustomCanvas.Erase;
  2. var
  3.   x,y:Integer;
  4. begin
  5.   for y:=0 to Height-1 do
  6.     for x:=0 to Width-1 do
  7.       Colors[x,y]:=colTransparent;
  8. end;

I am curious to know what is the difference in terms of execution time, could you please explain/demonstrate?
FPC 3.2.0/Lazarus 2.0.10+dfsg-4+b2 on Debian 11.5
FPC 3.2.2/Lazarus 2.2.0 on Windows 10 Pro 21H2

lagprogramming

  • Sr. Member
  • ****
  • Posts: 405
I am curious to know what is the difference in terms of execution time, could you please explain/demonstrate?

It's a matter of CPU cache usage.
Original code "erases"(which in fact consists in writing data) all the lines(rows) of the canvas simultaneously. This means that the CPU will try to simultaneously cache writes for many lines, no more than the height of the canvas.
New CPUs have huge caches and good mechanisms of managing it, but old CPUs are not that good. Those old CPUs will run the proposed code faster than the original code because the data writes are leaner, more fluent.
Also, there are CPUs that write data forward significantly faster than writing it backward. This is another example of CPU cache usage.

Чебурашка

  • Hero Member
  • *****
  • Posts: 568
  • СЛАВА УКРАЇНІ! / Slava Ukraïni!
I am curious to know what is the difference in terms of execution time, could you please explain/demonstrate?

It's a matter of CPU cache usage.
Original code "erases"(which in fact consists in writing data) all the lines(rows) of the canvas simultaneously. This means that the CPU will try to simultaneously cache writes for many lines, no more than the height of the canvas.
New CPUs have huge caches and good mechanisms of managing it, but old CPUs are not that good. Those old CPUs will run the proposed code faster than the original code because the data writes are leaner, more fluent.
Also, there are CPUs that write data forward significantly faster than writing it backward. This is another example of CPU cache usage.

Very interesting, thank you.
FPC 3.2.0/Lazarus 2.0.10+dfsg-4+b2 on Debian 11.5
FPC 3.2.2/Lazarus 2.2.0 on Windows 10 Pro 21H2

wp

  • Hero Member
  • *****
  • Posts: 11857
Here's a test project which measures the execution time for both methods. There's a 40% speed gain when y is in the outer loop (taking the case of x in the outer loop as a reference). Tested on a 10,000 x 10,000 pixel image.
Code: Pascal  [Select][+][-]
  1. program project1;
  2.  
  3. uses
  4.   SysUtils, fpImage, fpCanvas, fpImgCanv;
  5.  
  6. const
  7.   WIDTH = 10*1000;
  8.   HEIGHT = 10*1000;
  9. var
  10.   t: TDateTime;
  11.   img: TFPCustomImage;
  12.   cnv: TFPCustomCanvas;
  13.   i, x, y: Integer;
  14. begin
  15.   for i := 1 to 5 do
  16.   begin
  17.     WriteLn('Run #', i);
  18.     img := TFPMemoryImage.Create(WIDTH, HEIGHT);
  19.     try
  20.       cnv := TFPImageCanvas.Create(img);
  21.       try
  22.         Write('  outer loop x...: ');
  23.         t := Now;
  24.         for x:=0 to img.Width-1 do
  25.           for y:=0 to img.Height-1 do
  26.             cnv.Colors[x,y] := colTransparent;
  27.         t := Now-t;
  28.         WriteLn(FormatDateTime('s.zzz" seconds"', t));
  29.  
  30.         Write('  outer loop y...: ');
  31.         t := Now;
  32.         for y:=0 to img.Height-1 do
  33.           for x:=0 to img.Width-1 do
  34.             cnv.Colors[x,y] := colTransparent;
  35.         t := Now-t;
  36.         WriteLn(FormatDateTime('s.zzz" seconds"', t));
  37.       finally
  38.         cnv.Free;
  39.       end;
  40.     finally
  41.       img.Free;
  42.     end;
  43.     WriteLn;
  44.   end;
  45.  
  46.   Write('Done. Press ENTER to quit...');
  47.   ReadLn;
  48. end.

Post a patch to the FPC bug tracker, I doubt whether the developers taking care of graphics read this here.


marcov

  • Administrator
  • Hero Member
  • *
  • Posts: 11383
  • FPC developer.
Post a patch to the FPC bug tracker, I doubt whether the developers taking care of graphics read this here.

I work with image formats in my daily job, but I don't use fcl-image.

Anyway, committed. I'm somewhat surprised it still has effect, since afaik the fcl-image colors[] is quite slow with a lot of shifting for various formats.

 

TinyPortal © 2005-2018