Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Asm: Общие вопросы > Тест на производительность


Автор: Coder 3.4.2005, 01:34
Решил протестировать C++, Pascal и Asm на производительность кода. Вот три исходника:

Код

.486
.model flat,stdcall
option casemap:none
includelib c:\myasm\lib\kernel32.lib
includelib c:\myasm\lib\user32.lib
include c:\myasm\include\kernel32.inc
include c:\myasm\include\user32.inc
num_size equ 10
.data
stdout dd ?
buf db num_size dup(?)
frt db "%d",0
caret db 13,10
cWritten dd 0
.code
start:
invoke GetStdHandle,-11
mov stdout,eax
mov ecx,100000
nxt:
    push ecx
    invoke wsprintf, addr buf, addr frt, ecx
    invoke WriteConsoleA, stdout, addr buf, sizeof buf, addr cWritten, 0
    invoke WriteConsoleA, stdout, addr caret, 2, addr cWritten, 0
    pop ecx
loop nxt
invoke ExitProcess, 0
end start


Код

var
i : longint;
begin
  for i:=100000 downto 1 do
   writeln(i);
end.


Код

#include <stdio.h>

void main(){
  long i;
  for (i=100000;i!=1;i--)
    printf("%ld\n",i);
}


Так вот, получились интересные результаты, программа на C++ и Pascale выполняются за ~14 сек., а на Asm за (!) ~46 сек.
Почему такая ерунда происходит? я думал, что все должно быть наоборот - ведь на Асме идет прямое обраещение к процессору... где же быстродействие ассемблера?

P.S. используемые компиляторы:
С++ - Turbo C++ 3.0
Pascal - Borland Pascal 7.0
Asm - MASM32 7.0

P.S.2. еще мое наблюдение, при выполнение кода Паскаля и С загружен процесс ntvdm.exe, а при выполнении кода Asm загружен процесс csrss.exe. почему эти программы выполняются в разными процессами?

Автор: cardinal 3.4.2005, 01:53
Цитата(Coder @ 2.4.2005, 23:34)
Почему такая ерунда происходит?

