Recent

Author Topic: Assigning Arrays Optimized  (Read 3876 times)

torbente

  • Sr. Member
  • ****
  • Posts: 325
    • Noso Main Page
Assigning Arrays Optimized
« on: July 26, 2018, 07:42:11 pm »
Hi everyone. Are there anyway to optimize this?

Code: Pascal  [Select][+][-]
  1. ArrayOriginal : Array of MyRecordType;
  2. ArrayBackup : Array of MyRecordType;

I want store a copy of the original in the backup before perform some operations with the original one, in case something go wrong, i can restore it (i hope it was clearly explained)

This is how im doing it:

Code: Pascal  [Select][+][-]
  1. SetLength(ArrayBackup,length(ArrayOriginal));
  2. for counter := 0 to length(ArrayOriginal)-1 do
  3.    ArrayBackup[counter] :=  ArrayOriginal[counter];

Thank you.
Noso Cryptocurrency Main Developer
https://github.com/DevTeamNoso/NosoWallet

Xor-el

  • Sr. Member
  • ****
  • Posts: 404
Re: Assigning Arrays Optimized
« Reply #1 on: July 26, 2018, 08:19:01 pm »
Code: Pascal  [Select][+][-]
  1. ArrayBackup := Copy(ArrayOriginal);

ASerge

  • Hero Member
  • *****
  • Posts: 2223
Re: Assigning Arrays Optimized
« Reply #2 on: July 27, 2018, 01:59:12 am »
Code: Pascal  [Select][+][-]
  1. ArrayBackup := Copy(ArrayOriginal);
The main thing is that it improves the source code. Because System.Copy does the same thing. Moreover, because of its universality, it is even slower. Here is an example.
Code: Pascal  [Select][+][-]
  1. program Project1;
  2. {$MODE OBJFPC}
  3. {$APPTYPE CONSOLE}
  4.  
  5. uses SysUtils;
  6.  
  7. type
  8.   TMyRecordType = record
  9.     N: Integer;
  10.     S: string;
  11.   end;
  12.  
  13.   TMyArray = array of TMyRecordType;
  14.  
  15. function MyCopy(const Source: TMyArray): TMyArray;
  16. var
  17.   i: SizeInt;
  18. begin
  19.   SetLength(Result, Length(Source));
  20.   for i := Low(Source) to High(Source) do
  21.     Result[i] := Source[i];
  22. end;
  23.  
  24. const
  25.   CRepeatCount = 100;
  26.   CMaxCount = 100000;
  27.  
  28. procedure TestCopy;
  29. var
  30.   S, D: TMyArray;
  31.   i: Integer;
  32. begin
  33.   SetLength(S, CMaxCount);
  34.   for i := 1 to CRepeatCount do
  35.     D := Copy(S);
  36. end;
  37.  
  38. procedure TestMyCopy;
  39. var
  40.   S, D: TMyArray;
  41.   i: Integer;
  42. begin
  43.   SetLength(S, CMaxCount);
  44.   for i := 1 to CRepeatCount do
  45.     D := MyCopy(S);
  46. end;
  47.  
  48. procedure Measure(const Desc: string; Proc: TProcedure);
  49. var
  50.   StartTime, Elapsed: QWord;
  51. begin
  52.   StartTime := GetTickCount64;
  53.   Proc;
  54.   Elapsed := GetTickCount64 - StartTime;
  55.   Writeln(Desc, ' ', Elapsed);
  56. end;
  57.  
  58. begin
  59.   Measure('Copy', @TestCopy);
  60.   Measure('MyCopy', @TestMyCopy);
  61.   Readln;
  62. end.
Output:
Quote
Copy 1762
MyCopy 515
Copy 1763
MyCopy 499

But in my opinion, code improvement is worth such small losses. So better as say @Xor-el.

Handoko

  • Hero Member
  • *****
  • Posts: 5131
  • My goal: build my own game engine using Lazarus
Re: Assigning Arrays Optimized
« Reply #3 on: July 27, 2018, 03:28:53 am »
How about using Move? On my tests, it seemed faster:

