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

Вниз

Можно ли как то оптимизировать данный участок кода   Найти похожие ветки 

 
DVM ©   (2007-05-08 14:42) [0]


type
 
 PFColor =^TFColor;
 TFColor = packed record
   b,g,r: Byte;
 end;

 TMatrixItem = record
   Blue: Cardinal;
   Green: Cardinal;
   Red: Cardinal;
   Sum: Cardinal;
 end;
 PMatrixItem = ^TMatrixItem;

var
 pmi: PMatrixItem;
 pc: PFColor;

//------------------------

 inc(pmi^.blue, pc^.b);
 inc(pmi^.green, pc^.g);
 inc(pmi^.red, pc^.r);
 inc(pmi^.sum);
 Inc(pc);

//-------------------------

Отчеркнутый фрагмент выполняется сотни тысяч раз. Можно ли как ускорить эти операции?


 
Ega23 ©   (2007-05-08 14:52) [1]

На асме его написать?


 
DVM ©   (2007-05-08 14:53) [2]


> На асме его написать?

Не владею в такой степени, чтобы обставить компилятор Delphi в плане скорости.


 
X9 ©   (2007-05-08 14:55) [3]

Большой разницы между данным фрагментом (при использовании оптимизации) и его ASM-вариантом быть не должно.


 
DVM ©   (2007-05-08 14:56) [4]

Тут прямо хочется как-то одним действием увеличить все три переменных blue, green, red :)


 
MBo ©   (2007-05-08 14:59) [5]

>одним действием увеличить все три переменных blue, green, red :)
для этого MMX можно использовать, но накладные расходы на подготовку данных будут значительны, так что выигрыша может и не быть


 
X9 ©   (2007-05-08 14:59) [6]

Одним действие не получится, ибо 3 cardinal в один 32-битный регистр не поместятся. А почему именно Cardinal? Если это RGB, то Byte хватит за глаза. А если Byte, то уже есть возможность немного схитрить.


 
DVM ©   (2007-05-08 15:02) [7]


> А почему именно Cardinal?

Вычисляется средний цвет прямоугольного фрагмента изображения.

Cardinal - это суммы значений точек в клетке по каналам.

Так сделано для ускорения работы - после суммирования всех точек в клетке вычисляется средний цвет один раз.


 
MBo ©   (2007-05-08 15:31) [8]

var
ca: array of TFColor;
mi: TMatrixItem;
pc: PFColor;
i, N: Integer;
t: DWord;
begin
N := 1024*1024*64;
SetLength(ca, N);
FillChar(mi, SizeOf(mi), 0);
pc := @ca[0];
t := GetTickCount;
for i := 0 to N - 1 do begin
  inc(mi.blue, pc^.b);
  inc(mi.green, pc^.g);
  inc(mi.red, pc^.r);
  inc(mi.sum);
  Inc(pc);
end;
Caption := IntToStr(mi.Sum + mi.Blue +mi.Green +mi.Red) +" " + IntToStr(GetTickCount - t);
end;


Хм... Этот код для 64 мегапикселов (192 мегабайта) выполняется у меня за 453 мс, т.е. скорость обработки 150 мегапикселов в секунду. Мало? ;)


 
Rouse_ ©   (2007-05-08 15:34) [9]

type
PFColor =^TFColor;
TFColor = packed record
  b,g,r: Byte;
end;

TMatrixItem = record
  Blue: Cardinal;
  Green: Cardinal;
  Red: Cardinal;
  Sum: Cardinal;
end;
PMatrixItem = ^TMatrixItem;

procedure ModifyMatrix(MatrixItems: PMatrixItem; Color: PFColor;
 const MatrixItemsCount: Integer); assembler;
asm
 push eax
 push ebx
 push ecx
 push edx
 push edi
 push esi

 mov  esi, eax // MatrixItems
 mov  bx, [edx]
 mov  dl, [edx + 2] // Color

@loop:
 mov eax, [esi]
 add al, bl
 mov [esi], eax
 mov eax, [esi + 4]
 add al, bh
 mov [esi + 4], eax
 mov eax, [esi + 8]
 add al, dl
 mov [esi + 8], eax
 inc [esi + 12]
 add esi, 16
 loop @loop

 pop  esi
 pop  edi
 pop  edx
 pop  ecx
 pop  ebx
 pop  eax