Потому что, твой компилятор сделал все лучше, чем то, что сделал ты сам (то, что сделано на asm'е).
Цитата(Coder @ 2.4.2005, 23:34)
где же быстродействие ассемблера?

В более хитром подходе smile

Любой компилятор (не asm) перед тем как сделать exe'шник как бы создает asm, а потом уже делает понятный для процессора файл с коммандами. Некоторые компиляторы позволяют посмотреть на то, что они делают сами (создают asm листинги) и ты можешь подумать над тем, а нельзя ли сделать это лучше самому.
В твоем примере последнее не получилось smile

Рассказал все своими словами, может не очень получилось smile

Автор: S.A.P. 3.4.2005, 02:38
Могу предположить, что из за того, что Pascal и C++ у тебя досовские, а приложение на Асме - виндовое. Консоль - это не Dos приложение. Dos овские компилеры, например, вместо вызова wsprintf используют свой код и так, возможно будет быстрее, потому - что в асме ты принудительно обращаешься к функции в DLL, а Dos компилер может все это оптимизировать в инлайн функцию. Да и WriteConsoleA DOS компилер не использует, ее может использовать процесс, который эмулирует Dos приложение. Но это только ИМХО.

Автор: Coder 3.4.2005, 07:52
cardinal, покажи более хитрый подход!

Автор: Chingachguk 3.4.2005, 10:53
Цитата
ведь на Асме идет прямое обраещение к процессору...


Где ты увидел прямое обращение к процессору ? wsprintf - это API, так что это просто вызовы Win. К тому же у тебя два вызова WriteConsoleA в асме, а в СИ и Паскале наверняка один. Про то, что СИ и Пас под дос, а асм - для win, уже сказали.

Автор: cardinal 3.4.2005, 13:53
Цитата(Coder @ 3.4.2005, 05:52)
cardinal, покажи более хитрый подход!

а ты поставь себе MS VC++ и эксперементируй там. Создашь listing и исходя из него будешь оптимизировать (поправляя то, что стоит в _asm{} smile). А profile тебе скажет, что лучше.
А во-вторых попробуй вместо loop сделать просто dec. Помоему когда я экспериментировал у меня так быстрее получалось.
Когда добьешься оптимального результата можешь его использовать в другом C/C++ компиляторе (если он конечно _asm делать позволяет)...

Автор: oleg1973 3.4.2005, 19:29
давайте тестить printf из crtdll.dll

Автор: Coder 5.4.2005, 08:16
пользуясь всем вышепосоветованным решил проверить просто скорость прогонки циклов на этих языках (без вызова каких либо операторов, функций)
но брал уже цикл от 2`000`000`000 до 0.

Код

.486
.model flat,stdcall
option casemap:none
includelib c:\myasm\lib\kernel32.lib
include c:\myasm\include\kernel32.inc
.code
start:
mov eax,2000000000
nxt:
dec eax
cmp eax,0
jnz nxt
invoke ExitProcess, 0
end start

Код

var
i : longint;
begin
  for i:=200000000 downto 1 do ;
end.

Код

#include <stdio.h>
void main(){
  long i;
  for (i=2000000000;i!=1;i--);
}


Вот такие результаты:
Asm - ~5 сек
Pascal - ~3 сек !!!
C++ - ~16.5 сек

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

Автор: S.A.P. 5.4.2005, 08:48
Coder во первых убери строчку cmp eax,0. Инструкция DEC сама выставляет флаг признака нуля.
Во вторых сравни количество нулей у числа в C++ и Pascal и ASM smile
В третьих в С++ попробуй и такой цикл замутить
Код

long i = 2000000000;
while (i--){};

В четвертых посмотри в опциях компилатора всякие оптимизации по скорости.

Автор: S.A.P. 5.4.2005, 10:10
Вот как оптимизирует цикл Visual C++
Код

    while (i--)
    {
        _asm NOP;
00401005 90               nop              
00401006 48               dec         eax  
00401007 75 FC          jne         main+5 (401005h) 
    };


Разницы с ассемблером нет. А если убрать строчку _asm NOP, то вобще весь цикл вырезает. Посмотрим, как с этим Борланд справится.

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

Автор: Girder 5.4.2005, 15:19
Цитата(Perchilla @ 5.4.2005, 11:10)
Уже на глаз можно прикинуть, что Pascal обделается в этом тесте.

smile Уже на глаз... видно обратное smile особенно для старых компьютеров smile

Код:
Код

for i:=200000000 downto 1 do;
будет преобразован в вот ентот код:
Код
mov eax,0f4143e00h
Go:
inc eax
jnz Go

Автор: S.A.P. 5.4.2005, 15:46
Цитата(Girder @ 5.4.2005, 15:19)
Уже на глаз... видно обратное

чем этот код
Код

Go:
inc eax
jnz Go

будет быстрее этого
Код

Go:
dec  eax  
jne Go

smile
Тем более Visual C++ вобще пустые циклы вырезает.

Автор: Girder 5.4.2005, 15:49
Вот ентот код (особенно на старых компьютерах) будет медленнее:
Код
nop
dfkj:
nop
dec eax
jne sdfkj
Например у меня на p233MMX твой код медленне в 2 раза. У Coder явно тоже не современный комп smile

PS: И не надо мне советовать комп поменять... я его мож подарить хочу smile Вот только не берет ни кто smile

Автор: S.A.P. 5.4.2005, 16:01
Щас по другому проверим smile . Обратный цикл, с шагом 3, а через раз прибавлять по единичке.

Претендент:
Код

long i = 2000000000;
bool a = true;
while (i+=(a^=1)-3){};

Добавлено @ 16:04
Цитата(Girder @ 5.4.2005, 15:49)
Вот ентот код (особенно на старых компьютерах) будет медленнее:
только без NOP. Я его поставил, чтобы компилер цикл пустой не вырезал.

Добавлено @ 16:05
Цитата(Girder @ 5.4.2005, 15:49)
И не надо мне советовать комп поменять... я его мож подарить хочу smile Вот только не берет ни кто smile
у меня P166 дома пылиться smile .

Автор: Girder 5.4.2005, 17:20
Чего и то у тебя было 200000000 стало 2000000000

Тестируй:
Код
...
var i,j:Longint;
begin
 i:=200000000; //или 2000000000
 j:=3;
 repeat
  i:=i-j;
  j:=j xor 1;
 until (i<0);
...
PS: А мне лень... тестировать smile

Автор: Coder 7.4.2005, 12:05
Цитата(Perchilla)

Во вторых сравни количество нулей у числа в C++ и Pascal и ASM

Ой, извиняюсь smile короче с цифрой 2`000`000`000 Паскаль облажался - 26 сек.
Цитата(Perchilla)

Вот как оптимизирует цикл Visual C++

С какой версии VC++ есть такой оптимизатор? Есть ли такие возможности у C++Builder? (Я никогда не писал на С++ под виндой).
Что посоветуете C++Builder или VC++?
Цитата(Girder)

Код:
Код

for i:=200000000 downto 1 do;

будет преобразован в вот ентот код:
Код

mov eax,0f4143e00h    
Go:    
inc eax    
jnz Go


А что (какой компилер) это так код преобразовало? интересный подход и странный подход... ладно тут 2млрд, а если бы было число 10 в 2 байтовом регистре, он бы че весь 4 байтовый регистр ворошил на больших числах (начиная с 4294967286)?
Цитата(Girder)

Например у меня на p233MMX твой код медленне в 2 раза. У Coder явно тоже не современный комп

Athlon 952 smile

Автор: mb78 31.7.2008, 14:30
Если сделать на ассемблере под Dos , но не через прерывания а через запись в память 
(правда сначала надо сформировать свою быструю подпрограмму вывода целых чисел)
то я думаю такая программа будет длиться меньше секунды.
Для программ Dos  число 100000 повторений в 10-чной системе счисления это ничто.
Dos может перебрасывать блоки по 65535(ffffh) сотни раз в секунду.
А в Windows почти весь вывод на экран происходит через API , многие из которых работают очень медленно.
Например я пробовал закрашивать небольшой квадратик через API функцию SetPixel , и у
меня программа длилась несколько секунд. К тому же в Windows работает сразу много процессов
поэтому они замедляют друг друга.Для лучшей проверки вашего теста попробуйте загрузить
Windows в безопасном режиме , там меньше процессов и пограммы выполняются быстрее,
например у меня в несколько раз.

А почему в С+ получилось быстрее,я думаю возможно оттого , что в С+ для быстродействия вывод
сначала идет не не экран , а в память , и перебрасывается на экран несколько раз в секунду все
содержимое что нужно вывести.

Автор: Diabolus 24.9.2008, 15:06
Код

mov ecx,2000000000
tst:
loop tst

0m1.352s
(P4 - 3GHz)

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)