Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2005.08.07;
Скачать: CL | DM;

Вниз

Замена Move для маленьких объёмов данных.   Найти похожие ветки 

 
MegaVolt ©   (2005-07-20 16:01) [0]

Вот решил потестировать как работает Move для маленьких объёмов данных в данном случае для перемещения одного байта. Получил любопытные результаты:
Стандартная Move 7,35 сек
Move1 1,06 сек
Move2 1,15 сек
Move3 1,06 сек
Move4 1,15 сек

1. Почему изменение типа к которому я привожу данные влияет на результат?
2. Есть ли ещё более оптимальные методы?

Вот код:

unit Unit1;

interface

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

type
 TForm1 = class(TForm)
   Button1: TButton;
   procedure FormCreate(Sender: TObject);
   procedure Button1Click(Sender: TObject);
 private
   { Private declarations }
 public
   { Public declarations }
 end;

 TBA = array of byte;

 TBA2 = array [0..Maxint-1] of byte;

var
 Form1: TForm1;
 z: array [0..32767] of byte;

implementation

{$R *.DFM}

procedure TForm1.FormCreate(Sender: TObject);
var
 i:integer;
begin
 for i:=0 to 32767 do z[i]:=i;
end;

procedure move1(const Source; var Dest; Count: Integer);
var
 i:integer;
begin
 for i:=0 to Count-1 do
   TByteArray(Dest)[i]:=TByteArray(Source)[i];
end;

procedure move2(const Source; var Dest; Count: Integer);
var
 i:integer;
begin
 for i:=0 to Count-1 do
   TBA(@Dest)[i]:=TBA(@Source)[i];
end;

procedure move3(const Source; var Dest; Count: Integer);
var
 i:integer;
begin
 for i:=0 to Count-1 do
   TBA2(Dest)[i]:=TBA2(Source)[i];
end;

procedure move4(const Source; var Dest; Count: Integer);
var
 i:integer;
begin
 for i:=0 to Count-1 do
   PChar(@Dest)[i]:=PChar(@Source)[i];
end;

procedure Read(var Buffer; Count,ind:integer);
begin
 move4(z[ind],Buffer,Count);
end;

procedure TForm1.Button1Click(Sender: TObject);
var
 i,j,time:integer;
 b:byte;
begin
 time:=0;
 Dec(time,GetTickCount);
 for j:=0 to 1000 do
   for i:=0 to 32767 do
     begin
       Read(b,1,i);
       if b<>byte(i) then showmessage(IntToStr(b)+"<>"+IntToStr(i));
     end;
 Inc(time,GetTickCount);
 ShowMessage(IntToStr(time));
end;

end.


 
MBo ©   (2005-07-20 16:09) [1]

http://dennishomepage.gugs-cats.dk/FastCodeProject.htm
http://dennishomepage.gugs-cats.dk/Libraries.htm


 
PVOzerski ©   (2005-07-20 16:17) [2]

Замечание к реализации: не надо связываться с динамическими массивами, если хотим получить бОльшую скорость. А уж работать с ними вот так (неявно приводя статические массивы к динамическим) просто не следует.

Еще одно замечание: в Win32 задействуются 4-байтные регистры и такое же выравнивание, и не использовать это обстоятельство, занимаясь побайтовым копированием - вряд ли лучшее решение.

Вопросы к оптимизации:
1) Интересно, а что будет, если описать диапазоны массивов начинающимися не с нуля, а с единицы? Может, тогда в теле функции и вычитать не придется.
2) А если просто привести pointer к cardinal и начать к нему прибавлять вместо адресации по индексам?


 
Anatoly Podgoretsky ©   (2005-07-20 16:20) [3]

PVOzerski ©   (20.07.05 16:17) [2]
2) А если просто привести pointer к cardinal и начать к нему прибавлять вместо адресации по индексам?

Не трожь адресную математику, а то он такого натворит.


 
MegaVolt ©   (2005-07-20 16:29) [4]