end;

procedure TForm5.Button1Click(Sender: TObject);
var
 pmi, pmiTmp: PMatrixItem;
 pc: TFColor;
 I: Integer;
begin
 GetMem(pmi, SizeOf(TMatrixItem) * 4);
 try
   pc.b := 10;
   pc.g := 20;
   pc.r := 30;
   pmiTmp := pmi;
   for I := 1 to 4 do
   begin
     pmiTmp^.Blue := I * 10;
     pmiTmp^.Green := I * 11;
     pmiTmp^.Red := I * 12;
     pmiTmp^.Sum := I * 13;

     Memo1.Lines.Add(Format("%d.%d.%d.%d",
       [pmiTmp^.Blue, pmiTmp^.Green, pmiTmp^.Red, pmiTmp^.Sum]));

     Inc(pmiTmp);
   end;
   ModifyMatrix(pmi, @pc, 4);
   pmiTmp := pmi;
   for I := 0 to 3 do
   begin
     Memo1.Lines.Add(Format("%d.%d.%d.%d",
       [pmiTmp^.Blue, pmiTmp^.Green, pmiTmp^.Red, pmiTmp^.Sum]));
     Inc(pmiTmp);
   end;
 finally
   FreeMem(pmi);
 end;
end;


 
DVM ©   (2007-05-08 15:35) [10]


> Мало? ;)

Я детектор движения пишу. Сейчас скорость 500 fps при размере кадра 640*480 на одном ядре. Цель -1000 FPS. Но видимо в этом участе кода уже предел - буду другие места мучить. :)


 
Rouse_ ©   (2007-05-08 15:38) [11]

Не вот так проще:

procedure ModifyMatrix(MatrixItems: PMatrixItem; Color: PFColor;
 const MatrixItemsCount: Integer); assembler;
asm
 push eax
 push ebx
 push ecx
 push edx

 mov  bx, [edx]
 mov  dl, [edx + 2]

@loop:
 add [eax], bl
 add [eax + 4], bh
 add [eax + 8], dl
 inc [eax + 12]
 add eax, 16
 loop @loop

 pop  edx
 pop  ecx
 pop  ebx
 pop  eax
end;


 
DVM ©   (2007-05-08 15:52) [12]


> Rouse_ ©   (08.05.07 15:38) [11]

У меня цикл с 1 а не с нуля


 
Rouse_ ©   (2007-05-08 15:53) [13]

А этому коду пофигу... Он знает размер буффера и начальный адрес буффера. Хоть с десятки начинай


 
DVM ©   (2007-05-08 16:00) [14]


> Rouse_ ©   (08.05.07 15:53) [13]

Тогда че-то не так

Было и работает:


for cy := 1 to ty do
     begin
       for cx := 1 to tx do
       begin
         inc(pmi^.blue, pc^.b);
         inc(pmi^.green, pc^.g);
         inc(pmi^.red, pc^.r);
         Inc(pc);
       end;
       inc(integer(pc), Delta);
     end;
     pmi^.sum := ty * tx;


Стало, но не работает:


  for cy := 1 to ty do
    begin
        ModifyMatrix(pmi, pc, tx);
        inc(integer(pc), Delta);
     end;
   pmi^.sum := ty * tx;


 
DVM ©   (2007-05-08 16:10) [15]


> > Rouse_ ©

У тебя в цикле на ASM вроде указатель pc не сдвигается.


 
Rouse_ ©   (2007-05-08 16:11) [16]

Пропустил что второй параметр у тебя тоже массив :)
Тогда:

procedure ModifyMatrix(MatrixItems: PMatrixItem; Color: PFColor;
 const MatrixItemsCount: Integer); assembler;
asm
 push eax
 push ebx
 push ecx
 push edx

@loop:
 mov  bx, [edx]
 add [eax], bl
 add [eax + 4], bh
 mov bl, [edx + 2]
 add [eax + 8], bl
 inc [eax + 12]
 add eax, 16
 add edx, 3
 loop @loop

 pop  edx
 pop  ecx
 pop  ebx
 pop  eax
end;


 
DVM ©   (2007-05-08 16:11) [17]

Не я неправ, все на месте


 
Rouse_ ©   (2007-05-08 16:13) [18]

