xor一块内存 ( 积分: 100 )

  • 主题发起人 主题发起人 felixsun
  • 开始时间 开始时间
F

felixsun

Unregistered / Unconfirmed
GUEST, unregistred user!
我没在delphi中找到xorbuf 这类的函数, 就自己试着写了写,但效率不是很高,请高人帮助修改,这也是我第一次写 嵌入式汇编,

procedure XorBufAsm(D, S: Pointer
Count: Integer);
asm
push eax;
push ebx;
push ecx;
push edx;

dec edx
dec eax

test ecx,ecx
jz @2

@1:
mov bh,BYTE [edx+ecx]
xor Byte [eax+ecx], bh
dec ecx;
jnz @1;

@2:
pop edx;
pop ecx;
pop ebx;
pop eax;
end;

procedure XorBufAsm2(D, S: Pointer
Count: Integer);
asm
push eax;
push ebx;
push ecx;
push edx;

mov ebx,ecx;
and ebx,$3;
jz @2
shl ebx,8;
@1:
mov bl,BYTE [edx+ecx-1]
xor [eax+ecx-1], bl
dec ecx;
dec bh;
jnz @1;
@2:
shr ecx,2
jz @4
sub edx,4
sub eax,4
@3:
mov ebx,[edx+ecx*4]
xor [eax+ecx*4] ,ebx
dec ecx;
jnz @3;
@4:
pop edx;
pop ecx;
pop ebx;
pop eax;
end;

procedure XorBuf1(D, S: Pointer
Count: Integer);
var
i: Integer;
tmpByte: integer;
begin
for i := 0 to Count-1 do
begin
Byte((PChar(D) + i)^) := Byte((PChar(D) + i)^) xor Byte((PChar(S) + i)^);
end;
end;

procedure XorBuf2(D, S: Pointer
Count: Integer);
type
TIntegerArray = array[0..MaxInt div 8 - 1] of Integer;
PIntegerArray = ^TIntegerArray;
var
i, b: Integer;
begin
b := Count mod 4;
for i := 1 to b do
begin
Byte((PChar(D) + Count - i)^) := Byte((PChar(D) + Count - i)^) xor Byte((PChar(S) + Count - i)^);
end;
for i := 0 to (Count div 4) - 1 do
PIntegerArray(D)^ := PIntegerArray(D)^ xor PIntegerArray(S)^;
end;
 
我没在delphi中找到xorbuf 这类的函数, 就自己试着写了写,但效率不是很高,请高人帮助修改,这也是我第一次写 嵌入式汇编,

procedure XorBufAsm(D, S: Pointer
Count: Integer);
asm
push eax;
push ebx;
push ecx;
push edx;

dec edx
dec eax

test ecx,ecx
jz @2

@1:
mov bh,BYTE [edx+ecx]
xor Byte [eax+ecx], bh
dec ecx;
jnz @1;

@2:
pop edx;
pop ecx;
pop ebx;
pop eax;
end;

procedure XorBufAsm2(D, S: Pointer
Count: Integer);
asm
push eax;
push ebx;
push ecx;
push edx;

mov ebx,ecx;
and ebx,$3;
jz @2
shl ebx,8;
@1:
mov bl,BYTE [edx+ecx-1]
xor [eax+ecx-1], bl
dec ecx;
dec bh;
jnz @1;
@2:
shr ecx,2
jz @4
sub edx,4
sub eax,4
@3:
mov ebx,[edx+ecx*4]
xor [eax+ecx*4] ,ebx
dec ecx;
jnz @3;
@4:
pop edx;
pop ecx;
pop ebx;
pop eax;
end;

procedure XorBuf1(D, S: Pointer
Count: Integer);
var
i: Integer;
tmpByte: integer;
begin
for i := 0 to Count-1 do
begin
Byte((PChar(D) + i)^) := Byte((PChar(D) + i)^) xor Byte((PChar(S) + i)^);
end;
end;

procedure XorBuf2(D, S: Pointer
Count: Integer);
type
TIntegerArray = array[0..MaxInt div 8 - 1] of Integer;
PIntegerArray = ^TIntegerArray;
var
i, b: Integer;
begin
b := Count mod 4;
for i := 1 to b do
begin
Byte((PChar(D) + Count - i)^) := Byte((PChar(D) + Count - i)^) xor Byte((PChar(S) + Count - i)^);
end;
for i := 0 to (Count div 4) - 1 do
PIntegerArray(D)^ := PIntegerArray(D)^ xor PIntegerArray(S)^;
end;
 