Code: Pascal  [Select][+][-]
  1. procedure TestCopyUsingMove;
  2. var
  3.   S, D: TMyArray;
  4.   i: Integer;
  5. begin
  6.   SetLength(S, CMaxCount);
  7.   for i := 1 to CRepeatCount do begin
  8.     SetLength(D, CMaxCount);
  9.     Move(S[0], D[0], CMaxCount * SizeOf(TMyRecordType));
  10.   end;
  11. end;

Output:
Quote
CopyUsingMove 1152
MyCopy 1835

PascalDragon

  • Hero Member
  • *****
  • Posts: 5446
  • Compiler Developer
Re: Assigning Arrays Optimized
« Reply #4 on: July 27, 2018, 07:36:12 am »
How about using Move? On my tests, it seemed faster:

Code: Pascal  [Select][+][-]
  1. procedure TestCopyUsingMove;
  2. var
  3.   S, D: TMyArray;
  4.   i: Integer;
  5. begin
  6.   SetLength(S, CMaxCount);
  7.   for i := 1 to CRepeatCount do begin
  8.     SetLength(D, CMaxCount);
  9.     Move(S[0], D[0], CMaxCount * SizeOf(TMyRecordType));
  10.   end;
  11. end;

Output:
Quote
CopyUsingMove 1152
MyCopy 1835

This will fail if the array contains managed types as Move() won't care about the reference counts while both the explicit assignment in MyCopy() as well Copy() will.

Xor-el

  • Sr. Member
  • ****
  • Posts: 404
Re: Assigning Arrays Optimized
« Reply #5 on: July 27, 2018, 07:56:33 am »
@ASerge, you are right but another thing, using a loop to simulate copy won't create a true "copy" if the data contained in the array is a reference type, rather it will just change the pointer reference, but the inbuilt "Copy" function will take that into consideration and always create a true "Copy".

@Handoko, using "Move" will break reference counting for managed type so it is not safe.

taazz

  • Hero Member
  • *****
  • Posts: 5368
Re: Assigning Arrays Optimized
« Reply #6 on: July 27, 2018, 11:42:55 am »
@ASerge, you are right but another thing, using a loop to simulate copy won't create a true "copy" if the data contained in the array is a reference type, rather it will just change the pointer reference, but the inbuilt "Copy" function will take that into consideration and always create a true "Copy".
I think not. Both procedure will have the same result.
@Handoko, using "Move" will break reference counting for managed type so it is not safe.
Thats the only difference I can see.
Good judgement is the result of experience … Experience is the result of bad judgement.

OS : Windows 7 64 bit
Laz: Lazarus 1.4.4 FPC 2.6.4 i386-win32-win32/win64

ASerge

  • Hero Member
  • *****
  • Posts: 2223
Re: Assigning Arrays Optimized
« Reply #7 on: July 27, 2018, 03:08:26 pm »
using a loop to simulate copy won't create a true "copy" if the data contained in the array is a reference type, rather it will just change the pointer reference, but the inbuilt "Copy" function will take that into consideration and always create a true "Copy".
That's wrong. The Copy behaves the same as the structure assignment.
Code: Pascal  [Select][+][-]
  1. program Project1;
  2. {$MODE OBJFPC}
  3. {$APPTYPE CONSOLE}
  4. {$LONGSTRINGS ON} // Managed strings
  5.  
  6. type
  7.   TMyRecordType = record
  8.     S: string;
  9.   end;
  10.  
  11.   TMyArray = array of TMyRecordType;
  12.  
  13. function MyCopy(const Source: TMyArray): TMyArray;
  14. var
  15.   i: SizeInt;
  16. begin
  17.   SetLength(Result, Length(Source));
  18.   for i := Low(Source) to High(Source) do
  19.     Result[i] := Source[i];
  20. end;
  21.  
  22. var
  23.   A, D: TMyArray;
  24.   S: string = 'Test';
  25. begin
  26.   UniqueString(S); // Not const str, escape -1 refcount
  27.   Writeln(StringRefCount(S)); // Show 1
  28.   SetLength(A, 1);
  29.   A[0].S := S;
  30.   Writeln(StringRefCount(S)); // Show 2
  31.   D := Copy(A);
  32.   Writeln(StringRefCount(S)); // Show 3
  33.   D := MyCopy(A);
  34.   Writeln(StringRefCount(S)); // Show 3
  35.   Writeln(StringRefCount(D[0].S)); // Show 3
  36.   Readln;
  37. end.

