sudhakar_koundinya
asked on
Fast Strings , Fast Memory assignments .....
Hi all,
I involved in a project where the, total work depends on string functions, assigning memory, copying memory,deleting memory and so on.
Actually the project was completed. But when i compared the similar applications which were developed using c++, my application is working dead slow.Even I tested my application in c++ code.(it is working fine there). But client requires the source code of my project. I optimized the code also, by removing unneccessary loops and memory assignments.But still it is working slow,
When i read different articles provided on net. Most of the people are saying that delphi memory assignments and delphi strings are slow when compared to other language string functions and memory assignment functions.
what they are saying is hyper strings and fast strings( i don't know what these are) will work fast when compared to delphi strings.
******************
In this case i want explaination of hyper strings and fast strings. Please provide some source codes, if anybody have. According to one article fast strings are much faster than hyper strings.
*******************
similarly delphi memory assignments, and memory copy functions are slow b'coz the assembeled code uses 16 bit instructions instead of 32 bit instructions.
Here also i require some source code. If any body have the above source codes please post me.
If any body have detailed information on this please post ur valuable answers
thanks in advance
Koundinya
I involved in a project where the, total work depends on string functions, assigning memory, copying memory,deleting memory and so on.
Actually the project was completed. But when i compared the similar applications which were developed using c++, my application is working dead slow.Even I tested my application in c++ code.(it is working fine there). But client requires the source code of my project. I optimized the code also, by removing unneccessary loops and memory assignments.But still it is working slow,
When i read different articles provided on net. Most of the people are saying that delphi memory assignments and delphi strings are slow when compared to other language string functions and memory assignment functions.
what they are saying is hyper strings and fast strings( i don't know what these are) will work fast when compared to delphi strings.
******************
In this case i want explaination of hyper strings and fast strings. Please provide some source codes, if anybody have. According to one article fast strings are much faster than hyper strings.
*******************
similarly delphi memory assignments, and memory copy functions are slow b'coz the assembeled code uses 16 bit instructions instead of 32 bit instructions.
Here also i require some source code. If any body have the above source codes please post me.
If any body have detailed information on this please post ur valuable answers
thanks in advance
Koundinya
listening . . .
Listening, and waiting madshi :-)
yep,
madshi has the most background for this
from my point of view
look at its madBasic-unit at
http://www.madshi.net/
meikl ;-)
madshi has the most background for this
from my point of view
look at its madBasic-unit at
http://www.madshi.net/
meikl ;-)
:-) Thanx, guys...
hyper strings and fast strings have some nice routines. The biggest improvements can be found when comparing strings or the like. E.g. if you want to find out whether two strings are identical, while ignoring the case, with only Delphi you would do:
if CompareText(str1, str2) = 0 then
Or if you want to find out whether one string is a part of another, again ignoring the case, you would have to do something like that:
if Pos(AnsiUpperCase(str1), AnsiUpperCase(str2)) <> 0 then
Such things are really slow, if you're calling them quite often. There are much faster functions for such stuff available. I think both hyper strings and fast strings have nice functions there. My package madBasic also contains some fast string functions, as meikl already pointed out. Best would be to download all 3 and compare yourself. Doing a little performance test is really no problem. Just do the things you normally do in a big loop and check how long it takes with different functions.
Memory assignment should not be too bad with Delphi. And especially strings in general are NO WAY slow. Quite the other way round! In Delphi strings are reference counted. That can save both memory and time. Copy actions are done by Delphi automatically in the background, only if it is needed. However, if you're writing "unclever" code, it might be very slow. Just a tight change might make it multiple times faster, simply by avoiding some allocation actions.
Please show us some string/memory actions you're often doing. Then we might find suggestions to make it faster. But have no fear, you can write top performing programs with Delphi string, no problem, if you're doing it right.
Regards, Madshi.
hyper strings and fast strings have some nice routines. The biggest improvements can be found when comparing strings or the like. E.g. if you want to find out whether two strings are identical, while ignoring the case, with only Delphi you would do:
if CompareText(str1, str2) = 0 then
Or if you want to find out whether one string is a part of another, again ignoring the case, you would have to do something like that:
if Pos(AnsiUpperCase(str1), AnsiUpperCase(str2)) <> 0 then
Such things are really slow, if you're calling them quite often. There are much faster functions for such stuff available. I think both hyper strings and fast strings have nice functions there. My package madBasic also contains some fast string functions, as meikl already pointed out. Best would be to download all 3 and compare yourself. Doing a little performance test is really no problem. Just do the things you normally do in a big loop and check how long it takes with different functions.
Memory assignment should not be too bad with Delphi. And especially strings in general are NO WAY slow. Quite the other way round! In Delphi strings are reference counted. That can save both memory and time. Copy actions are done by Delphi automatically in the background, only if it is needed. However, if you're writing "unclever" code, it might be very slow. Just a tight change might make it multiple times faster, simply by avoiding some allocation actions.
Please show us some string/memory actions you're often doing. Then we might find suggestions to make it faster. But have no fear, you can write top performing programs with Delphi string, no problem, if you're doing it right.
Regards, Madshi.
I would guess that a memory manager targeted at small memory blocks (which strings usually are) could help.
Thanks all,
for immediate response. May be i am late to react for ur responses :-( . I feel sorry for that.
Thanks Madshi, I will check ur project. If it is useful for me i will try to use that
Pos, Compare,CompareNoCase,Stri ngReplace are the frequent methods I have to use in the project. I read that these methods are slow when compared to other language functions.
When coming to memory management, Move is the method , i am using frequently. This is also problem for me as per articles . So I got one method from some site. In my case it is not helpful for me though it is faster
//My move is not as fast as MOVE when source and destination are both
//DWord aligned, but certainly faster when they are not.
//As we are moving characters in a string, it is not very likely at all that
//both source and destination are DWord aligned, so moving bytes avoids the
//cycle penality of reading/writing DWords across physical boundaries
procedure PMove(const Source; var Dest; Count : Integer);
asm
//Note: When this function is called, delphi passes the parameters as follows
//ECX = Count
//EAX = Const Source
//EDX = Var Dest
//If no bytes to copy, just quit altogether, no point pushing registers
cmp ECX,0
Je @JustQuit
//Preserve the critical delphi registers
push ESI
push EDI
//move Source into ESI (generally the SOURCE register)
//move Dest into EDI (generally the DEST register for string commands)
//This may not actually be neccessary, as I am not using MOVsb etc
//I may be able just to use EAX and EDX, there may be a penalty for
//not using ESI, EDI but I doubt it, this is another thing worth trying !
mov ESI, EAX
mov EDI, EDX
//The following loop is the same as repNZ MovSB, but oddly quicker !
@Loop:
//Get the source byte
Mov AL, [ESI]
//Point to next byte
Inc ESI
//Put it into the Dest
mov [EDI], AL
//Point dest to next position
Inc EDI
//Dec ECX to note how many we have left to copy
Dec ECX
//If ECX <> 0 then loop
Jnz @Loop
//Another optimization note.
//Many people like to do this
//Mov AL, [ESI]
//Mov [EDI], Al
//Inc ESI
//Inc ESI
//There is a hidden problem here, I wont go into too much detail, but
//the pentium can continue processing instructions while it is still
//working out the desult of INC ESI or INC EDI
//(almost like a multithreaded CPU)
//if, however, you go to use them while they are still being calculated
//the processor will stop until they are calculated (a penalty)
//Therefore I alter ESI and EDI as far in advance as possible of using them
//Pop the critical Delphi registers that we have altered
pop EDI
pop ESI
@JustQuit:
end;
****************
One more point i have to share with you guys is
in one article i read that
instead of following like this
while(1): do
begin
a[x]:=b[x]
x:=x+1;
end;
he is suggesting some thin like this for code optimization. I don't know why it should be like that.
x=len(b);
while(1): do
begin
if(x<=0) then break;
a[x]:=b[x];
x:=x-1;
end;
Author of the article is saying that, this will work fast when compared to previous one. Are there any particular reasons for this.
Waiting for responses
thanks
Koundinya
for immediate response. May be i am late to react for ur responses :-( . I feel sorry for that.
Thanks Madshi, I will check ur project. If it is useful for me i will try to use that
Pos, Compare,CompareNoCase,Stri
When coming to memory management, Move is the method , i am using frequently. This is also problem for me as per articles . So I got one method from some site. In my case it is not helpful for me though it is faster
//My move is not as fast as MOVE when source and destination are both
//DWord aligned, but certainly faster when they are not.
//As we are moving characters in a string, it is not very likely at all that
//both source and destination are DWord aligned, so moving bytes avoids the
//cycle penality of reading/writing DWords across physical boundaries
procedure PMove(const Source; var Dest; Count : Integer);
asm
//Note: When this function is called, delphi passes the parameters as follows
//ECX = Count
//EAX = Const Source
//EDX = Var Dest
//If no bytes to copy, just quit altogether, no point pushing registers
cmp ECX,0
Je @JustQuit
//Preserve the critical delphi registers
push ESI
push EDI
//move Source into ESI (generally the SOURCE register)
//move Dest into EDI (generally the DEST register for string commands)
//This may not actually be neccessary, as I am not using MOVsb etc
//I may be able just to use EAX and EDX, there may be a penalty for
//not using ESI, EDI but I doubt it, this is another thing worth trying !
mov ESI, EAX
mov EDI, EDX
//The following loop is the same as repNZ MovSB, but oddly quicker !
@Loop:
//Get the source byte
Mov AL, [ESI]
//Point to next byte
Inc ESI
//Put it into the Dest
mov [EDI], AL
//Point dest to next position
Inc EDI
//Dec ECX to note how many we have left to copy
Dec ECX
//If ECX <> 0 then loop
Jnz @Loop
//Another optimization note.
//Many people like to do this
//Mov AL, [ESI]
//Mov [EDI], Al
//Inc ESI
//Inc ESI
//There is a hidden problem here, I wont go into too much detail, but
//the pentium can continue processing instructions while it is still
//working out the desult of INC ESI or INC EDI
//(almost like a multithreaded CPU)
//if, however, you go to use them while they are still being calculated
//the processor will stop until they are calculated (a penalty)
//Therefore I alter ESI and EDI as far in advance as possible of using them
//Pop the critical Delphi registers that we have altered
pop EDI
pop ESI
@JustQuit:
end;
****************
One more point i have to share with you guys is
in one article i read that
instead of following like this
while(1): do
begin
a[x]:=b[x]
x:=x+1;
end;
he is suggesting some thin like this for code optimization. I don't know why it should be like that.
x=len(b);
while(1): do
begin
if(x<=0) then break;
a[x]:=b[x];
x:=x-1;
end;
Author of the article is saying that, this will work fast when compared to previous one. Are there any particular reasons for this.
Waiting for responses
thanks
Koundinya
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
Madshi,
You are talking abt aligned actions
What are that?
You are talking abt aligned actions
What are that?
ASKER
Lingababu,
Can u explain how ur move works.
thanks
Can u explain how ur move works.
thanks
If you move from or to an odd physical RAM address, the move often is slower. E.g. if you do this:
Move(pointer(1)^, pointer(5)^, 1000);
Of course this is nonsense. But let's do as if would be real. You're moving from an odd address to an odd address. That's probably slow. Better would be to split that line into those:
Move(pointer( 1)^, pointer( 5)^, 3);
Move(pointer( 4)^, pointer( 8)^, 996);
Move(pointer(1000)^, pointer(1004)^, 1);
This way we're doing 2 slow Moves (the first and third), but both Moves do only copy <4 bytes, so it's no big problem. But the big chunk of the Move is done from an even address to an even address (even is a multiple of 4). These 3 Moves are supposed to be faster than the one from above.
Now my MoveAligned function basically checks the Move addresses and splits one Move call into several, if it makes sense.
Regards, Madshi.
Move(pointer(1)^, pointer(5)^, 1000);
Of course this is nonsense. But let's do as if would be real. You're moving from an odd address to an odd address. That's probably slow. Better would be to split that line into those:
Move(pointer( 1)^, pointer( 5)^, 3);
Move(pointer( 4)^, pointer( 8)^, 996);
Move(pointer(1000)^, pointer(1004)^, 1);
This way we're doing 2 slow Moves (the first and third), but both Moves do only copy <4 bytes, so it's no big problem. But the big chunk of the Move is done from an even address to an even address (even is a multiple of 4). These 3 Moves are supposed to be faster than the one from above.
Now my MoveAligned function basically checks the Move addresses and splits one Move call into several, if it makes sense.
Regards, Madshi.
Compare the two Moves yourself. I'm quite sure mine is faster.
ASKER
Thanks Madshi,
I will test that code. DO u have any article regarding fast strings and hyper strings?
I will test that code. DO u have any article regarding fast strings and hyper strings?
No.
ASKER
In MadBasic (your project),
What is the the approach you are following to make the functions work faster.
In my project, in some areas i am following this idea for traversing into the data. But as per lingababu comment, will it work slow
while(1): do
begin
a[x]:=b[x]
x:=x+1;
end;
thanks
What is the the approach you are following to make the functions work faster.
In my project, in some areas i am following this idea for traversing into the data. But as per lingababu comment, will it work slow
while(1): do
begin
a[x]:=b[x]
x:=x+1;
end;
thanks
ASKER
Madshi,
Just now I saw this on net
procedure MoveMem32(Src,Dest:Pointer ;Size:inte ger);
// Size=number of dword elements to fill
// assumes that Size>4
asm
push edi
push esi
push ebx
mov ebx,[eax]
mov [eax],ebx
mov ebx,[eax+4]
mov [eax+4],ebx
mov ebx,[eax+8]
mov [eax+8],ebx
mov ebx,[eax+12]
mov [eax+12],ebx
mov ebx,edx
add ebx,15
and ebx,-16
mov edi,ebx
sub ebx,edx
shr ebx,2
sub ecx,ebx
lea esi,[eax+4*ebx]
rep movsd
pop ebx
pop esi
pop edi
end;
http://www.optimalcode.com/general.htm
Just now I saw this on net
procedure MoveMem32(Src,Dest:Pointer
// Size=number of dword elements to fill
// assumes that Size>4
asm
push edi
push esi
push ebx
mov ebx,[eax]
mov [eax],ebx
mov ebx,[eax+4]
mov [eax+4],ebx
mov ebx,[eax+8]
mov [eax+8],ebx
mov ebx,[eax+12]
mov [eax+12],ebx
mov ebx,edx
add ebx,15
and ebx,-16
mov edi,ebx
sub ebx,edx
shr ebx,2
sub ecx,ebx
lea esi,[eax+4*ebx]
rep movsd
pop ebx
pop esi
pop edi
end;
http://www.optimalcode.com/general.htm
>> Just now I saw this on net
Well, compare the speed yourself. Maybe you get the fastest solution, if you combine that MoveMem32 with my MoveAligned. Just change my MoveAligned function in that way, that it called MoveMem32 instead of Move.
>> In MadBasic (your project), what is the the approach you are following to make the functions work faster.
There are several approaches. Do you really need to understand the internals? Why not just trying Fast strings, Hyper strings and madBasic and take the best/fastest from each package?
>> In my project, in some areas i am following this idea for traversing into the data. But as per lingababu
comment, will it work slow
Yes, such a loop will be slow, because it does byte per byte. Copying memory dword by dword is usually way faster, well, if the dword move is aligned (even). Thus I wrote MoveAligned.
Regards, Madshi.
Well, compare the speed yourself. Maybe you get the fastest solution, if you combine that MoveMem32 with my MoveAligned. Just change my MoveAligned function in that way, that it called MoveMem32 instead of Move.
>> In MadBasic (your project), what is the the approach you are following to make the functions work faster.
There are several approaches. Do you really need to understand the internals? Why not just trying Fast strings, Hyper strings and madBasic and take the best/fastest from each package?
>> In my project, in some areas i am following this idea for traversing into the data. But as per lingababu
comment, will it work slow
Yes, such a loop will be slow, because it does byte per byte. Copying memory dword by dword is usually way faster, well, if the dword move is aligned (even). Thus I wrote MoveAligned.
Regards, Madshi.
ASKER
And I have found following code on net. When I tested giving errors.
procedure
movelong( fromp : Pchar;
var top : pchar;
len : longint);
{--------
long mover
- assumes from and to do not overlap (to not in from) }
type
longtype = array[1 .. 63 * 1024] of char;
longtypeptr = ^ longtype;
ptrrec = record
ofs, seg : word; end;
const
longtypelen = sizeof(longtype);
begin
{ fix the pointers: offsets between 0 and 15 }
inc(ptrrec(fromp).seg, ptrrec(fromp).ofs div 16);
ptrrec(fromp).ofs := ptrrec(fromp).ofs and 15;
inc(ptrrec(top).seg, ptrrec(top).ofs div 16);
ptrrec(top).ofs := ptrrec(top).ofs and 15;
{ move pieces }
while len > sizeof(longtype) do begin
{ faster than: move(fromp^, top^, sizeof(longtype)); }
asm
push ds
lds si,fromp
les di,top
mov cx,(longtypelen / 2)
cld
rep movsw
pop ds
end;
dec(len, sizeof(longtype));
inc(ptrrec(fromp).seg, sizeof(longtype) div 16);
inc(ptrrec(top).seg, sizeof(longtype) div 16);
end;
if len <> 0 then
{ faster than: move(fromp^, top^, len); }
asm
push ds
lds si,fromp
les di,top
mov cx,word(len)
shr cx, 1
cld
jnc @wordmove
movsb
@wordmove:
rep movsw
pop ds
end;
end;
procedure
movelong( fromp : Pchar;
var top : pchar;
len : longint);
{--------
long mover
- assumes from and to do not overlap (to not in from) }
type
longtype = array[1 .. 63 * 1024] of char;
longtypeptr = ^ longtype;
ptrrec = record
ofs, seg : word; end;
const
longtypelen = sizeof(longtype);
begin
{ fix the pointers: offsets between 0 and 15 }
inc(ptrrec(fromp).seg, ptrrec(fromp).ofs div 16);
ptrrec(fromp).ofs := ptrrec(fromp).ofs and 15;
inc(ptrrec(top).seg, ptrrec(top).ofs div 16);
ptrrec(top).ofs := ptrrec(top).ofs and 15;
{ move pieces }
while len > sizeof(longtype) do begin
{ faster than: move(fromp^, top^, sizeof(longtype)); }
asm
push ds
lds si,fromp
les di,top
mov cx,(longtypelen / 2)
cld
rep movsw
pop ds
end;
dec(len, sizeof(longtype));
inc(ptrrec(fromp).seg, sizeof(longtype) div 16);
inc(ptrrec(top).seg, sizeof(longtype) div 16);
end;
if len <> 0 then
{ faster than: move(fromp^, top^, len); }
asm
push ds
lds si,fromp
les di,top
mov cx,word(len)
shr cx, 1
cld
jnc @wordmove
movsb
@wordmove:
rep movsw
pop ds
end;
end;
Looks like 16bit code to me...
madshi, your code is making me feel dizzy :)
:-)
ASKER
thanks and sorry for late responding
:)
:)