MBo спасибо эти странички я уже нашел предварительно порывшись по интеу. Но там куча ассемблера :( а я в нём не силён :(

PVOzerski
>А уж работать с ними вот так просто не следует.

Это в данном конкретном случае принимающий массив байт. А если принимающий массив не байт а динамический массив?

>в Win32 задействуются 4-байтные регистры

А что делать если действительно нужна побайтная обработка? Или всё равно читать по 4 байта а потом цикл от 1 до 4 крутить?

>А если просто привести pointer к cardinal и начать к нему прибавлять вместо адресации по индексам?

Что то вроде этого?

procedure move5(const Source; var Dest; Count: Integer);
var
 i:integer;
begin
 for i:=0 to Count-1 do
   byte(pointer(Cardinal(@Dest)+i)^):=byte(pointer(Cardinal(@Source)+i)^);
end;


Получил время 2,2 сек :(


 
MegaVolt ©   (2005-07-20 16:33) [5]

Удалено модератором
Примечание: В персональную почту


 
Anatoly Podgoretsky ©   (2005-07-20 16:39) [6]

MegaVolt ©   (20.07.05 16:29) [4]
Что то вроде этого?
byte(pointer(Cardinal(@Dest)+i)^):=byte(pointer(Cardinal(@Source)+i)^);

Тебе разве советовали складывать с индексом, как раз на оборот


 
PVOzerski ©   (2005-07-20 16:40) [7]

procedure move5(const Source; var Dest; Count: Integer);
var
i:integer;
p1, p2: pointer;
c1: cardinal absolute p1;
c2: cardinal absolute p2;
begin
p1 := @Source;
p2 := @dest;
for i:=1 to Count do
  begin
    byte(p2^) := byte(p1^);
    inc(c1);
    inc(c2);
  end;

end;


 
MegaVolt ©   (2005-07-20 16:40) [8]

Удалено модератором
Примечание: Личная переписка


 
han_malign ©   (2005-07-20 16:43) [9]

на вскидку

TByteArray(Source)[i] - обращение к ячейке памяти по индексированному адресу
примерно так:
mov edx, @Source
mov ecx, i
mov AL, [edx+ecx] ; сложение выполняется специальным индексным блоком процессора - без затрат

PChar(@Source)[i] (по симантике соответсвует (PChar(@Source)+i)^)
- сложение адреса + обращение
примерно так:
mov edx, @Source
add edx, i       ;!!!
mov AL, [edx]
хотя тут компилятор может и оптимизировать до предыдущего варианта

отсюда разница - 1,06 / 1,15

move2 - вообще криминал

move - проверка перекрытия блоков(самое длительное) + загрузка EDI, ESI + проверка шага(4/1), копирование - само собой, для исчезающе малых объемов данных, это не выгодно(когда можно PDWORD()^:=PDWORD()^ (PWORD, PBYTE) - за две asm-операции)

moveX - в данном случае(count = 1) - проверка (Count > 0) + описанное выше + проверка (Count > 0)

отсюда разница - 7,35 / 1,06..1,15


короче пройдись в CPU View и все поймешь
реализацию movе можно посмотреть в System.pas

З.Ы. для непересекающихся блоков памяти рекомендуется пользовать copy() - и будет всем щастье


 
MegaVolt ©   (2005-07-20 16:43) [10]

PVOzerski Move5 1,7 сек :(


 
MegaVolt ©   (2005-07-20 16:49) [11]

han_malign спасибо за подробный разбор.

Вот только несколько вопросов:
1. TByteArray(Source)[i] не делает проверки на выход за 32К? Ведь в оригинале TByteArray = array [0..32767] of byte.

2. В чём криминал move2? Ведь у меня Dest может быть и динамическим массивом

3. >для непересекающихся блоков памяти рекомендуется пользовать copy()

А что делать если может возникнуть ситуация когда Dest заполняется за несколько вызовов Read?


 
PVOzerski ©   (2005-07-20 16:55) [12]

1) Должно зависеть от {$R+/-}
2) Если ты передал статический массив, у него нет скрытого заголовка, свойственного массивам динамическим.


 
MegaVolt ©   (2005-07-20 16:59) [13]

PVOzerski
>2) Если ты передал статический массив, у него нет скрытого заголовка, свойственного массивам динамическим.

А если DEST является куском реального динамического массива причём не с середины то TByteArray(Dest) это корректно будет?


 
Anatoly Podgoretsky ©   (2005-07-20 17:04) [14]

MegaVolt ©   (20.07.05 16:59) [13]
А если DEST является куском реального динамического массива причём не с середины то TByteArray(Dest) это корректно будет?

Корректно, если не будешь выходить за границы.


 
MegaVolt ©   (2005-07-20 17:09) [15]

Anatoly Podgoretsky
>Корректно, если не будешь выходить за границы.

Ок. Спасибо.
А есть способы ещё ускорить работу по сравнению с Move1?


 
REA   (2005-07-20 17:37) [16]

>2) А если просто привести pointer к cardinal и начать к нему прибавлять вместо адресации по индексам?

приводить ничего не надо, можно просто Inc(PByte), но выигрыш от этого небольшой. Можно организовать цикл downto - будет небольшой выигрыш, но видимо не на всех процессорах.



Страницы: 1 вся ветка

Текущий архив: 2005.08.07;
Скачать: CL | DM;

Наверх




Память: 0.51 MB
Время: 0.046 c
1-1121719168
sybrex
2005-07-19 00:39
2005.08.07
За что отвечает свойство объекта owner, а за что parent?


14-1121643366
Мутамба
2005-07-18 03:36
2005.08.07
Правда ли что на Украине какой-то батюшка предал анафиме модерато


1-1121319843
silvestr
2005-07-14 09:44
2005.08.07
Вывод надписи на поверх всех окон


4-1118176862
ATarget
2005-06-08 00:41
2005.08.07
Узнать какие dll - ки запрашивает ехе-шник


8-1112626691
Charly22
2005-04-04 18:58
2005.08.07
Создание эскизов графических файлов