给点小建议:
32位的CPU,Delphi自己的嵌入式汇编都是按照32位对齐的(如 Move),看你上面Xor时用的都是8位,这么增加了寻址时间。据说寻一个8位数据的地址所消耗Cpu的时间要远远大于寻一个32位数据的地址的消耗。所以建议楼主也试试32位对齐的Xor方法,那样效率应该就会高一些。
 
unit uXorMemory;

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, ExtCtrls;

type
TForm1 = class(TForm)
btnRunTest: TButton;
memoLog: TMemo;
ledtLength: TLabeledEdit;
procedure btnRunTestClick(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
procedure LogHex(const s:PChar;len:Integer);
end;

var
Form1: TForm1;

implementation

{$R *.dfm}
{
简单测试如下:(Celeron1.1G 256M)

申请字节数(Byte) 计算耗时(ms) Counter(误差范围未准确测试)
80,000,000 531 ~2974 1905385 ~10652417
8,000,000 50 ~60 187289 ~219706
800,000 10 21749 ~41901
80,000 0 325~330
8,000 0 34
}
procedure XorMem(Source,Dest:Pointer
Count:Integer);
asm
{ ->EAX source value }
{ EDX destination value }
{ ECX Count }

PUSH ebx
mov ebx,ecx
and ebx,03H

ShR ECX,2
Jz @@exit
@@loop:
push eax
mov eax,[eax]
xor [edx],eax
add edx,04h
pop eax
add eax,04h
dec ecx
jnz @@loop
cmp ebx,0
jz @@exit
@@trail://剩余字节0..3
push eax
mov al,[eax]
xor [edx],al
inc edx
pop eax
inc eax
dec ebx
jnz @@trail
@@exit:
POP ebx
end;

procedure TForm1.btnRunTestClick(Sender: TObject);
var
s,d:PChar;
len:Integer;
timeUsed:Cardinal;
counterBefore,counterAfter,counterFrequency:Int64;
str:string;
timeForMem:Cardinal;
begin
{
当申请内存大于100M 的时候,计算时间就比较长了,大概在0.5分钟左右

当频繁申请释放内存的时候,申请与释放的时间将会变得非常大
总计用时 21571 ms
计算用时 13840 ms//从此可看出申请释放的时间和计算的时间几乎相当
计算用时 49543465 counter
}
timeForMem :=GetTickCount;

len :=StrToIntDef(Trim(ledtLength.Text),1);
s :=GetMemory(len);
FillMemory(s,len,$95)
//$95 xor $A5 =$30
LogHex(s,len);

d :=GetMemory(len);
FillMemory(d,len,$A5);
LogHex(d,len);
try
QueryPerformanceFrequency(counterFrequency);//int counts per second
timeUsed :=GetTickCount;
QueryPerformanceCounter(counterBefore);

XorMem(s,d,len);

QueryPerformanceCounter(counterAfter);
timeUsed :=GetTickCount -timeUsed;

LogHex(d,len);

str :=Format('计算用时 %d counter',[counterAfter -counterBefore]);
memoLog.Lines.Insert(0,str);
str :=Format('计算用时 %d ms',[timeUsed]);
memoLog.Lines.Insert(0,str);

finally
FreeMemory(d);
FreeMemory(s);
end;
timeForMem :=GetTickCount -timeForMem;
str :=Format('总计用时 %d ms',[timeForMem]);
memoLog.Lines.Insert(0,str);
end;
procedure TForm1.LogHex(const s:PChar;len:Integer);
var
i :Integer;
str:string;
begin
str :='';
if len<1024 then
for i:=0 to len-1 do
str :=Format('%s 0x%s',[str,IntToHex(Integer(s),2)])
else str:='len >1024';
memoLog.Lines.Insert(0,str);
end;

end.
 
简单测试如下:(Celeron1.1G 256M)

申请字节数(Byte) 耗时(ms) Counter(误差范围未准确测试)
80000000 531 ~2974 1905385 ~10652417
8000000 50 ~60 187289 ~219706
800000 10 21749 ~41901
80000 0 325~330
8000 0 34
 
感谢dawnsong的帮助,请问还有没更快的方法,比如用 mmx..等多媒体指令级
 
更快的话,自己去估算一下指令周期,选取最优化。(另,查找一下Intel的指令手册。据说其Cpu模式是双流水线,所以前后匹配的指令执行起来更快。)

呵呵,这个我从今天开始可能就没时间了,你自己试着去优化吧[:)]
这个优化,还是得依靠具体的Cpu,具体的指令手册,我就爱默能助了
 
接受答案了.
 
后退
顶部