Эээ, погоди. Вот это не то что было в начале:

for cy := 1 to ty do
    begin
      for cx := 1 to tx do
      begin
        inc(pmi^.blue, pc^.b);
        inc(pmi^.green, pc^.g);
        inc(pmi^.red, pc^.r);
        Inc(pc);
      end;
      inc(integer(pc), Delta);
    end;
    pmi^.sum := ty * tx;


 
Rouse_ ©   (2007-05-08 16:15) [19]

короче на пальцах...
Мой код принимает на вход два массива PMatrixItem и PFColor, каждый цветовой элемент первого массива увеличивается на значение цвета из второго массива а pmi^.sum просто увеличивается на единицу... Оно?


 
DVM ©   (2007-05-08 16:16) [20]


> Эээ, погоди. Вот это не то что было в начале:

Да, я знаю, я поправил твой код там одна строка лишняя получается, но все равно не фурычит че-то.

Я так понял твоя функция это замена внутреннего цикла?


 
Rouse_ ©   (2007-05-08 16:17) [21]

угу


 
DVM ©   (2007-05-08 16:19) [22]


> Оно?

Оно вроде. pmi^.sum  можно выкинуть из цикла оно и так рассчитывается.


 
DVM ©   (2007-05-08 16:21) [23]


> угу

Или я че-то непонимаю, но в результате замены все работает не так как ранее.


 
Rouse_ ©   (2007-05-08 16:22) [24]

Ну я как твою задачу понял - так ее и реализовал :)
Либо неверно я понял, либо ты ее неверно описал :)


 
DVM ©   (2007-05-08 16:24) [25]

Короче вот:

Было:


     for cy := 1 to ty do
     begin
      //ModifyMatrix(pmi, pc, tx);
       for cx := 1 to tx do
       begin
         inc(pmi^.blue, pc^.b);
         inc(pmi^.green, pc^.g);
         inc(pmi^.red, pc^.r);
         pmi^.sum := ty * tx;
         Inc(pc);
       end;
       inc(integer(pc), Delta);
     end;
     


Меняем:


     for cy := 1 to ty do
     begin
       ModifyMatrix(pmi, pc, tx);
       //for cx := 1 to tx do
       //begin
         //inc(pmi^.blue, pc^.b);
         //inc(pmi^.green, pc^.g);
         //inc(pmi^.red, pc^.r);
         //pmi^.sum := ty * tx;
         //Inc(pc);
       //end;
       inc(integer(pc), Delta);
     end;
     


Где:

procedure ModifyMatrix(MatrixItems: PMatrixItem; Color: PFColor;
const MatrixItemsCount: Integer); assembler;
asm
push eax
push ebx
push ecx
push edx

@loop:
mov  bx, [edx]
add [eax], bl
add [eax + 4], bh
mov bl, [edx + 2]
add [eax + 8], bl
inc [eax + 12]
add eax, 16
add edx, 3
loop @loop

pop  edx
pop  ecx
pop  ebx
pop  eax
end;


Не работает.


 
DVM ©   (2007-05-08 16:25) [26]

pmi^.sum := ty * tx;

только надо убрать в первом коде


 
Rouse_ ©   (2007-05-08 16:26) [27]

А, ну тогда естественно не так...
Сек...


 
Rouse_ ©   (2007-05-08 16:29) [28]

Вот это закоментрарь:

 //inc [eax + 12]
 //add eax, 16


 
DVM ©   (2007-05-08 16:33) [29]

Один фиг, смотри:

Постараюсь без неточностей:

Было:

     for cy := 1 to ty do
     begin
       //ModifyMatrix(pmi, pc, tx);
       for cx := 1 to tx do
       begin
         inc(pmi^.blue, pc^.b);
         inc(pmi^.green, pc^.g);
         inc(pmi^.red, pc^.r);
         Inc(pc);
       end;
       inc(integer(pc), Delta);
     end;
     pmi^.sum := ty * tx;

Стало:



    for cy := 1 to ty do
     begin
       ModifyMatrix(pmi, pc, tx);
       inc(integer(pc), Delta);
     end;
     pmi^.sum := ty * tx;



Где:


