Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Основная";
Текущий архив: 2005.08.07;
Скачать: [xml.tar.bz2];

Вниз

Замена 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;
Скачать: [xml.tar.bz2];

Наверх





Память: 0.49 MB
Время: 0.035 c
4-1118325354
Андрей Жук
2005-06-09 17:55
2005.08.07
Какой функцией можно получить параметры памяти процесса


1-1121349544
webpauk
2005-07-14 17:59
2005.08.07
запись картинок из ImageList


1-1121440987
lookin
2005-07-15 19:23
2005.08.07
Где должен оказаться Splitter?


14-1121313940
Некто
2005-07-14 08:05
2005.08.07
Какие компьютеры у вас (дом, работа)?


14-1121262293
Pil
2005-07-13 17:44
2005.08.07
Где взять документацию для XLReport на русском языке?





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский