![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
Pointer->Integer->Pointer
alertus © (2005-05-27 17:36:00)Подскажите, пожалуйста, если я пишу так:
a:^real;
p:^real;
....
getmem(a,100*sizeof(real));
p:=pointer(integer(a)+0);
p^:=0.347;
p:=pointer(integer(a)+8);
p^:=0.764;
p:=pointer(integer(a)+16);
p^:=0.764;
....
Похоже ли это на работу динамического массива и какова будет разница в скорости??
ZlDoc (2005-05-28 00:09:00) [41]Народ чет вы все похоже на высоком уровне засиделись (хоть я сам на асьме не профи). Но скажу, что смотреть длинну команды или прогонять Mov в цикле For (да еще и с вызовом процедуры), это както не по научному. имхо.
Время выполнения команды надо тактами процессора измерять (они в старых учебниках по процессорам написаны). Процессор такая вещ что состояние может тока раз в такт менять. Следовательно, чтоб выполнить mov eax, [I + ESP + ECX], ему надо несколько тактов чтоб I + ESP + ECX посчитать, а потом mov выполнить.
Так что и без тестов сказать можно что быстрее выполниться (тем более смотрю никак в результатах не сойдетесь)
PS. Быстрее ассемблера ничего не придумали...
Marser (2005-05-27 23:50:00) [42]
> Defunct © (27.05.05 21:10) [35] [Новое
>сообщение][Ответить]
>begin...end © (27.05.05 20:58) [31]
>
> > Ваш код я видоизменил: вместо ламерского способа
> измерения времени выполнения кода функцией использовал
>GetTickCount,
>
> Вам не стыдно такое писать?
Действительно ламерство. Если б ты предложил QueryPerformanceTimer, то это дело. Но TDateTime с сопутствующими - истинная черепаха.
Твоя проблема, ИМХО, в том, что глубочайшие знания у тебя соседствуют с пробелами чуть ли не в табличке умножения.
Defunct (2005-05-27 23:45:00) [43]Anatoly Podgoretsky © (27.05.05 22:27) [38]
Нет скорее это не влияние цикла вызова и возврата а особенность работы P3, для которого более сложная иструкция (читать более большая), тратит больше времени на погдотовку, потому что за результат [30] я ручаюсь со всей ответственностью.
begin...end © (27.05.05 21:37) [36]
Промолчу, если вы заметили, я уже стараюсь с вами не спорить.
begin...end © (27.05.05 22:12) [37]
Предполагаю, что на P3 тормозит не умножение индекса, а наличие постоянной константы, которое значительно раздувает размер команды. Для получение объективного результата проверьте в равных условиях команды
mov eax, [I + ESP + ECX*8]
и
mov eax, [I + ESP + ECX]
т.е. сугубо наличие умножения индекса.
Anatoly Podgoretsky (2005-05-27 22:27:00) [44]Вот оно влияние цикла, вызова и возврата из подпрограммы. А казалось бы безобидный с виду тест.
begin...end (2005-05-27 22:12:00) [45]Воспользовался "методом устранения ошибки" из [30]. Теперь функции содержат по 100 команд MOV: в Test -- команды вида
mov eax, [I + ESP + ECX*8], где I -- целочисленные константы от 0 до 99, а в Test2 --mov eax, [ESP + ECX].
В связи с малой производительностью процессора пришлось уменьшить число итераций до 200 миллионов, иначе я бы заснул в ожидании результатов. А результаты впечатляют:
С умножением -- 84520
Без умножения -- 46480
"Выводы построите сами" (c) Defunct
begin...end (2005-05-27 21:37:00) [46]> Defunct © (27.05.05 21:05) [34]
> Я прекрасно знаю насколько объективно, именно Вы относитесь
> к моим постам
Вы своими постами заслужили такое отношение. Поэтому смело можете сказать спасибо зеркалу.
> забыли выключить оптимизацию
Не совсем понятно, каким образом опция оптимизации может повлиять на код самих asm-функций, но, раз уж Вы об этом упомянули, я повторил тест с отключённой оптимизацией.
Результаты таковы:
С умножением -- 37974
Без умножения -- 34750
Уж и не знаю, что нужно сделать, чтобы вариант с умножением выиграл. Может, с бубном возле компьютера поплясать?
> > Кстати, обратите внимание на количество хинтов компилятора
> Обратил - ни одного hint'a либо warning'a.
Это у Вас что-то с компилятором. А может быть, Вы просто отключили показ хинтов? Приведу список хинтов, возникших на Delphi 7 (конечно, с первого раза код [28] откомпилировать не удалось -- пришлось добавить объявления перменных T1, T2 и T3):
[Hint] Unit1.pas(75): Value assigned to 'T2' never used
[Hint] Unit1.pas(70): Value assigned to 'E2' never used
[Hint] Unit1.pas(67): Value assigned to 'E1' never used
[Hint] Unit1.pas(58): Value assigned to 'T3' never used
[Hint] Unit1.pas(56): Value assigned to 'E2' never used
[Hint] Unit1.pas(54): Value assigned to 'E1' never used
Если выключить оптимизацию, то количество хинтов уменьшается до двух, но они есть.
> Defunct © (27.05.05 21:10) [35]
Не стыдно.
Defunct (2005-05-27 21:10:00) [47]begin...end © (27.05.05 20:58) [31]
> Ваш код я видоизменил: вместо ламерского способа измерения времени выполнения кода функцией использовал GetTickCount,
Вам не стыдно такое писать?
Defunct (2005-05-27 21:05:00) [48]begin...end © (27.05.05 20:58) [31]
Я прекрасно знаю насколько объективно, именно Вы относитесь к моим постам, но в этот раз ничего у Вас не выйдет. LOL оставьте себе, раз забыли выключить оптимизацию.
> Кстати, обратите внимание на количество хинтов компилятора
Обратил - ни одного hint'a либо warning'a.
alertus (2005-05-27 21:02:00) [49]Наваял такую программу:
function writems:string;
var
t:TDateTime;
h,m,s,ms:word;
begin
t:=Time;
DecodeTime(t, h, m, s, ms);
result:=inttostr(s)+'.'+inttostr(ms);
end;
procedure TForm1.Button5Click(Sender: TObject);
var
a:^real; //311x700
b:^real; //700x311
c:^real; //311x311
i,j,k:integer;
p:^real;
pa,pb,pc:^real;
temp:real;
begin
getmem(a,311*700*sizeof(real));
getmem(b,311*700*sizeof(real));
getmem(c,311*311*sizeof(real));
memo1.lines.add(writems);
for i:=1 to 311 do begin
for j:=1 to 311 do begin
temp:=0;
p:=integer(0);
for k:=1 to 700 do begin
pa:=pointer(integer(a)+(i-1)*311+integer(p));
pb:=pointer(integer(b)+(j-1)*311+integer(p));
temp:=temp+pa^*pb^;
inc(p);
end;
pc:=pointer(integer(c)+(i-1+(j-1)*311)*sizeof(real));
pc^:=temp;
end;
end;
memo1.lines.add(writems);
end;
Время умножения - 1.2 с, прежний метод 3.2 с, метод с использованием a:array[0..0] - 3.0 с (до этого про 4.0 было неверно, я брал другой размер матрицы и перепутал).
т.к. у меня в программе матрица 1 это транспонированная матрица 2, то, я думаю, можно сократить еще время, т.к. у матрицы-результата под нижней диагональю зеркальное отражение того, что над верхней диагональю, но время сократиться еще не более чем в 2 раза.
Очень помогли советы
MBo © (27.05.05 18:41) [15] и
begin...end © (27.05.05 19:06) [20], всем огромное спасибо.
begin...end (2005-05-27 20:59:00) [50]
> времени выполнения кода функцией
времени выполнения кода функцией Now
begin...end (2005-05-27 20:58:00) [51]> Defunct © (27.05.05 19:57) [28]
> тот код который вы приводите я не понимаю
Сорри, но я ничего не могу с этим поделать.
> Это какой-то набор значков.
LOL. Любой листинг программного кода -- это набор значков.
> Не знаю что вы там в нем меряли.
Времена выполнения двух вариантов кода.
Ваш код я видоизменил: вместо ламерского способа измерения времени выполнения кода функцией использовал GetTickCount, хотя это тоже не лучший способ.
var
i : integer;
T1, T2, T3: Cardinal;
E1, E2 : Integer;
begin
T1 := GetTickCount;
for i := 0 to 2000*1000*1000 do
begin
E1 := Test;
end;
E2 := E1;
T3 := E2*T1;
T2 := GetTickCount;
ShowMessage('С умножением: '+ IntToStr(T2 - T1));
T1 := GetTickCount;
for i := 0 to 2000*1000*1000 do
begin
E1 := Test2;
end;
E2 := E1;
T2 := GetTickCount;
ShowMessage( 'Без умножения: '+ IntToStr(T2 - T1));
T2 := E2*T2;
end
Кстати, обратите внимание на количество хинтов компилятора, указывающих на выкинутые им строчки. Это свидетельствует о том, что бессмысленных значков в Вашем коде намного больше, чем в моём.
Результаты проверки таковы (на Pentium 3):
С умножением -- 30304
Без умножения -- 25947
Чуда не произошло, что мной и ожидалось.
Defunct (2005-05-27 20:51:00) [52]Anatoly Podgoretsky © (27.05.05 20:12) [29]
Спасибо за метод устранения ошибки.
В общем картина такая.
1. выключил оптимизацию.
2. функция test
приняла такой вид:
xor ecx, ecx
mov eax, [0 + ESP + ECX*8]
...
mov eax, [99 + ESP + ECX*8]
3. Функция test2 такой:
xor ecx, ecx
mov eax, [ESP]
...
mov eax, [ESP]
по сотне команд в обеих функциях. Циклы остались такими же - по 2млрд итераций.
Результаты выполнения теста на P4:
1-й запуск:
с умножением без умножения
44.581с 44.565с
2-й запуск
с умножением без умножения
44.518с 44.518с
3-й запуск
с умножением без умножения
44.518с 44.518с
Выводы постоите сами ;>
Anatoly Podgoretsky (2005-05-27 20:12:00) [53]Чего результаты то не привел, ну зачем же каждому компилировать. Кроме того тест желательно оптимизировать, что бы уменьши погрешность от цикла и команд вызова/возврата. это делается так
mov eax, [ESP + ECX*8]
... повторения строки от 100 раз и более
mov eax, [ESP + ECX*8]
Defunct (2005-05-27 19:57:00) [54]begin...end © (27.05.05 19:53) [26]
Да я уже проверил, а тот код который вы приводите я не понимаю. Это какой-то набор значков. Не знаю что вы там в нем меряли.
function test:integer;
var
a : array[0..100] of byte;
asm
xor ecx, ecx
mov eax, [ESP + ECX*8]
end;
function test2:integer;
var
a : array[0..100] of byte;
asm
xor ecx, ecx
mov eax, [ESP + ECX]
end;
procedure TForm1.rClick(Sender: TObject);
var
i : integer;
E1, E2 : Integer;
begin
T1 := Now;
for i := 0 to 2000*1000*1000 do
begin
E1 := Test;
end;
E2 := E1;
T3 := E2*T1;
T2 := Now;
ShowMessage('С умножением '+ FormatDateTime('nn:ss:zzz', T2 - T1));
T1 := Now;
for i := 0 to 2000*1000*1000 do
begin
E1 := Test2;
end;
E2 := E1;
T2 := Now;
ShowMessage( 'Без умножения '+ FormatDateTime('nn:ss:zzz', T2 - T1));
T2 := E2*T2;
end;
Defunct (2005-05-27 19:55:00) [55]> begin...end
> сколько в облегчении вычисления индексов.
Вот например это вообще теряет смысл, если проц. и так умеет перемножать индексные регистры непосредственно при адресации элемента массива.
т.е. доступно даже такое
mov eax, [CONST + ebx + ecx*8]
и эта команда будет выполняться одинаково быстро с командой
mov eax, [ebx]
begin...end (2005-05-27 19:53:00) [56]> Defunct © (27.05.05 19:48) [25]
А Вы, надо полагать, уже проверили?
type
TElemType = Integer;
PElemType = ^TElemType;
const
ElemsCount = 10000000;
var
a: Pointer;
p: PElemType;
T1, T2, I: Cardinal;
begin
GetMem(a, ElemsCount * sizeof(TElemType));
p := a;
T1 := GetTickCount;
for I := 0 to Pred(ElemsCount) do
PElemType(Integer(p) + I * sizeof(TElemType))^ := 1;
T1 := GetTickCount - T1;
p := a;
T2 := GetTickCount;
for I := 0 to Pred(ElemsCount) do
begin
p^ := 1;
Inc(p)
end;
T2 := GetTickCount - T2;
Caption := Format('Умножение: %d; сложение: %d', [T1, T2]);
FreeMem(a)
end.
"Чуешь Тайд?" (c) Defunct
Defunct (2005-05-27 19:48:00) [57]begin...end © (27.05.05 19:10) [22]
Ну и ничего,
прежде чем сразу спорить возьми и проверь по скорости
mov eax, [ebx + ecx]
и
mov eax, [ebx + ecx*8]
оно рульно будет (С) begin...end
alertus (2005-05-27 19:41:00) [58]Да, я согласен, я думал, что sizeof(real) тормозит программу, но это как-бы константа, поэтому лучше писать
p:=pointer(integer(a)+sizeof(real));
> begin...end © (27.05.05 19:06) [20]
насчет наращивания адреса, похоже, очень дельный совет.
А еще такой вопрос:
если я по очереди обращаюсь к нескольким элементам памяти, зависит ли скорость от расстояния между этими физическими адресами??
Anatoly Podgoretsky (2005-05-27 19:12:00) [59]p:=pointer(integer(a) +8 );
Так не допустимо, размер Real не 8, а величина переменная, но даже если бы и постоянно, то это все равно выглядит некрасиво.
begin...end (2005-05-27 19:10:00) [60]> Defunct © (27.05.05 19:08) [21]
Ну и что? Речь-то не о возможности, а о скорости.