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

Вниз

Pointer->Integer->Pointer   Найти похожие ветки 

 
alertus ©   (2005-05-27 17:36) [0]

Подскажите, пожалуйста, если я пишу так:

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;
....


Похоже ли это на работу динамического массива и какова будет разница в скорости??


 
Digitman ©   (2005-05-27 17:41) [1]


> Похоже ли это на работу динамического массива


нет, не похоже.


> какова будет разница в скорости


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


 
-=XP=- ©   (2005-05-27 17:45) [2]

Похоже. Но и только.

Лучше использовать не +0, +8, а +SizeOf(pointer) * ItemIndex

А зачем так изголяться? Чем динамические массивы не подошли?
Или конструкция типа:

{$RANGECHECKS OFF}
type
 PRealArray = ^TRealArray;
 TRealArray = array[0..0] of real;
var
 A: PRealArray;
begin
 GetMem(A, 100 * SizeOf(real));
 A^[2] := 0.764;
 ...


 
alertus ©   (2005-05-27 17:47) [3]

Почему не похоже, ведь у меня получился массив из 100 элементов типа real, к каждому из которых я имею доступ.
И если я изначально не знаю размер массива, то я могу его задать в ходе выполнения программы (после мне его менятьт не потребуется).

Я столкнулся с программированием на Matlab, там перемножение двух матриц 300x700 элементов real занимает около 1/4 секунды, а у меня на Delphi с использованием динамических массивов - 4 сек.
Matlab написан на C++, там динамические массивы объявляются так:
float *a.

В общем я хочу ускорить операции с динамическими массивами, судя по Matlab"у это возможно.

Может быть кто-нибудь знает как это запрограммировано на Matlab"е??


 
Digitman ©   (2005-05-27 17:50) [4]


> Почему не похоже


по кочану.

любой дин.тип данных предусматривает упр.структуру ... она у тебя ГДЕ ?


 
alertus ©   (2005-05-27 17:50) [5]


> Лучше использовать не +0, +8, а +SizeOf(real) * ItemIndex


Да, я так и хотел сделать в дальнейшем.

А как насчет скорости или другой реализации??


 
alertus ©   (2005-05-27 17:52) [6]


> любой дин.тип данных предусматривает упр.структуру ... она
> у тебя ГДЕ ?

Меня беспокоит то, что любая управляющая структура уменьшает скорость, я специально делаю все на наиболее низком уровне, хочу попробовать на asm"е это сделать...


 
-=XP=- ©   (2005-05-27 17:54) [7]

Тут проблема не с динамическими массивами.
Скорее всего, у Вас алгоритм другой, нежели в MathLab.


 
Digitman ©   (2005-05-27 17:58) [8]


> Меня беспокоит то, что любая управляющая структура уменьшает
> скорость


при обращении по чтению - ровно на одну-две маш.инструкции.

мизер.


> специально делаю все на наиболее низком уровне


начинать нужно со своего менеджера памяти (адаптированного под конкр.задачи), а не с динамических структур, иначе все твои усилия будут сведены на нет


> хочу попробовать на asm"е это сделать


попробуй.
тем более что садомазо нынче в моде)


 
Lin7   (2005-05-27 18:11) [9]


> alertus ©   (27.05.05 17:47) [3]
> Я столкнулся с программированием на Matlab, там перемножение
> двух матриц 300x700 элементов real занимает около 1/4 секунды,
> а у меня на Delphi с использованием динамических массивов
> - 4 сек.


Может приведёшь свой код? Дело в том, что в MatLab"е интерпретатор и у меня Matlab работает медленнее, чем тот же код переписанный на Delphi, причём в разы. В новых версиях Mаtlab"а появился встроенный компилятор, но он позволяет (если не ошибаюсь) компилить matlab"овские функции в только dll.


 
alertus ©   (2005-05-27 18:12) [10]

А что насчет менеджера памяти, я так понимаю, есть такой тип TMemoryManeger, он создается вместе с приложением (TApplication).
Он управляет всей памятью, которая требуется приложению, в том числе и динамическими массивами, но он проверяет не превышены ли текущие границы динамического массива и т.п.
Это, как я понимаю и есть управляющая структура, а я хочу ее обойти или поменьше использовать.
Я совсем не уверен что это все правильно, но я ищу способы ускорить мою программу.

> Скорее всего, у Вас алгоритм другой, нежели в MathLab.

Я думаю, что для перемножения матриц другого алгоритма просто не существует в природе (возможно я не прав). Я использую такой:

var
 m1:array[1..2,1..3] of real;
 m2:array[1..3,1..2] of real;
 mr:array[1..2,1..2] of real;
 temp:real;
begin
 for i:=1 to 2 do begin
   for j:=1 to 2 do begin
     temp:=0;
     for k:=1 to 3 do begin
       temp:=temp+m1[i,k]*m2[k,j];
     end;
     mr[i,j]:=temp;
   end;
 end;