procedure ModifyMatrix(MatrixItems: PMatrixItem; Color: PFColor;
const MatrixItemsCount: Integer); assembler;
asm
push eax
push ebx
push ecx
push edx

@loop:
mov  bx, [edx]
add [eax], bl
add [eax + 4], bh
mov bl, [edx + 2]
add [eax + 8], bl
//inc [eax + 12]
//add eax, 16
add edx, 3
loop @loop

pop  edx
pop  ecx
pop  ebx
pop  eax
end;


Это не одно и то же выходит.


 
Rouse_ ©   (2007-05-08 16:37) [30]

Ты лучше результаты первого и второго покажи... Что у тебя на входе находится в pmi^ и на выходе в момент выполнения inc(integer(pc), Delta);


 
DVM ©   (2007-05-08 16:47) [31]


> Rouse_ ©

А какая строка в твоем коде отвечает за количество оборотов цикла?


 
Rouse_ ©   (2007-05-08 16:49) [32]

const MatrixItemsCount: Integer
Указывает на размер буффера во втором параметре. т.е. кол-во элементов типа ТFColor


 
DVM ©   (2007-05-08 16:54) [33]


> Rouse_ ©   (08.05.07 16:49) [32]

Теперь мне все понятно, подумаю сам дальше. Твоя функция на 10% быстрее вроде как чем мой код на паскале, но почему то дает ложные срабатывания детектора, т.е. в pmi^ где то заносятся левые значения.

Почему - неясно пока.

Результаты тут привести проблематично - я смотрю уже на последствия изменений - когда сравниваются два кадра изображения, сами же значения в pmi^ мне мало о чем скажут. На входе там нули.


 
Rouse_ ©   (2007-05-08 16:56) [34]


> в pmi^ где то заносятся левые значения.

Вероятно размер буффера более меньший, чем указан в третьем параметре...


 
Sapersky   (2007-05-08 17:21) [35]

procedure GetSumA(Src : PFColor; Dst : PMatrixItem; Count : Integer);
asm
 push ebx
 push esi
 push edi
 push edx
 mov esi, eax   // Src -> esi
 mov eax, edx
 mov ebx, [eax] // unpacking Dst to ebx, edx, edi
 mov edx, [eax + 4]
 mov edi, [eax + 8]
@loop:
 movzx eax, byte ptr [esi]
 add ebx, eax // b
 movzx eax, byte ptr [esi + $01]
 add edx, eax // g
 movzx eax, byte ptr [esi + $02]
 add edi, eax // r
 add esi, 3
 dec ecx
jnz @loop
 mov eax, edx
 pop edx
 mov [edx], ebx
 mov [edx + 4], eax
 mov [edx + 8], edi
 pop edi
 pop esi
 pop ebx
end;

pmi.blue, pmi.green, pmi.red хранятся в регистрах, за счёт чего получается существенно быстрее.
Копирайт, скажу честно, принадлежит дельфийскому оптимизатору. Вот это даёт практически аналогичный результат:

procedure GetSum(Src : PFColor; Dst : PMatrixItem; Count : Integer);
Var n, r, g, b : Integer;
begin
b := Dst.Blue; g := Dst.Green; r := Dst.Red;
for n := 0 to Count - 1 do begin
 inc(r, Src.b);
 inc(g, Src.g);
 inc(b, Src.r);
 Inc(Src);
end;
Dst.Blue := b; Dst.Green := g; Dst.Red := r;
end;

но присвоение начальных значений r,g,b занимает один из регистров, и получается немного медленнее. Если присваивать 0 - скорость такая же, как и у asm.


 
DVM ©   (2007-05-08 17:36) [36]


> Sapersky   (08.05.07 17:21) [35]

Вот с твоим вариантом проблем нет - работает нормально.

мой вариант - 450 fps
GetSum 470
GetSumА 550

Вот только непонятен мне посл вариант немного.

PS. Хочу сделать (точнее сделал) детектор движения, как расширение FastDIB.


 
Sapersky   (2007-05-08 19:35) [37]

Вот только непонятен мне посл вариант немного.
Это практически копия CPU window от GetSum.
movzx eax, byte ptr [esi]
это то же самое что и
xor eax, eax
mov al, [esi]
но быстрее, несмотря даже на то, что xor можно вынести из цикла.