marcov

  • Administrator
  • Hero Member
  • *
  • Posts: 11383
  • FPC developer.
Re: Assigning Arrays Optimized
« Reply #8 on: July 27, 2018, 03:16:55 pm »
Use copy directly, don't loop.

Code: Pascal  [Select][+][-]
  1.     program Project1;
  2.     {$MODE OBJFPC}
  3.     {$APPTYPE CONSOLE}
  4.      
  5.     uses SysUtils;
  6.      
  7.     type
  8.       TMyRecordType = record
  9.         N: Integer;
  10.         S: string;
  11.       end;
  12.      
  13.       TMyArray = array of TMyRecordType;
  14.      
  15.     function MyCopy(const Source: TMyArray): TMyArray;
  16.     var
  17.       i: SizeInt;
  18.     begin
  19.       SetLength(Result, Length(Source));
  20.       for i := Low(Source) to High(Source) do
  21.         Result[i] := Source[i];
  22.     end;
  23.      
  24.     const
  25.       CRepeatCount = 100;
  26.       CMaxCount = 100000;
  27.      
  28.     procedure TestCopy;
  29.     var
  30.       S, D: TMyArray;
  31.       i: Integer;
  32.     begin
  33.       SetLength(S, CMaxCount);
  34.       for i := 1 to CRepeatCount do
  35.         D := Copy(S);
  36.     end;
  37.      
  38.     procedure TestMyCopy;
  39.     var
  40.       S, D: TMyArray;
  41.       i: Integer;
  42.     begin
  43.       SetLength(S, CMaxCount);
  44.       for i := 1 to CRepeatCount do
  45.         D := MyCopy(S);
  46.     end;
  47.  
  48.     procedure TestMycompleteCopy;
  49.     var
  50.       S, D: TMyArray;
  51.       i: Integer;
  52.     begin
  53.       SetLength(S, CMaxCount);
  54.       d:=copy(s);
  55.     end;
  56.      
  57.     procedure Measure(const Desc: string; Proc: TProcedure);
  58.     var
  59.       StartTime, Elapsed: QWord;
  60.     begin
  61.       StartTime := GetTickCount64;
  62.       Proc;
  63.       Elapsed := GetTickCount64 - StartTime;
  64.       Writeln(Desc, ' ', Elapsed);
  65.     end;
  66.      
  67.     begin
  68.       Measure('Copy', @TestCopy);
  69.       Measure('MyCopy', @TestMyCopy);
  70.       Measure('MyCompleteCopy', @TestMycompleteCopy);
  71.       Readln;
  72.     end.
  73.  

Xor-el

  • Sr. Member
  • ****
  • Posts: 404
Re: Assigning Arrays Optimized
« Reply #9 on: July 27, 2018, 04:36:09 pm »
@ASerge and @taazz
you are both right, they both produce the same result. my bad.


engkin

  • Hero Member
  • *****
  • Posts: 3112
Re: Assigning Arrays Optimized
« Reply #10 on: July 27, 2018, 05:25:09 pm »
Use copy directly, don't loop.
That was not looping. It is repeating the test CRepeatCount times.

torbente

  • Sr. Member
  • ****
  • Posts: 325
    • Noso Main Page
Re: Assigning Arrays Optimized
« Reply #11 on: July 28, 2018, 07:55:52 am »
Code: Pascal  [Select][+][-]
  1. ArrayBackup := Copy(ArrayOriginal);

Im using this as it fits perfectly for my needs.

Thanks a lot to you all.
Noso Cryptocurrency Main Developer
https://github.com/DevTeamNoso/NosoWallet

 

TinyPortal © 2005-2018