end;


Я реализовал свою небольшую прогараммку:

procedure TForm1.Button1Click(Sender: TObject);
var
 i,j,k:integer;
 temp:real;
 t1,t2:real;
 pt:^real;
 off:integer;
begin
 m1.w:=400;
 m1.h:=800;
 getmem(m1.pint,400*800*sizeof(real));
 m2.w:=800;
 m2.h:=400;
 getmem(m2.pint,800*400*sizeof(real));
 mr.w:=400;
 mr.h:=400;
 getmem(mr.pint,400*400*sizeof(real));
 for i:=1 to 400 do begin
   for j:=1 to 400 do begin
     temp:=0;
     for k:=1 to 800 do begin
       pt:=pointer(integer(m1.pint)+(i-1+(k-1)*m1.w));
       t1:=pt^;
       pt:=pointer(integer(m2.pint)+(k-1+(i-1)*m1.h));
       t2:=pt^;
       temp:=temp+t1*t2;
     end;
     pt:=pointer(integer(mr.pint)+(i-1+(j-1)*m1.h));
     pt^:=temp;
   end;
 end;
end;


Она длится 2.7 секунды, уже лучше чем 4, да и размер матриц больше, только это не объективно, потому что я на другом компьютере, хотя процессоры почти одинаковые.


 
MBo ©   (2005-05-27 18:16) [11]

Какой процессор?


 
alertus ©   (2005-05-27 18:17) [12]


> В новых версиях Mаtlab"а появился встроенный компилятор,
> но он позволяет (если не ошибаюсь) компилить matlab"овские
> функции в только dll.


Да, это так, но, как я понимаю, если я напишу на матлабе функцию перемножения матриц и сделаю dll, то этой dll нужна другая, где реализовано само умножения, я с трудом понимаю где ее искать, и я не знаю точно как передавать параметры.

Ну и, в конце концов, я хочу написать свою функцию на Dephi.


> Дело в том, что в MatLab"е интерпретатор и у меня Matlab
> работает медленнее, чем тот же код переписанный на Delphi,
> причём в разы.

Да, это абсолютно так для циклов и программ, но если взять отдельно функцию перемножения матриц, то ситуация резко меняется в противоположную сторону.


 
alertus ©   (2005-05-27 18:18) [13]


> Какой процессор?

Дома Athlon 1000, а на работе, где я сейчас - Athlon 800.


 
Digitman ©   (2005-05-27 18:23) [14]


> хочу написать свою функцию на Dephi


это похвально.
и перевешивает любые иные аргументы.

размер матрицы-результата тебе известен ?

думаю - да.

а если да, то дин.структуры нафих не нужны - один раз распределил память и заполняй ее сколь угоднго "эффективно", хоть  на асме, хоть на хрясме)


 
MBo ©   (2005-05-27 18:41) [15]

Кроме канонического алгоритма вычисления произведения матриц, существуют и более сложные - Винограда, Штрассена. На порядок они выигрыша не дадут, а в пару раз при твоих размерах - возможно. Кроме того, с точки зрения оптимизации работы с памятью может быть эффективно предварительно транспонировать одну из матриц, чтобы обращение к памяти шло подряд, а не скачками. И еще - использование SSE-иструкций современных процессоров - при программировании на ASM или использовании соответствующих компиляторов - може привести к ускорению еще в несколько раз.


 
begin...end ©   (2005-05-27 18:50) [16]

> -=XP=- ©   (27.05.05 17:45) [2]

> Лучше использовать не +0, +8, а +SizeOf(pointer) * ItemIndex

А причём тут SizeOf(pointer)?


 
Verg ©   (2005-05-27 18:52) [17]


> Она длится 2.7 секунды, уже лучше чем 4,


Это логично. Она (вторая функция) - реализована неверно. Экономия времени достигнута отсутствием требуемого умножения смещения от указателя на sizeof(real). Реально вычисляются адреса ячеек, как будь-то они размером 1 (байт).
А вообще задумайся - обход столбца одной матрицы и строки другой делаются строго последовательно. Т.о. если уж так хочется оптимизировать, то надо от прямого индексирования, сопровождающегося "в лоб" вычислением адреса через i,j и умножением на sizeof(real) на каждом шаге, переходить на суммирование индексных смещений (наращивание на каждом шаге). Т.о. ты избавишься от операций умножения для вычислений физического адреса ячейки матрицы.


 
-=XP=- ©   (2005-05-27 18:55) [18]

А причём тут SizeOf(pointer)?

Типа опечатка. Там дальше написано: SizeOf(real)

:)


 
alertus ©   (2005-05-27 19:03) [19]


> а если да, то дин.структуры нафих не нужны - один раз распределил
> память и заполняй ее сколь угоднго "эффективно", хоть  на
> асме, хоть на хрясме)