Можно вообще избавиться от asm, если использовать GetSum вот в таком варианте:
procedure GetSum(Src : PFColor; Dst : PMatrixItem; Count : Integer);
Var n, r, g, b : Integer;
begin
b := 0; g := 0; r := 0;
for n := 0 to Count - 1 do begin
inc(r, Src.b);
inc(g, Src.g);
inc(b, Src.r);
Inc(Src);
end;
Dst.Blue := b; Dst.Green := g; Dst.Red := r;
end;

Var mi : TMatrixItem;

for cy := 1 to ty do begin
 GetSum(pc, @mi, tx);
 Inc(pmi.blue, mi.blue);
 Inc(pmi.green, mi.green)
 Inc(pmi.red, mi.red);
<...>

скорость должна быть такая же, что и с GetSumA.
Так что ассемблер знать надо, но писать на нём вовсе не обязательно (за исключением MMX/SSE, но это штука весьма специфичная и далеко не всегда применимая).

PS. Хочу сделать (точнее сделал) детектор движения, как расширение FastDIB.

В смысле выложить код? Это можно посмотреть, глядишь, ещё чего оптимизируем.


 
DVM ©   (2007-05-09 13:39) [38]


> Sapersky   (08.05.07 17:21) [35]

А ведь все таки и твоя функция работает не совсем правильно, я сразу и не заметил.

Правильно работает, только если писать так:


procedure GetSum(var Src : PFColor; var Dst : PMatrixItem; Count : Integer);
 Var n, r, g, b : Integer;
begin
 b := Dst.Blue; g := Dst.Green; r := Dst.Red;
 for n := 0 to Count - 1 do
   begin
     inc(r, Src.b);
     inc(g, Src.g);
     inc(b, Src.r);
     Inc(Src);
   end;
 Dst.Blue := b; Dst.Green := g; Dst.Red := r;
end;


но с var медленно очень, в два раза медленнее.


 
DVM ©   (2007-05-09 13:44) [39]


> В смысле выложить код? Это можно посмотреть, глядишь, ещё
> чего оптимизируем.

Да, но сначала его причесать надо, у меня там пока много спорных моментов в плане и скорости и функциональности. Детектор должен быть очень быстрым и несложным - в духе FastDIB. Собственно почти уже готово.


 
DVM ©   (2007-05-09 14:36) [40]

А вот так все работает очень хорошо. Но пришлось отказаться от доп процедуры, ибо доп процедура работает правильно только при указании ключевого слова var, но это медленно.

Итак, было (510 fps):

for cy := 1 to ty do
 begin
   for cx := 1 to tx do
     begin
       inc(pmi^.blue, pc^.b);
       inc(pmi^.green, pc^.g);
       inc(pmi^.red, pc^.r);
       Inc(pc);
     end;
  inc(integer(pc), Delta);
end;


Стало (660 fps):


for cy := 1 to ty do
 begin
   b := 0; g := 0; r := 0;
   for CX := 1 to TX do
     begin
       inc(B, pc^.b);
       inc(g, pc^.g);
       inc(R, pc^.r);
       Inc(PC);
     end;
   mi.Blue := b; mi.Green := g; mi.Red := r;
   Inc(pmi.blue, mi.blue);
   Inc(pmi.green, mi.green);
   Inc(pmi.red, mi.red);
   inc(integer(pc), Delta);
 end;


Код стал странноват, но быстрее на 20 процентов.

Интересно, а еще быстрее можно?



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

Форум: "Прочее";
Текущий архив: 2007.06.03;
Скачать: [xml.tar.bz2];

Наверх





Память: 0.56 MB
Время: 0.043 c
15-1178615955
Jan1
2007-05-08 13:19
2007.06.03
Защита программы от крэка


15-1178168718
Рауф
2007-05-03 09:05
2007.06.03
Перенос БД Paradox на другую машину.


15-1178470182
ArtemESC
2007-05-06 20:49
2007.06.03
Диски FAT в OpenSuse 10.2


15-1178872117
Плохиш
2007-05-11 12:28
2007.06.03
А пофигу мне голубые штаны!!!!


15-1178467183
ArtemESC
2007-05-06 19:59
2007.06.03
OpenSuse 10.2





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
Английский Французский Немецкий Итальянский Португальский Русский Испанский