Thread View: borland.public.delphi.basm
26 messages
26 total messages
Started by Dennis
Wed, 18 Sep 2002 07:51
Move Optimization
Author: Dennis
Date: Wed, 18 Sep 2002 07:51
Date: Wed, 18 Sep 2002 07:51
15 lines
1405 bytes
1405 bytes
Hi Proposal for benchmark rules Memory chunks of many different sizes must be part of the benchmark. Ranging from a few bytes to some M bytes. The benchmark must run on cached memory as well as uncached. Memory chunks must be aligned as well as unaligned (but no worse than what we get from the memory manager). Sub benchmarks are run under the described conditions and their values are summed up to give the final benchmark. Sub benchmarks must attribute evenly in the final benchmark. Dennis
Re: Move Optimization
Author: Eric Grange
Date: Wed, 18 Sep 2002 08:33
Date: Wed, 18 Sep 2002 08:33
11 lines
1516 bytes
1516 bytes
> (but no worse than what we get from the memory manager). I wouldn't use that restriction, Move can be used in string functions, with char alignment, and thus a higher probability of having at least one unaligned block of memory rather than an aligned block (f.i. in Concat, Copy, Insert and Delete...). (when transfering large blocks, the cost of handling the unaligned bytes separately is negligible, and for small blocks, it may help you save the setup costs of a 'rep movsd' or MMX transfer). Eric
Re: Move Optimization
Author: Dennis
Date: Wed, 18 Sep 2002 10:55
Date: Wed, 18 Sep 2002 10:55
20 lines
1654 bytes
1654 bytes
Hi Eric Then we should measure at blocks with these alignments: none, 4byte, 8 byte, 16byte, 32byte? Dennis Eric Grange wrote: > > (but no worse than what we get from the memory manager). > > I wouldn't use that restriction, Move can be used in string > functions, with char alignment, and thus a higher probability > of having at least one unaligned block of memory rather than an > aligned block (f.i. in Concat, Copy, Insert and Delete...). > (when transfering large blocks, the cost of handling the unaligned > bytes separately is negligible, and for small blocks, it may help > you save the setup costs of a 'rep movsd' or MMX transfer). > > Eric
Re: Move Optimization
Author: Hagen Reddmann
Date: Wed, 18 Sep 2002 16:55
Date: Wed, 18 Sep 2002 16:55
15 lines
1460 bytes
1460 bytes
Better 1,2,3,4 thats the most probable cases. Better we don't use any restrictions because Delphis move() have no restrictions, and any replacement schoud'nt have it. Hagen "Dennis" <marianndennis@email.dk> schrieb im Newsbeitrag news:3D885BB8.33FB9B50@email.dk... > Hi Eric > > Then we should measure at blocks with these alignments: none, 4byte, 8 > byte, 16byte, 32byte? > > Dennis >
Re: Move Optimization
Author: Robert Lee
Date: Wed, 18 Sep 2002 22:11
Date: Wed, 18 Sep 2002 22:11
13 lines
1543 bytes
1543 bytes
Hagen Reddmann wrote: > Better 1,2,3,4 thats the most probable cases. Better we don't use any > restrictions because Delphis move() have no restrictions, and any > replacement schoud'nt have it. I agree, it has to cover all possible cases (including the dreaded overlap case). The key for big moves is to split off the unaligned ends to do separately. Plus you really want to streamline the path for small moves. -- Bob Lee High Performance Delphi - http://www.optimalcode.com/
Re: Move Optimization
Author: John O'Harrow
Date: Wed, 18 Sep 2002 23:14
Date: Wed, 18 Sep 2002 23:14
25 lines
1986 bytes
1986 bytes
A useful starting point for an optimised move procedure might be my Pentium and Athlon move procedures as listed in the thread "MMX functions". These optimised procedures work with any data size and use prefetching and MMX, but do not yet allow overlapping blocks. John O'Harrow "Robert Lee" <rhlee@optimalcode.com> wrote in message news:3D88FA1D.153D60A1@optimalcode.com... > Hagen Reddmann wrote: > > > Better 1,2,3,4 thats the most probable cases. Better we don't use any > > restrictions because Delphis move() have no restrictions, and any > > replacement schoud'nt have it. > > I agree, it has to cover all possible cases (including the dreaded overlap > case). The key for big moves is to split off the unaligned ends to do > separately. Plus you really want to streamline the path for small moves. > > -- > Bob Lee > High Performance Delphi - http://www.optimalcode.com/ > >
Re: Move Optimization
Author: Dennis
Date: Thu, 19 Sep 2002 07:38
Date: Thu, 19 Sep 2002 07:38
32 lines
2097 bytes
2097 bytes
Hi John Yes. Throw them in here as your suggestions. Dennis John O'Harrow wrote: > A useful starting point for an optimised move procedure might be my Pentium > and Athlon move procedures as listed in the thread "MMX functions". These > optimised procedures work with any data size and use prefetching and MMX, > but do not yet allow overlapping blocks. > > John O'Harrow > > "Robert Lee" <rhlee@optimalcode.com> wrote in message > news:3D88FA1D.153D60A1@optimalcode.com... > > Hagen Reddmann wrote: > > > > > Better 1,2,3,4 thats the most probable cases. Better we don't use any > > > restrictions because Delphis move() have no restrictions, and any > > > replacement schoud'nt have it. > > > > I agree, it has to cover all possible cases (including the dreaded overlap > > case). The key for big moves is to split off the unaligned ends to do > > separately. Plus you really want to streamline the path for small moves. > > > > -- > > Bob Lee > > High Performance Delphi - http://www.optimalcode.com/ > > > >
Re: Move Optimization
Author: Dennis
Date: Thu, 19 Sep 2002 07:42
Date: Thu, 19 Sep 2002 07:42
28 lines
1871 bytes
1871 bytes
Hi We can make it a rule that the one proposing a function writes the benchmark code. Respecting all votes and proposals of course. I write the code for the move benchmark, but i would like you all to paste some code that exemplifies your proposal for rules. This will help me getting started and make the benchmark more varied and realistic. Dennis Dennis wrote: > Hi > > Proposal for benchmark rules > > Memory chunks of many different sizes must be part of the benchmark. > Ranging from a few bytes to some M bytes. > The benchmark must run on cached memory as well as uncached. > Memory chunks must be aligned as well as unaligned (but no worse than > what we get from the memory manager). > > Sub benchmarks are run under the described conditions and their values > are summed up to give the final benchmark. Sub benchmarks must attribute > evenly in the final benchmark. > > Dennis
Re: Move Optimization
Author: Dennis
Date: Thu, 19 Sep 2002 07:55
Date: Thu, 19 Sep 2002 07:55
22 lines
1733 bytes
1733 bytes
Hi We also need to agree on some test that the optimized function need to pass to be part of the competition/project. In case of move it is easy to write some code that initializes two arrays with different data, copies one to the other and verify they are identical. How do we test that it properly handles overlapped destination and source? Should we make a test for; static arrays, dynamic arrays, strings, PChars etc? Is it OK that the move function reads out of the source start/end? If the standard move does not I vote no. Writing out of bounds is not allowed? Should we explicitly test that ebx, edi & esi registers are preserved? Any other proposals for test cases? It will make me happy if you supply code for proposed testcases :-) Dennis
Re: Move Optimization
Author: Eric Grange
Date: Thu, 19 Sep 2002 08:05
Date: Thu, 19 Sep 2002 08:05
28 lines
2349 bytes
2349 bytes
> Should we make a test for; static arrays, dynamic arrays, strings, PChars > etc? PChars or binary memory should be enough (you can cover all the cases easily with them, it's just a matter of allocating a big buffer and positionning pointers inside it). > Is it OK that the move function reads out of the source start/end? If the > standard move does not I vote no. > Writing out of bounds is not allowed? I say no for both, because the bytes you may read/write may stand in protected memory of some kind (there is a recent thread in the NG on a similar problem affecting Boolean assignment, the one with mov vs mozx vs movsx). > Should we explicitly test that ebx, edi & esi registers are preserved? I say yes, though not preserving them will probably crash the test proggy on short notice anyway. There should also be some FPU code to make sure no EMMS/FEMMS has been forgotten if MMX is used (the FPU code will fail if EMMS has been forgotten). There is also the problem of cache-related instruction (movntq, prefetch...) which can give a boost to Move in some benchmark situations, but kill performance in real-world cases (movntq and similar instructions can be particularly dangerous from that point of view in my experience). Eric
Re: Move Optimization
Author: Dennis
Date: Thu, 19 Sep 2002 18:15
Date: Thu, 19 Sep 2002 18:15
117 lines
5247 bytes
5247 bytes
Hi
This is the first proposal for benchmark code. All suggestions for
modifications are welcome.
Missing is control over data alignment and control over caching.
These array sizes are "moved";
//8;11;15;20;27;36;49;66;89;120;162;219;296;400;540;729;984;1328;1793;2421;3268;4412;5956;8041;10855;14654;19783;26707;36054;48673;65709;88707;119754;161668;218252;294640;397764;536981;724924;978647;1321173;1783584;
The average copy speed in MB/s is the benchmark.
There is no cache flush between runs.
There is no code for data alignment.
procedure TMainForm.RunButtonClick(Sender: TObject);
var
SourceArray : array[0..1999999] of Byte;
DestinationArray : array[0..1999999] of Byte;
I, K, Kmax, RunNo : Cardinal;
NoOfBytesPerSec, NoOfMBytesPerSec, NoOfMBytesPerSecTotal,
NoOfMBytesPerSecMax,
NoOfMBytesPerSecMin : Int64;
NoOfBytesFP, RunTimeSec : Extended;
ArraySize, NoOfBytes : Int64;
X, Y : Pointer;
lpFrequency, lpPerformanceCount, StartCount, EndCount,
NoOfTicks : TLargeInteger;
Succes : Boolean;
const
ARRAYGROWFACTOR : Double = 1.35;
ARRAYSIZESTART : Cardinal = 8;
RUNNOMAX : Cardinal = 20000000; //Must be bigger than Arraysize or some
bick blocks will not be run
begin
StatusBar1.SimpleText := 'Running';
SummedNoOfMBytesPerSecEdit.Text := '';
SummedArraySizeEdit.Text := '';
NoOfMBytesPerSecMaxEdit.Text := '';
X := @SourceArray;
Y := @DestinationArray;
AddressSourceEdit.Text := IntToHex(Integer(X), 8);
AddressDestEdit.Text := IntToHex(Integer(Y), 8);
ProgressBar1.Max := 42;
ArraySize := ARRAYSIZESTART;
NoOfMBytesPerSecTotal := 0;
NoOfMBytesPerSecMax := 0;
NoOfMBytesPerSecMin := 99999999;
//Initialize arrays
for I := 0 to 1999999 do
begin
SourceArray[I] := 255;
DestinationArray[I] := 1;
end;
Succes := QueryPerformanceFrequency(lpFrequency);
if not Succes then
raise Exception.Create('QueryPerformanceFrequency failed');
RunNo := 1;
while (ArraySize < 1999999) do
begin
SummedArraySizeEdit.Text := SummedArraySizeEdit.Text +
IntToStr(ArraySize) + ';';
if ArraySize > Length(DestinationArray) then
raise Exception.Create('ArraySize to big');
ArraySizeLabeledEdit.Text := IntToStr(ArraySize);
Update;
Kmax := Round(RUNNOMAX / ArraySize);//Adjust Kmax because more runs are
needed on small blocks than on big blocks
Succes := QueryPerformanceCounter(lpPerformanceCount);
if Succes then
StartCount := lpPerformanceCount
else
raise Exception.Create('QueryPerformanceCounter failed');
for K := 1 to Kmax do
begin
//Functions to benchmark
Move(SourceArray, DestinationArray, ArraySize);
end;
Succes := QueryPerformanceCounter(lpPerformanceCount);
if Succes then
EndCount := lpPerformanceCount
else
raise Exception.Create('QueryPerformanceCounter failed');
NoOfTicks := EndCount - StartCount;
RunTimeSec := NoOfTicks / lpFrequency;
RunTimeEdit.Text := FloatToStrF(RunTimeSec, ffFixed, 9, 1);
NoOfBytes := ArraySize * Kmax;
NoOfBytesFP := NoOfBytes;
if RunTimeSec <> 0 then
NoOfBytesPerSec := Round(NoOfBytesFP / RunTimeSec)
else
NoOfBytesPerSec := 0;
NoOfMBytesPerSec := Round(NoOfBytesPerSec / 1024 / 1024);
NoOfMBytesPerSecEdit.Text := IntToStr(NoOfMBytesPerSec);
NoOfMBytesPerSecTotal := NoOfMBytesPerSecTotal + NoOfMBytesPerSec;
NoOfMBytesPerSecTotalEdit.Text := IntToStr(NoOfMBytesPerSecTotal);
NoOfMBytesPerSecAverageEdit.Text := FloatToStrF(NoOfMBytesPerSecTotal /
RunNo, ffFixed, 9, 0);
if NoOfMBytesPerSec < NoOfMBytesPerSecMin then
NoOfMBytesPerSecMin := NoOfMBytesPerSec;
NoOfMBytesPerSecMinEdit.Text := IntToStr(NoOfMBytesPerSecMin);
if NoOfMBytesPerSec > NoOfMBytesPerSecMax then
NoOfMBytesPerSecMax := NoOfMBytesPerSec;
NoOfMBytesPerSecMaxEdit.Text := IntToStr(NoOfMBytesPerSecMax);
SummedNoOfMBytesPerSecEdit.Text := SummedNoOfMBytesPerSecEdit.Text +
NoOfMBytesPerSecEdit.Text + ';';
ProgressBar1.Position := RunNo;
ArraySize := Round(ArraySize * ARRAYGROWFACTOR);
Inc(RunNo);
Update;
end;
RichEdit1.Lines.Add(SummedNoOfMBytesPerSecEdit.Text);
RichEdit1.Lines.SaveToFile('C:\Temp\MeMoveTiming.Txt');//Ready for import
into Excel
StatusBar1.SimpleText := 'Finished';
end;
Dennis
Re: Move Optimization
Author: Dennis
Date: Thu, 19 Sep 2002 18:20
Date: Thu, 19 Sep 2002 18:20
131 lines
5818 bytes
5818 bytes
Hi
This is the second proposal for benchmark code.
It is an extension of the first benchmark. Here move is called twice in
every loop. Once with the same array size as before. Once with an arraysize
which is MaxSize = 2MB - Arraysize. Thus every loop copies 2 MB and the two
moves competes on the cache and lots of cache misses is the result.
//This benchmark uses four static arrays of byte, size 2MB
//Move is called repeatedly on two sets of arrays. One array is of size X
and the other is MaxSize - X
//The two array sets competes on the cache, which is never big enough to
hold all 4 arrays
//The number of bytes "moved" is always MaxSize
//As X changes the ration between array sizes change
//The move speed is recorded for each X
//After N runs statistics is computed; Max -, Min - & Average - copy speed
//Average copy speed is the benchmark
procedure TMainForm.RunButtonClick(Sender: TObject);
var
SourceArray1 : array[1..2000000] of Byte;
DestinationArray1 : array[1..2000000] of Byte;
SourceArray2 : array[1..2000000] of Byte;
DestinationArray2 : array[1..2000000] of Byte;
I, K, Kmax, RunNo : Cardinal;
NoOfBytesPerSec, NoOfMBytesPerSec, NoOfMBytesPerSecTotal,
NoOfMBytesPerSecMax,
NoOfMBytesPerSecMin : Int64;
NoOfBytesFP, RunTimeSec : Extended;
ArraySize, NoOfBytes : Int64;
X1, X2, Y1, Y2 : Pointer;
lpFrequency, lpPerformanceCount, StartCount, EndCount,
NoOfTicks : TLargeInteger;
Succes : Boolean;
const
ARRAYGROWFACTOR : Double = 1.35;
ARRAYSIZESTART : Cardinal = 8;
RUNNOMAX : Cardinal = 100;
ARRAYSIZEMAX : Cardinal = 2000000;
begin
StatusBar1.SimpleText := 'Running';
SummedNoOfMBytesPerSecEdit.Text := '';
SummedArraySizeEdit.Text := '';
NoOfMBytesPerSecMaxEdit.Text := '';
X1 := @SourceArray1;
Y1 := @DestinationArray1;
X2 := @SourceArray2;
Y2 := @DestinationArray2;
AddressSourceEdit.Text := IntToHex(Integer(X1), 8) + '/' +
IntToHex(Integer(X2), 8);
AddressDestEdit.Text := IntToHex(Integer(Y1), 8) + '/' +
IntToHex(Integer(Y2), 8);
ProgressBar1.Max := 42;
ArraySize := ARRAYSIZESTART;
NoOfMBytesPerSecTotal := 0;
NoOfMBytesPerSecMax := 0;
NoOfMBytesPerSecMin := 99999999;
//Initialize arrays
for I := 1 to ARRAYSIZEMAX do
begin
SourceArray1[I] := 255;
DestinationArray1[I] := 1;
SourceArray2[I] := 255;
DestinationArray2[I] := 1;
end;
Succes := QueryPerformanceFrequency(lpFrequency);
if not Succes then
raise Exception.Create('QueryPerformanceFrequency failed');
RunNo := 1;
while (ArraySize < ARRAYSIZEMAX) do
begin
SummedArraySizeEdit.Text := SummedArraySizeEdit.Text +
IntToStr(ArraySize) + ';';
if ArraySize > Length(DestinationArray1) then
raise Exception.Create('ArraySize to big');
ArraySizeLabeledEdit.Text := IntToStr(ArraySize);
Update;
Kmax := RUNNOMAX;
Succes := QueryPerformanceCounter(lpPerformanceCount);
if Succes then
StartCount := lpPerformanceCount
else
raise Exception.Create('QueryPerformanceCounter failed');
for K := 1 to Kmax do
begin
//Functions to benchmark
Move(SourceArray1, DestinationArray1, ArraySize);
Move(SourceArray2, DestinationArray2, ARRAYSIZEMAX - ArraySize);
end;
Succes := QueryPerformanceCounter(lpPerformanceCount);
if Succes then
EndCount := lpPerformanceCount
else
raise Exception.Create('QueryPerformanceCounter failed');
NoOfTicks := EndCount - StartCount;
RunTimeSec := NoOfTicks / lpFrequency;
RunTimeEdit.Text := FloatToStrF(RunTimeSec, ffFixed, 9, 1);
NoOfBytes := ARRAYSIZEMAX * Kmax;
NoOfBytesFP := NoOfBytes;
if RunTimeSec <> 0 then
NoOfBytesPerSec := Round(NoOfBytesFP / RunTimeSec)
else
NoOfBytesPerSec := 0;
NoOfMBytesPerSec := Round(NoOfBytesPerSec / 1024 / 1024);
NoOfMBytesPerSecEdit.Text := IntToStr(NoOfMBytesPerSec);
NoOfMBytesPerSecTotal := NoOfMBytesPerSecTotal + NoOfMBytesPerSec;
NoOfMBytesPerSecTotalEdit.Text := IntToStr(NoOfMBytesPerSecTotal);
NoOfMBytesPerSecAverageEdit.Text := FloatToStrF(NoOfMBytesPerSecTotal /
RunNo, ffFixed, 9, 0);
if NoOfMBytesPerSec < NoOfMBytesPerSecMin then
NoOfMBytesPerSecMin := NoOfMBytesPerSec;
NoOfMBytesPerSecMinEdit.Text := IntToStr(NoOfMBytesPerSecMin);
if NoOfMBytesPerSec > NoOfMBytesPerSecMax then
NoOfMBytesPerSecMax := NoOfMBytesPerSec;
NoOfMBytesPerSecMaxEdit.Text := IntToStr(NoOfMBytesPerSecMax);
SummedNoOfMBytesPerSecEdit.Text := SummedNoOfMBytesPerSecEdit.Text +
NoOfMBytesPerSecEdit.Text + ';';
ProgressBar1.Position := RunNo;
ArraySize := Round(ArraySize * ARRAYGROWFACTOR);
Inc(RunNo);
Update;
end;
RichEdit1.Lines.Add(SummedNoOfMBytesPerSecEdit.Text);
RichEdit1.Lines.SaveToFile('C:\Temp\MeMoveTiming.Txt');//Ready for import
into Excel
StatusBar1.SimpleText := 'Finished';
end;
Dennis
Re: Move Optimization
Author: Eric Grange
Date: Fri, 20 Sep 2002 08:17
Date: Fri, 20 Sep 2002 08:17
15 lines
1745 bytes
1745 bytes
> What do you specifically mean by "binary memory"? Nothing special, just what you get from a GetMem f.i. (ie. untyped bunch of bytes) > Thats not a problem as i se it. They will just give bad benchmark results and be > sorted out. It is crucial that our benchmarks are very realistic. That may not be easy, the benchmark will do lots of moves, the movntq performance loss happen if you move and then perform something on the moved data (or part of the moved data, that would have been in cache otherwise, but isn't due to the novntq). If you just move lots of bytes around without caring about them, movntq looks plenty fast. Eric
Re: Move Optimization
Author: Robert Lee
Date: Fri, 20 Sep 2002 11:29
Date: Fri, 20 Sep 2002 11:29
12 lines
1357 bytes
1357 bytes
Dennis wrote: > Hi > > This is the first proposal for benchmark code. All suggestions for > modifications are welcome. You have no overlapped cases, and no tiny moves. Don't forget that move is used throughout the RTL without consideration as to the size of move. Consequently, tiny moves need to be very streamlined. -- Bob Lee High Performance Delphi - http://www.optimalcode.com/
Re: Move Optimization
Author: Dennis
Date: Fri, 20 Sep 2002 13:34
Date: Fri, 20 Sep 2002 13:34
23 lines
1710 bytes
1710 bytes
Hi I thought these very tiny 8;11;15;20;27;36. But ok i will set up a benchmark including more small ones and the overlapped case. Does anybody have a good example of an overlapped move from real life? Dennis Robert Lee wrote: > Dennis wrote: > > > Hi > > > > This is the first proposal for benchmark code. All suggestions for > > modifications are welcome. > > You have no overlapped cases, and no tiny moves. Don't forget that move is used throughout the RTL without consideration as to the size of move. Consequently, tiny moves need to be very streamlined. > > -- > Bob Lee > High Performance Delphi - http://www.optimalcode.com/
Re: Move Optimization
Author: Robert Lee
Date: Fri, 20 Sep 2002 13:41
Date: Fri, 20 Sep 2002 13:41
19 lines
1559 bytes
1559 bytes
Dennis wrote: > Hi > > I thought these very tiny 8;11;15;20;27;36. How about 0-15, also 30 on a $XXXX XXX1 alignment is an interesting worst case. BTW: see my other message. If we split the move problem into two pieces it would significantly simplify the benchmarking. > But ok i will set up a benchmark including more small ones and the overlapped case. > Does anybody have a good example of an overlapped move from real life? How about deleting an element from an array? -- Bob Lee High Performance Delphi - http://www.optimalcode.com/
Re: Move Optimization
Author: Robert Lee
Date: Fri, 20 Sep 2002 13:51
Date: Fri, 20 Sep 2002 13:51
13 lines
1420 bytes
1420 bytes
Hmm, might need an intermediate DWord aligned routine as well. > procedure AlignedFwdMove() // assumes 16byte alignment with count divisible > by 16 > procedure FwdMove() // calls AlignedFwdMove for the aligned center of the > move > procedure RevMove() // handles overlap cases > procedure Move() // handle all cases, calls FwdMove and RevMove as needed > -- Bob Lee High Performance Delphi - http://www.optimalcode.com/
Re: Move Optimization
Author: Per Larsen
Date: Fri, 20 Sep 2002 15:23
Date: Fri, 20 Sep 2002 15:23
21 lines
1665 bytes
1665 bytes
Bob, Warning: There's a potentially serious bug in your ReplaceRoutine method. > Data.Distance:=Integer(NewAddr)-(Integer(Addr)+5); That should be Data.Distance:=Integer(NewAddr)-Integer(Addr)-5; Your version assumes the new address is higher than the original. IOW, this will actually never become an issue if you're using code linked into the app as a direct replacement (as you're doing here) since System always comes first in memory, but in case you ever want to use this for something else... I just worked with some similar code yesterday, which is why this jumped out at me. - Per
Re: Move Optimization
Author: Per Larsen
Date: Fri, 20 Sep 2002 15:26
Date: Fri, 20 Sep 2002 15:26
11 lines
1385 bytes
1385 bytes
Dennis, IMO, the best thing to do would be to rig a real existing app with a Move, which logged all calls to a data file with information about source alignment, target alignment, size, and overlapped/not. That data could then be used as input to the benchmark. This would also supply real-life data about what cases are more important to optimize for. - Per
Re: Move Optimization
Author: Dennis
Date: Fri, 20 Sep 2002 15:58
Date: Fri, 20 Sep 2002 15:58
21 lines
1295 bytes
1295 bytes
Hi Can anybody tell me why this code is bad. Move destroys the source string. I believed S1 had to survive the Move. var S1, S2 : AnsiString; begin S1 := 'Dennis'; S2 := 'XXXXXX'; Edit1.Text := S1; Edit2.Text := S2; Move(S1, S2, 6); Edit3.Text := S1; Edit4.Text := S2; end; Thanks Dennis
Re: Move Optimization
Author: Robert Lee
Date: Fri, 20 Sep 2002 16:37
Date: Fri, 20 Sep 2002 16:37
10 lines
1260 bytes
1260 bytes
> @E: > mov cx, [eax+12] > mov [edx+12], cx word sized access is "bad". It causes stalls on some(all?) CPU's I'll look int FwdMove tonite. -- Bob Lee High Performance Delphi - http://www.optimalcode.com/
Re: Move Optimization
Author: Robert Lee
Date: Fri, 20 Sep 2002 16:38
Date: Fri, 20 Sep 2002 16:38
14 lines
1325 bytes
1325 bytes
Per Larsen wrote: > Bob, > > Warning: There's a potentially serious bug in your ReplaceRoutine > method. Subtle, but important. Thanks, -- Bob Lee High Performance Delphi - http://www.optimalcode.com/
Re: Move Optimization
Author: Robert Lee
Date: Fri, 20 Sep 2002 16:53
Date: Fri, 20 Sep 2002 16:53
24 lines
1687 bytes
1687 bytes
Eric Grange wrote:
> Looks fair to me, slight issue: the pascal Move
> doesn't handle overlap for length 2-4.
Oops, I didn't mean to leave that one in there. It isn't ready for primetime yet.
> @F:
> mov cl, [eax+14] // source[count-15+0]
> mov [edx+14], bl
> @E:
> mov cx, [eax+12]
> mov [edx+12], cx
Two problems:
1) this is supposed to be a *forward* move. You are copying backwards here. I had a FreeMove version that worked like this but it is an unnecessary complication
2) word-sized access is "bad" as it causes a CPU stall on some (all?) processors.
I'll look at it more tonite.
--
Bob Lee
High Performance Delphi - http://www.optimalcode.com/
Re: Move Optimization
Author: Hagen Reddmann
Date: Fri, 20 Sep 2002 17:12
Date: Fri, 20 Sep 2002 17:12
46 lines
2611 bytes
2611 bytes
How about to collect first some realtime inputs of Move() calls or GetMem() and so on. I think before we optimize such procedures we should collect the most provable best/worstcase. After that we can think about our design strategies. Thats the main problem with such ideas as using MMX/SSE2 move() replacements. All they gave on my trials bad performances because they are only fast in very rare circumstances. And second, they proposed performance are far from reality and in fact says nothing about the real performance with highly randomized realtime applications. Why should be an high optimized MMX/SSE2 move() that requiere 1Mb moves, faster when I do it in ten years 1000 times, and 1 trillion times i do moves of length smaller than 64 bytes ?! Best regards, Hagen "Robert Lee" <rhlee@optimalcode.com> schrieb im Newsbeitrag news:3D8B259B.C88CD284@optimalcode.com... > Dennis wrote: > > > Hi > > > > I thought these very tiny 8;11;15;20;27;36. > > How about 0-15, also 30 on a $XXXX XXX1 alignment is an interesting worst case. > > BTW: see my other message. If we split the move problem into two pieces it would significantly simplify the benchmarking. > > > > But ok i will set up a benchmark including more small ones and the overlapped case. > > Does anybody have a good example of an overlapped move from real life? > > How about deleting an element from an array? > > -- > Bob Lee > High Performance Delphi - http://www.optimalcode.com/ > >
Re: Move Optimization
Author: Dennis
Date: Fri, 20 Sep 2002 19:15
Date: Fri, 20 Sep 2002 19:15
123 lines
4769 bytes
4769 bytes
One more benchmark proposal. Small strings 1,2,3....8 byte. Random compiler
controlled alignment.
Longer strings get less runs -> all string length's attribute approximately
the same to the benchmark.
function StringMoves : Extended;
var
SourceString1, DestString1 : AnsiString;
RunTimeSec : Extended;//Destroy alignment
SourceString2, DestString2 : AnsiString;
AverageCopySpeed : Extended;//Destroy alignment
SourceString3, DestString3 : AnsiString;
SourceString4, DestString4 : AnsiString;
MBMoved : Extended;//Destroy alignment
SourceString5, DestString5 : AnsiString;
SourceString6, DestString6 : AnsiString;
SourceString7, DestString7 : AnsiString;
SourceString8, DestString8 : AnsiString;
I1, I2, I3, I4, I5, I6, I7, I8 : Cardinal;
Count1, Count2, Count3, Count4, Count5, Count6, Count7, Count8 : Cardinal;
lpFrequency, lpPerformanceCount, StartCount, EndCount, NoOfTicks :
TLargeInteger;
Succes : Boolean;
const
NOOFRUNS1 : Cardinal = 10000000;
NOOFRUNS2 : Cardinal = 5000000;
NOOFRUNS3 : Cardinal = 3333333;
NOOFRUNS4 : Cardinal = 2500000;
NOOFRUNS5 : Cardinal = 2000000;
NOOFRUNS6 : Cardinal = 1666666;
NOOFRUNS7 : Cardinal = 1400000;
NOOFRUNS8 : Cardinal = 1250000;
begin
MainForm.StatusBar1.SimpleText := 'Running Sub Benchmark: StringMoves';
SourceString1 := 'A';
DestString1 := '1';
SourceString2 := 'AB';
DestString2 := '01';
SourceString3 := 'ABC';
DestString3 := '012';
SourceString4 := 'ABCD';
DestString4 := '0123';
SourceString5 := 'ABCDE';
DestString5 := '01234';
SourceString6 := 'ABCDEF';
DestString6 := '012345';
SourceString7 := 'ABCDEFG';
DestString7 := '0123456';
SourceString8 := 'ABCDEFGH';
DestString8 := '01234567';
Count1 := Length(SourceString1);
Count2 := Length(SourceString2);
Count3 := Length(SourceString3);
Count4 := Length(SourceString4);
Count5 := Length(SourceString5);
Count6 := Length(SourceString6);
Count7 := Length(SourceString7);
Count8 := Length(SourceString8);
Succes := QueryPerformanceFrequency(lpFrequency);
if Succes then
begin
Succes := QueryPerformanceCounter(lpPerformanceCount);
if Succes then
StartCount := lpPerformanceCount
else
raise Exception.Create('QueryPerformanceCounter failed');
end
else
raise Exception.Create('QueryPerformanceFrequency failed');
for I1 := 1 to NoOfRuns1 do
begin
Move(SourceString1[1], DestString1[1], Count1);
end;
for I2 := 1 to NoOfRuns2 do
begin
Move(SourceString2[1], DestString2[1], Count2);
end;
for I3 := 1 to NoOfRuns3 do
begin
Move(SourceString3[1], DestString3[1], Count3);
end;
for I4 := 1 to NoOfRuns4 do
begin
Move(SourceString4[1], DestString4[1], Count4);
end;
for I5 := 1 to NoOfRuns5 do
begin
Move(SourceString5[1], DestString5[1], Count5);
end;
for I6 := 1 to NoOfRuns6 do
begin
Move(SourceString6[1], DestString6[1], Count6);
end;
for I7 := 1 to NoOfRuns7 do
begin
Move(SourceString7[1], DestString7[1], Count7);
end;
for I8 := 1 to NoOfRuns8 do
begin
Move(SourceString8[1], DestString8[1], Count8);
end;
Succes := QueryPerformanceCounter(lpPerformanceCount);
if Succes then
EndCount := lpPerformanceCount
else
raise Exception.Create('QueryPerformanceCounter failed');
NoOfTicks := EndCount - StartCount;
RunTimeSec := NoOfTicks / lpFrequency;
MBMoved := (Count1 * NOOFRUNS1
+ Count2 * NOOFRUNS2
+ Count3 * NOOFRUNS3
+ Count4 * NOOFRUNS4
+ Count5 * NOOFRUNS5
+ Count6 * NOOFRUNS6
+ Count7 * NOOFRUNS7
+ Count8 * NOOFRUNS8) / (1024 * 1024);
AverageCopySpeed := MBMoved / RunTimeSec;
MainForm.RunTimeEdit.Text := FloatToStrF(RunTimeSec, ffFixed, 9, 1);
Result := AverageCopySpeed;
end;
Dennis
Re: Move Optimization
Author: Robert Lee
Date: Sat, 21 Sep 2002 00:28
Date: Sat, 21 Sep 2002 00:28
20 lines
2173 bytes
2173 bytes
Hagen Reddmann wrote: > How about to collect first some realtime inputs of Move() calls or GetMem() > and so on. With functions like these there really aren't any "typical" apps. You essentially have to optimize for all scenarios because any single app is likely to only use a small subset of the total and of those any one could be "the" time critical one. This means you have to pursue differing strategies based on the input. Then you have to come up with wost-case scenarios based on the algorithm and use those to make decisions. > Why should be an high optimized MMX/SSE2 move() that requiere 1Mb moves, > faster when I do it in ten years 1000 times, and 1 trillion times i do moves > of length smaller than 64 bytes ?! Like I said above you have to optimize for all the cases. Fortunately, with move the optimization criteria shift with the input cases. (minimal overhead for tiny moves -> minimal loop times for big moves) -- Bob Lee High Performance Delphi - http://www.optimalcode.com/
Thread Navigation
This is a paginated view of messages in the thread with full content displayed inline.
Messages are displayed in chronological order, with the original post highlighted in green.
Use pagination controls to navigate through all messages in large threads.
Back to All Threads