Размеры матриц изначально не известны на первой, ни второй, ни ризультата, но в ходе программы они не меняются.


> Она (вторая функция) - реализована неверно.

Да, я теперь заметил, торопился когда писал.


> Кроме того, с точки зрения оптимизации работы с памятью
> может быть эффективно предварительно транспонировать одну
> из матриц.

Вообще если говорить о моей программе, то у меня вторая матрица - это транспонированная первая (это аппроксимация алгоритма Ньютона для нахождения производной функции нескольких переменных от по двум переменным), а что, если используются близкие адреса, то это будет быстрее??

Всем огромное спасибо, попробую совместить все советы.


 
begin...end ©   (2005-05-27 19:06) [20]

> alertus ©   (27.05.05 19:03) [19]

> а что, если используются близкие адреса, то это будет быстрее??

Дело не столько в близких адресах, сколько в облегчении вычисления индексов. И об этом я уже говорил Вам в предыдущей ветке.

var
 a: Pointer;
 p: ^Real;
begin
 GetMem(a, 100 * sizeof(Real));
 p := a;
 p^ := 0.347;
 Inc(p);
 p^ := 0.764;
 Inc(p);
 p^ := 0.764;
 ...
end.


 
Defunct ©   (2005-05-27 19:08) [21]

Verg ©   (27.05.05 18:52) [17]

Допускается же умножение индексного регистра при адресации массивов. пример:

 mov EAX, [EBX + ESI*8]


 
begin...end ©   (2005-05-27 19:10) [22]

> Defunct ©   (27.05.05 19:08) [21]

Ну и что? Речь-то не о возможности, а о скорости.


 
Anatoly Podgoretsky ©   (2005-05-27 19:12) [23]

p:=pointer(integer(a)+8);
Так не допустимо, размер Real не 8, а величина переменная, но даже если бы и постоянно, то это все равно выглядит некрасиво.


 
alertus ©   (2005-05-27 19:41) [24]

Да, я согласен, я думал, что sizeof(real) тормозит программу, но это как-бы константа, поэтому лучше писать
p:=pointer(integer(a)+sizeof(real));


> begin...end ©   (27.05.05 19:06) [20]

насчет наращивания адреса, похоже, очень дельный совет.

А еще такой вопрос:
если я по очереди обращаюсь к нескольким элементам памяти, зависит ли скорость от расстояния между этими физическими адресами??


 
Defunct ©   (2005-05-27 19:48) [25]

begin...end ©   (27.05.05 19:10) [22]

Ну и ничего,
прежде чем сразу спорить возьми и проверь по скорости

mov  eax, [ebx + ecx]
и
mov  eax, [ebx + ecx*8]

оно рульно будет (С) begin...end


 
begin...end ©   (2005-05-27 19:53) [26]

> 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:55) [27]

> begin...end
> сколько в облегчении вычисления индексов.

Вот например это вообще теряет смысл, если проц. и так умеет перемножать индексные регистры непосредственно при адресации элемента массива.

т.е. доступно даже такое

mov eax, [CONST + ebx + ecx*8]
и эта команда будет выполняться одинаково быстро с командой
mov eax, [ebx]


 
Defunct ©   (2005-05-27 19:57) [28]

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;


 
Anatoly Podgoretsky ©   (2005-05-27 20:12) [29]

Чего результаты то не привел, ну зачем же каждому компилировать. Кроме того тест желательно оптимизировать, что бы уменьши погрешность от цикла и команд вызова/возврата. это делается так

mov  eax, [ESP + ECX*8]
... повторения строки от 100 раз и более
mov  eax, [ESP + ECX*8]


 
Defunct ©   (2005-05-27 20:51) [30]

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с


Выводы постоите сами ;>


 
begin...end ©   (2005-05-27 20:58) [31]

> 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


Чуда не произошло, что мной и ожидалось.


 
begin...end ©   (2005-05-27 20:59) [32]


> времени выполнения кода функцией

времени выполнения кода функцией Now


 
alertus ©   (2005-05-27 21:02) [33]

Наваял такую программу:

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], всем огромное спасибо.


 
Defunct ©   (2005-05-27 21:05) [34]

begin...end ©   (27.05.05 20:58) [31]

Я прекрасно знаю насколько объективно, именно Вы относитесь к моим постам, но в этот раз ничего у Вас не выйдет. LOL оставьте себе, раз забыли выключить оптимизацию.

> Кстати, обратите внимание на количество хинтов компилятора
Обратил - ни одного hint"a либо warning"a.


 
Defunct ©   (2005-05-27 21:10) [35]

begin...end ©   (27.05.05 20:58) [31]

> Ваш код я видоизменил: вместо ламерского способа измерения времени выполнения кода функцией использовал GetTickCount,

Вам не стыдно такое писать?


 
begin...end ©   (2005-05-27 21:37) [36]

> 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]

