Форум: "Прочее";
Текущий архив: 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.057 c