Не стыдно.


 
begin...end ©   (2005-05-27 22:12) [37]

Воспользовался "методом устранения ошибки" из [30]. Теперь функции содержат по 100 команд MOV: в Test -- команды вида mov eax, [I + ESP + ECX*8], где I -- целочисленные константы от 0 до 99, а в Test2 -- mov eax, [ESP + ECX].

В связи с малой производительностью процессора пришлось уменьшить число итераций до 200 миллионов, иначе я бы заснул в ожидании результатов. А результаты впечатляют:

С умножением  -- 84520
Без умножения -- 46480


"Выводы построите сами" (c) Defunct


 
Anatoly Podgoretsky ©   (2005-05-27 22:27) [38]

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


 
Defunct ©   (2005-05-27 23:45) [39]

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]

т.е. сугубо наличие умножения индекса.


 
Marser ©   (2005-05-27 23:50) [40]


> Defunct ©   (27.05.05 21:10) [35] [Новое
>сообщение][Ответить]
>begin...end ©   (27.05.05 20:58) [31]
>
> > Ваш код я видоизменил: вместо ламерского способа
> измерения времени выполнения кода функцией использовал
>GetTickCount,
>
> Вам не стыдно такое писать?

Действительно ламерство. Если б ты предложил QueryPerformanceTimer, то это дело. Но TDateTime с сопутствующими - истинная черепаха.
Твоя проблема, ИМХО, в том, что глубочайшие знания у тебя соседствуют с пробелами чуть ли не в табличке умножения.


 
ZlDoc ©   (2005-05-28 00:09) [41]

Народ чет вы все похоже на высоком уровне засиделись (хоть я сам на асьме не профи). Но скажу, что смотреть длинну команды или прогонять Mov в цикле For (да еще и с вызовом процедуры), это както не по научному. имхо.
Время выполнения команды надо тактами процессора измерять (они в старых учебниках по процессорам написаны). Процессор такая вещ что состояние может тока раз в такт менять. Следовательно, чтоб выполнить mov eax, [I + ESP + ECX], ему надо несколько тактов чтоб I + ESP + ECX посчитать, а потом mov выполнить.
Так что и без тестов сказать можно что быстрее выполниться (тем более смотрю никак в результатах не сойдетесь)

PS. Быстрее ассемблера ничего не придумали...


 
Defunct ©   (2005-05-28 00:10) [42]

Marser ©   (27.05.05 23:50) [40]

Это мне?


 
Marser ©   (2005-05-28 00:12) [43]


> Defunct ©   (28.05.05 0:10) [42] [Новое
>сообщение][Ответить]
>Marser ©   (27.05.05 23:50) [40]
>
> Это мне?

У бегиныча я пробелов не наблюдал. Были какие-то мелочные проколы, но программное время с помощью TDateTime он не измерял...


 
Marser ©   (2005-05-28 00:13) [44]


> PS. Быстрее ассемблера ничего не придумали...

Фронт прямоугольного импульса (С)
:о)


 
Defunct ©   (2005-05-28 00:20) [45]

Marser ©   (28.05.05 00:12) [43]

А какая разница с помощью чего измерять время если мне хватает точности. Ведь на фоне 2*~110 Млрд инструкция, два обращения к системному таймеру, роли не играет. Тем более, Now изменяется с каждым тиком таймера, вот и скажате, какой смысл использовать GetTickCount который выдает какие-то значения в "попугаях", когда я вам вывел время более привычных секундах с такой же точностью как begin...end (вы сказали без проколов) с помощью GetTickCount.

Или "глубочайшие знания у тебя соседствуют с пробелами чуть ли не в табличке умножения" (C) Marser?.


 
Defunct ©   (2005-05-28 00:22) [46]

Marser ©   (27.05.05 23:50) [40]

Теперь уже вас спрашиваю, вам не стыдно такое писать?
1. функции QueryPerformanceTimer нет.
2. GetTickCount и Now изменяются с одинаковой точностью.
3. Вы просто так оскорбили меня на ровном месте.


 
Defunct ©   (2005-05-28 00:29) [47]

ZlDoc ©   (28.05.05 00:09) [41]

> несколько тактов чтоб I + ESP + ECX посчитать
Не нужно, потому что для вычисления адреса не используется обычное АЛУ, а используется дополнительный сумматор/вычислитель адреса, учитывая конвеерную организацию процессора, вычисление адреса и действие АЛУ выполняются параллельно.


 
Marser ©   (2005-05-28 00:32) [48]


> 1. функции QueryPerformanceTimer нет.

QueryPerformanceCounter, уж простите великодушно.

> 2. GetTickCount и Now изменяются с одинаковой
> точностью.

А скорость? GetTickCount это один элементарный системный вызов. А у Вас кроме того ещё и FormatDateTime используется.

> 3. Вы просто так оскорбили меня на ровном месте.

1. Не на ровном.
2. Не оскорбил.
3. Всё равно прошу прощения.


 
Defunct ©   (2005-05-28 00:41) [49]

Marser ©   (28.05.05 00:32) [48]

Я не хочу никого выставить ламером,
ошибаются все. Тем более под общую шумиху, впринципе ваше поведение было ожидаемо.

Но, обратите внимание сюда:

T1 := now;
цикл
T2 := now;


Ничего лишнего, кроме засечения времени старта и останова.
Наличие запущеных сервисов под winxp дадут куда большую погрешность чем погрешность, получаемая за счет времени затрачиваемого на конвертирование показаний сист. таймера в TDateTime. Тем более погрешность эта систематическая, и для первого и для второго тестов одинакова, соответственно на точность результата никак не влияет.

Далее, уже после того как измерения произведены идет отображение на экран, при этом на не волнует как долго будет длиться этот процесс.


 
Marser ©   (2005-05-28 00:47) [50]

Вот неполное изложение того, во что выливается Now:
function Now: TDateTime;
{$IFDEF MSWINDOWS}
var
 SystemTime: TSystemTime;
begin
 GetLocalTime(SystemTime);
 with SystemTime do
   Result := EncodeDate(wYear, wMonth, wDay) +
     EncodeTime(wHour, wMinute, wSecond, wMilliseconds);
end;
function EncodeDate(Year, Month, Day: Word): TDateTime;
begin
 if not TryEncodeDate(Year, Month, Day, Result) then
   ConvertError(@SDateEncodeError);
end;
function TryEncodeDate(Year, Month, Day: Word; out Date: TDateTime): Boolean;
var
 I: Integer;
 DayTable: PDayTable;
begin
 Result := False;
 DayTable := @MonthDays[IsLeapYear(Year)];
 if (Year >= 1) and (Year <= 9999) and (Month >= 1) and (Month <= 12) and
   (Day >= 1) and (Day <= DayTable^[Month]) then
 begin
   for I := 1 to Month - 1 do Inc(Day, DayTable^[I]);
   I := Year - 1;
   Date := I * 365 + I div 4 - I div 100 + I div 400 + Day - DateDelta;
   Result := True;
 end;
end;
function EncodeTime(Hour, Min, Sec, MSec: Word): TDateTime;
begin
 if not TryEncodeTime(Hour, Min, Sec, MSec, Result) then
   ConvertError(@STimeEncodeError);
end;
function TryEncodeTime(Hour, Min, Sec, MSec: Word; out Time: TDateTime): Boolean;
begin
 Result := False;
 if (Hour < 24) and (Min < 60) and (Sec < 60) and (MSec < 1000) then
 begin
   Time := (Hour * 3600000 + Min * 60000 + Sec * 1000 + MSec) / MSecsPerDay;
   Result := True;
 end;
end;

Вот вам и ничего лишнего...
При кратковременных засечках это даёт очень большую погрешность. Крооме того, для кратковренных засечек измерений в милисекундах(gettickcount) вполне достаточно.

> Тем более под общую шумиху, впринципе ваше поведение
> было ожидаемо.

Моё - нет :-)


 
ZlDoc ©   (2005-05-28 00:49) [51]

Defunct ©
Ok. Возможно я не прав. (Но точно помню где-то читал что сначала вычисляется адрес)
Но всеравно мерить не выход. Ведь Win среда многозадачная, и праллельно с измерениями выполняются еще 2 десятка процессов + некоторые с RalTime приоритетом. Много опытов придется ставить чтоб чего то достоверное получить.


 
Defunct ©   (2005-05-28 00:55) [52]

Marser ©   (28.05.05 00:47) [50]

Спасибо что вы привели код функции Now, но опять-таки пусть 1000 команд, пусть 10000 (хотя на самом деле их там меньше), против 2.2*10^11 (кол-во команд в цикле), это вы сами понимаете фактически 0.

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


 
Marser ©   (2005-05-28 01:01) [53]


> Defunct ©   (28.05.05 0:55) [52]

Допустим, что так. Я кокретный пример не рассматривал. В общем случае GetTickCount эффективнее, а также проще.


 
Defunct ©   (2005-05-28 01:02) [54]

ZlDoc ©   (28.05.05 00:49) [51]

Ну так при измерении были приостановлены почти все процессы, и заметьте результат получился дважды одинаковым. (при первом тесте случайно дернул мышку).

Marser ©   (28.05.05 00:47) [50]
> Крооме того, для кратковренных засечек измерений в милисекундах(gettickcount) вполне достаточно.

Загляните в [30], ~45 секунд это кратковременная засечка? С точностью до сотых секунды NOW вполне достаточно.


 
Defunct ©   (2005-05-28 01:04) [55]

Marser ©   (28.05.05 01:01) [53]
> Я кокретный пример не рассматривал.

Вот, поэтому может быть не стоит делать поспешных выводов о ламерстве?


 
Marser ©   (2005-05-28 01:09) [56]


> Вот, поэтому может быть не стоит делать поспешных
> выводов о ламерстве?

А я о ламерстве конкретно вашем ничего и не говорил.  На злодієві шапка горить? ;-)


 
Defunct ©   (2005-05-28 01:17) [57]

Marser ©   (28.05.05 01:09) [56]

Да ладно там :) Куда уж отпираться-то.

Marser ©   (27.05.05 23:50) [40]
> Действительно ламерство.

Defunct ©   (28.05.05 00:10) [42]
> Это мне?

Marser ©   (28.05.05 00:12) [43]
> У бегиныча я пробелов не наблюдал. Были какие-то мелочные проколы, но программное время с помощью TDateTime он не измерял...


 
Marser ©   (2005-05-28 01:20) [58]

Добре. Можете мене записати в свої одвічні вороги, якщо вам так кортить.


 
Marser ©   (2005-05-28 01:22) [59]

Але я вам щиро не раджу цього робити... Зайвий ворог, та ще й на рівному місці...


 
Defunct ©   (2005-05-28 01:27) [60]

Marser ©   (28.05.05 01:22) [59]

Помоему и так все цивилизовано решилось.

"Мир! Дружба! Жвачка!" :) поговорка со времен когда жвачка стоила гораздо больше булки хлеба.


 
begin...end ©   (2005-05-28 10:55) [61]

> Defunct ©   (27.05.05 23:45) [39]

> Промолчу, если вы заметили, я уже стараюсь с вами не спорить.

Теперь смотрим, что же было в посте [36], на который Вы "промолчали":

1. Результаты, опровергающие Ваши утверждения (даже с отключённой оптимизацией вариант с умножением проиграл).
2. Уличение Вас во лжи насчёт отсутствия хинтов (их просто не могло не быть, или они были отключены).

Поэтому молчание только подтверждает Ваше стремление изворачиваться и патологическое нежелание признавать свои ошибки.

> Для получение объективного результата проверьте в равных
> условиях команды
>
> mov eax, [I + ESP + ECX*8]
> и
> mov eax, [I + ESP + ECX]
>
> т.е. сугубо наличие умножения индекса.

Если нужно проверить команды, отличающиеся только наличием умножения индекса, то зачем тогда константа I? Команды, отличающиеся только наличием умножения, уже проверялись в Вашем коде [28], результаты выполнения которого были приведены мной в [31] и [36] (с включённой и отключённой оптимизацией, соответственно).

Сорри, но прогонять Ваши тесты уже надоело. Судя по тому, как Вы были уверены в результате, в [36] вариант с умножением должен был выиграть. Однако этого не произошло.

Что касается способа измерения времени, то не удивлюсь, если в следующий раз Вы будете использовать часы с кукушкой.

Судя по [33], автору вопроса мой совет помог, а для меня это в этой ветке -- главное.


 
Sergey Masloff   (2005-05-28 11:28) [62]

begin...end ©   (27.05.05 20:58) [31]
>способа измерения времени выполнения кода функцией использовал >GetTickCount, хотя это тоже не лучший способ.
Ну да. Это ж время работы системы а не вашего кода. Так что GetThreadTimes() было бы уместнее (если конечно это в NT системе происходит). А иначе меряется средняя по больнице температура.


 
TUser ©   (2005-05-28 13:11) [63]

Вообще, не думаю, что тут надо браться за асм или изменять логику работы с дин.массивами. Сущействует несколько алгоритмов умножения матриц, который различаются скоростью работы. Посмотрите в интернете по словам "алгоритм Штрассена" - это один из самых быстрых.


 
Defunct ©   (2005-05-28 18:03) [64]

begin...end ©   (28.05.05 10:55) [61]
LMD

> Судя по тому, как Вы были уверены в результате,
Я до сих пор в нем уверен.


Sergey Masloff   (28.05.05 11:28) [62]
прочитайте ветку дальше.

TUser ©   (28.05.05 13:11) [63]
Если на асме есть возможность расчитать индекс быстрее, почему бы не воспользоваться этим?


 
Defunct ©   (2005-05-28 18:59) [65]

Прочитать о масштабировании индексных региcтров можно в "Instruction Set Reference Vol 2.A" в разделе 2.6 "Addressing-Mode Enconiding of ModR/M and SIB"

В "Vol 2.B, Appendix B" можно найти что инструкции
[ecx]
[ecx*8]
выполняются за одинаковое количество тактов.

Всего хорошего.

PS: (как меня уже дастали выбрыки begin...end, я тебе не школьник, чтобы от тебя выслушивать все это дерьмо).


 
begin...end ©   (2005-05-28 20:31) [66]

> Defunct ©   (28.05.05 18:59) [65]

> LMD

Из этой реплики следует, что Вам надоело жить.

>> Судя по тому, как Вы были уверены в результате,
> Я до сих пор в нем уверен.

А я до сих пор уверен в результатах [31] и [36].

> Defunct ©   (28.05.05 18:59) [65]

Если это так, то [31] и [36] можно объяснить только корявостью написанного Вами теста.

> я тебе не школьник

Верно, Вы больше похожи на дошкольника.

> выслушивать все это дерьмо

Придётся.

Продолжать разговаривать с деревом смысла не вижу.


 
Defunct ©   (2005-05-28 21:01) [67]

begin...end ©   (28.05.05 20:31) [66]

> Если это так, то [31] и [36] можно объяснить только корявостью написанного Вами теста.

Странно, почему же у меня "коряво написанный тест" это подтверждает.

А может быть ваше "неламерское" видоизменение, так повлияло. Не вы ли написали:
> Ваш код я видоизменил: вместо ламерского способа измерения времени

> Верно, Вы больше похожи на дошкольника.
>> выслушивать все это дерьмо
> Придётся.

LMD


 
TUser ©   (2005-05-29 05:01) [68]

> Если на асме есть возможность расчитать индекс быстрее,
почему бы не воспользоваться этим?

Да я не против. Просто быстрее в таком случае означает - процентов на 10 максимум, я понимаю. Обычно, если уж программа медленно работает, то очень сильно помогает изменение логики работы алгоритма, а не переход на си, ассемблер или покупка супер-компьютера. А судя по [10] тут как раз такой случай, что алгоритм можно улучшить.

Хотя против асма тоже ничего не имею.


 
Defunct ©   (2005-05-29 07:54) [69]

TUser ©   (29.05.05 05:01) [68]

навеяно вашими размышлениями..
Алгоритм [33] на асме с MMX и SSE и масштабированием индексов о котором здесь был спор с begin...end.

Работает почти в 3 раза быстрее чем [33]. 0.38 сек. (моя функция) против 1.0сек. (оригинал [33])

procedure TForm2.Button4Click(Sender: TObject);
var
a:^real;  //311x700
b:^real;  //700x311
c:^real;  //311x311
begin
getmem(a,311*700*sizeof(real));
getmem(b,311*700*sizeof(real));
getmem(c,311*311*sizeof(real));

memo1.lines.add(writems);

{}
asm
{ подготовка MMX и SSE }
  push  ebx
  push  esi

  mov   eax, c
  movd  mm6, eax
  mov   eax, b
  movd  mm0, eax
  mov   eax, a
  movd  mm1, eax      // A - low dword

  mov   eax, 311
  movd  mm2, eax
  punpckldq mm2, mm2  // Двойной множитель на 311

// for i := 0 to 310 do
  mov   ecx, 310
@L1:
// for j := 0 to 310 do
  mov   edx, 310
@L2:
  pxor  xmm1, xmm1    // Переменная Temp в фантазии SSE
                      // Расчет i/j адреса вынесен из цикла k
  movd  mm4, ecx
  punpckldq mm4, mm4
  movd  mm4, edx
  movq  mm3, mm4
  pmullw mm3, mm2
  pmulhw mm4, mm2
  pslld  mm4, 16      // j * 311
  paddd  mm4, mm3
  punpckldq mm3, mm4  // i * 311

// for k := 0 to 699 do
  mov   ebx, 699
@L3:

  movd   eax, mm0   ; // pointer to B
  add    eax, ebx   ;
  movd   esi, mm4
  movq   xmm0, [eax + esi*8]
  movd   eax, mm1   ; // pointer to A
  add    eax, ebx
  movd   esi, mm3
  mulsd  xmm0, [eax + esi*8]
  addpd  xmm1, xmm0          ; // temp:=temp+pa^*pb^;

  dec    ebx
  jns    @L3

  movd   eax, mm6   ; // pointer to C
  movd   esi, mm4   ; // j * 311
  add    esi, ecx   ; // + i
  movq   [eax + esi*8], xmm1 // сохраняем temp

  dec    edx
  jns    @L2

  dec    ecx
  jns    @L1

  emms
  pop  esi
  pop  ebx
end;

memo1.lines.add(writems);

end;


 
Defunct ©   (2005-05-29 08:31) [70]

Кстати именно этот множитель индекса и не учтен в [33] его вообще там нет, соответственно функция [33] не рабочая .. и моя не рабочая (т.к. делал по образу [33]), а чтобы сделать ее рабочей надо поменять в цикле k этот код

 movd   eax, mm0   ; // pointer to B
 add    eax, ebx   ;
 movd   esi, mm4
 movq   xmm0, [eax + esi*8]
 movd   eax, mm1   ; // pointer to A
 add    eax, ebx
 movd   esi, mm3


на такой:

 movd   eax, mm0   ; // pointer to B
 movd   esi, mm4
 add    esi, ebx   ;
 movq   xmm0, [eax + esi*8]
 movd   eax, mm1   ; // pointer to A
 movd   esi, mm3
 add    esi, ebx


 
Marser ©   (2005-05-29 11:03) [71]


> begin...end ©
> Defunct ©  

Break!
Вы уже давно грызётесь. А толку-то? Никому из вас это на пользу не идёт, авторитету не добавляет. Только однеому создаёт неповторимый оттенок, а другому ещё более его усугубляет.
Зачем?


 
alertus ©   (2005-05-30 17:00) [72]

Подскажите, пожелуйста, где можно прочитать про инструкции SSE??


 
Digitman ©   (2005-05-30 17:03) [73]


> Подскажите, пожелуйста, где можно прочитать про инструкции
> SSE??


в мануалах от Интела ... это же его детище ..


 
alertus ©   (2005-05-30 17:06) [74]

Как я понял, там почти тоже самое, как программирование на асме, только добавляются регистры новые для быстрых операций с вещественными числами??
А ссылку не подскажете??


 
Digitman ©   (2005-05-30 17:11) [75]

на сайте у Анатолия Подгорецкого, кажется, был ..

в оригинале файл называется 24547112.pdf

IA-32 Intel ® Architecture
Software Developer’s
Manual
Volume 2 :
Instruction Set Reference


 
Defunct ©   (2005-05-30 17:28) [76]

alertus ©   (30.05.05 17:06) [74]

Боюсь у Athlon"a нет SSE. (во всяком случае насколько я помню у Athlon TB не было, а вы говорили что у вас Athlon 800, это скорее всего и есть TB). У AMD процессоров есть 3DNow! для работы с числами с плавающей точкой, так что ищите мануал на сайте AMD а не Intel"а. Вам всего навсего нужна замена команд ADDPD/ADDSD и MULPD/MULSD.


 
DiamondShark ©   (2005-05-30 17:53) [77]


> зависит ли скорость от расстояния между этими физическими
> адресами??

В системах с многоуровневой памятью -- зависит.
Иногда очень сильно.


 
begin...end ©   (2005-05-30 20:05) [78]

> alertus ©   (27.05.05 21:02) [33]

Этот код не выполняет умножения матриц. Вот рабочий код:

const
 M = 311; // Число строк в A и столбцов в B
 N = 700; // Число строк в B и столбцов в A
type
 TElement = Real;
 PElement = ^TElement;
var
 Temp: TElement;
 i, j, k: Integer;
 A, B, C: PElement;
 pA, pB, pC: PElement;
begin
 GetMem(A, M * N * sizeof(TElement));
 GetMem(B, N * M * sizeof(TElement));
 GetMem(C, M * M * sizeof(TElement));
 try
   pC := C;
   for i := 1 to M do
   begin
     pA := PElement(Integer(A) + (i - 1) * N * sizeof(TElement));
     for j := 1 to M do
     begin
       pB := PElement(Integer(B) + (j - 1) * sizeof(TElement));
       Temp := 0;
       for k := 1 to N do
       begin
         Temp := Temp + pA^ * pB^;
         Inc(pA);
         Inc(pB, M)
       end;
       pC^ := Temp;
       Inc(pC);
       Dec(pA, N)
     end
   end
 finally
   FreeMem(A);
   FreeMem(B);
   FreeMem(C)
 end
end.


> Defunct ©   (29.05.05 07:54) [69]
> Defunct ©   (29.05.05 08:31) [70]

Нерабочий код. Вылетает с External Exception.


 
Defunct ©   (2005-05-30 20:07) [79]

begin...end ©   (30.05.05 20:05) [78]

Код под P4, mulsd на P3 нет.


 
Defunct ©   (2005-05-30 20:08) [80]

> begin...end
Прошу прощения что поставил неверный коментарий:

{ подготовка MMX и SSE2 }


 
begin...end ©   (2005-05-30 20:39) [81]

> alertus ©   (27.05.05 21:02) [33]

Дополнение к [78]: матрицы должны быть расположены в памяти по строкам -- вначале первая строка, затем вторая и т.д. Матрица результата будет размещена таким же образом.



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

Форум: "Основная";
Текущий архив: 2005.06.14;
Скачать: [xml.tar.bz2];

Наверх




Память: 0.73 MB
Время: 0.039 c
1-1117207820
Cash
2005-05-27 19:30
2005.06.14
Проблема целесообразности


4-1113852432
Jeson
2005-04-18 23:27
2005.06.14
помогите с форматированием винчестера в Delphi 7


4-1113899638
dimasih
2005-04-19 12:33
2005.06.14
Документация по TService


1-1117175223
ingine
2005-05-27 10:27
2005.06.14
Удаление Строк в StringGrid


1-1117101129
P.N.P.
2005-05-26 13:52
2005.06.14
Форма в ScrollBox и OnKeyDown





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