Соответствует ли действительности то, что компилятор Object Pascal в
Delphi лучше компилятора C++ в C++Builder? Для эксперимента я создал два
проекта на С++Builder и Delphi соответственно, и всего навсего в процедуре
обрабатывающей нажатие на кноку задал пустой цикл от 1 до 1 миллиарда:
В С++Builder соответсвующая функция выглядела сл. образом:
void __fastcall TForm1::Button1Click(TObject *Sender)
{
for (int i = 0; i < 1000000000; i++);
}
а в Delphi соответствующая процедура выглядела так:
procedure TForm1.Button1Click(Sender: TObject);
var i : integer;
begin
for i:= 0 to 1000000000 do;
end;
И что же оказывается - Программа на Delphi выполняется в 5 раза быстрее(4
сек., а на С++Builder - 20 cек.)! ??
Тогда я решил выяснить в чём разница в конечном коде, генерируемом
компиляторами C++Builder и Delphi. Для этого я просто установил точки
останова(breakpoint) напротив циклов и во время выполнения заглянул в
Debug Windows/CPU и что оказалось:
код сгенерированный компилятором С++Builder, соответсвующий пустому циклу
в ассемблерном представлении выглядит сл. образом:
xor edx, edx
mov [ebp-0x34], edx
inc dword ptr [ebp-0x34]
mov ecx, [ebp-0x34]
cmp ecx, 0x3b9aca00
jl -0x0e
А у Delphi получился такой код:
mov edx, $3b9aca00
dec edx
jnz TForm1.Button1Click + $5
Т.О. отсюда уже понятны причины почему программа на Delphi быстрее
выполняется. Помимо того что бросается в глаза большее количество команд
видно ещё принципиальное отличие - в коде первой программы в качестве
переменной-счётчика используется ячейка памяти, а компилятор Delphi
сгенерировал код в котором используется регистр процессора в качестве
счётчика. Хорошо, можно и устранить последнее отличее сл. образом:
void __fastcall TForm1::Button1Click(TObject *Sender)
{
for (register int i = 0; i < 1000000000; i++);
}, т.е. перед переменной-счётчиком i указали спецификатор register,
предварительно в настройках компилятора разрешив использование Register
Variables(Project/Options/Advanced Compiler/Register Variables).
Действительно тогда код сгенерированный компилятором С++Builder изменится
к виду:
mov eax, 0x3b9aca00
dec eax
test eax, eax
jnle -0x05
Как видим теперь уже почти не отличается от кода сгенерированного
компилятором Delphi! За исключением одной лишней команды - test eax,
eax(зачем она нужна??) и команды jnle вместо jnz. Вот за счёт этой лишней
команды test eax, eax, кот. выполняется в цикле и увеличивается время
выполнения (на 15 сек. становится дольше). Так что же это?! Низкое
качество генерируемого кода компилятором C++Builder в сравнении с
компилятором Delphi?? Специалисты! Помогите! Проясните ситуацию. Какой же
компилятор лучше - C++Builder или компилятор Delphi?? Или возможно как-то
добиться той же эффективности кода, настроив как-то компилятор С++ в
С++Builder? Очень благодарен за ответы с пояснением!
PS Ещё заметил такой прикол, что если в С++Builder вместо просто цикла от
1 до миллиарда использовать 2 равносильных цикла, т.е. один вложенный в
другой: внешний от 1 до миллиона, а внутренний от 1 до тысячи, вот тогда
как ни парадоксально скорость выполнения 2х циклов быстрее в 5 раз чем
просто одного от 1 до миллиарда! Т.Е. вариант:
for (int i = 0; i < 1000000000; i++);
много медленее, чем вариант:
for(int i = 1; i < 1000000; i++)
for(int j = 1; j < 1000; j++);
!!?? Получается что если нам надо выполнить какие-то действия в
программе миллиард раз, нужно это сделать не в одном цикле, а задать
внешний цикл от 1 до миллиона и внутренний от 1 до тысячи, например, и в
теле внутреннего описать все действия!!??
Максим
Всего в теме 346 сообщений
Добавить свое сообщение
Отслеживать это обсуждение
- Средства разработки. Языки программирования.
- Delphi 4 or Delphi 5
- Что приобрести в качестве средства разработки?
- Delphi6
- Delphi vs PowerBuilder
- Вот и вышла Delphi 7... Вы рады?
- Функциональное программирование
№ 296 21-06-2007 02:59 | |
Ответ на »сообщение 295« (Антон Григорьев)
___________________________
Ответ на »сообщение 294« (al_mt)
___________________________
Вообще-то было бы странно, если бы .Net приложение работало бы быстрее нативного кода %)
Не все с этим согласны :)
... может оптимизировать финальный исполняемый код, используя инструкции конкретного машинного кода, предназначенные для конкретного процессора."
А вот эта вот байда - чистый маркетинг. заметьте оговорку "может" :)))) В принципе может. На деле получается, что время компиляции прибавляется к времени исполнения %) %))))))
№ 295 21-06-2007 02:16 | |
Ответ на »сообщение 294« (al_mt)
___________________________
Вообще-то было бы странно, если бы .Net приложение работало бы быстрее нативного кода %)
Не все с этим согласны :)
"<...> Это объясняет, почему можно рассчитывать на то, что выполнение управляемого кода IL будет почти настолько же быстрым, как и выполнение родного машинного кода. Однако это не объясняет того, почему Microsoft ожидает повышения производительности. Причина состоит в том, что поскольку финальная стадия компиляции происходит во время выполнения, JIT-компилятор на этот момент уже знает, на каком типе процессора запущена программа. А это значит, что он может оптимизировать финальный исполняемый код, используя инструкции конкретного машинного кода, предназначенные для конкретного процессора."
Кристиан Нейгел, Билл Ивьен, Джей Глинн, Карли Уотсон, Морган Скиннер, Фллен Джонс "C# 2005 для прфессионалов" М.: Издательский дом "Вильямс", 2007, страница 46.
№ 294 21-06-2007 00:46 | |
Ответ на »сообщение 293« (Марина)
___________________________
>Интересно всё таки какой нибудь более сложный тест придумать, чтобы проверить насколько сильно этот баг >влияет на скорость выполнения реальных приложений.
На Gamedev народ тоже столкнулся с проблеммой Delphi 10 работает медленнее чем Delphi 7.
http://www.gamedev.ru/flame/forum?id=66154&page=12
Вообще-то было бы странно, если бы .Net приложение работало бы быстрее нативного кода %)
№ 293 20-06-2007 22:39 | |
>Интересно всё таки какой нибудь более сложный тест придумать, чтобы проверить насколько сильно этот баг >влияет на скорость выполнения реальных приложений.
На Gamedev народ тоже столкнулся с проблеммой Delphi 10 работает медленнее чем Delphi 7.
http://www.gamedev.ru/flame/forum?id=66154&page=12
№ 292 03-04-2007 10:06 | |
Ответ на »сообщение 291« (DRON)
___________________________
Ну и хрен с ним (оптимизатором)
"Wipe your hand across your mouth, and laugh"
T.S.Eliot
№ 291 03-04-2007 06:11 | |
Ответ на »сообщение 290« (Cepгей Poщин)
___________________________
Я тут слегка погуглин и нашёл вот это http://qc.codegear.com/wc/qcmain.aspx?d=8695, действительно ошибка в кодогенератор была внесена именно в D7Update1 и с тех пор не исправлена, хотя и помечена как "Closed в D2005".
Выражается она в том что оптимизатор тупит и забывает про существование некоторых регистров, в данном случае про ebp, а это приводит к интенсивным обменам с памятью (стеком). Те у кого Delphi7 ещё могут заменить DCC32.exe и DCC70.dll на оригинальные, с диска, остальные вообще в пролёте.
Правда должен сказать, что это заметно только на довольно специфическом коде где много одновременно задействованных локальных переменных и нет ничего кроме обменов и простейших операций, а если выбрать алгоритм немного посложнее, то и D5 и D7 будут генерить одинакого плохой код.
Интересно всё таки какой нибудь более сложный тест придумать, чтобы проверить насколько сильно этот баг влияет на скорость выполнения реальных приложений.
№ 290 03-04-2007 02:43 | |
По поводу сравнения скорости работы Delphi5 и BDS2006 см. »сообщение 250 в теме №377 на БП«
Вот мои печальные выводы:
Действительно вынос кода в процедуру и замена for на while деает некоторое улучшение, но тем не менее BDS2006 работает медленнее чем Delphi5 в 1,4..1,6 раза. Было бы еще понятно, если бы это происходило на каком-нибудь Pentium-90. Но тест производился на Pentium4 3GHz
Вот тестовая программа:
program TestTime;
uses
Sysutils,
Windows
;
var
razmer:integer;
b:array[1..20] of integer;
Time1,Time2,nomvar,d,m,kl,min,obmen:integer;
procedure CallFor;
var b:array[1..20] of integer;
d,m,kl,min,obmen:integer;
begin
for d:=1 to 20 do
b[d]:=d;
nomvar:=0;
while True do
begin
nomvar:=nomvar+1;
for m:=razmer downto 2 do
if b[m]>b[m-1] then
break;
if m=1 then
Break;
obmen:=m-1;
for min:=obmen+1 to razmer do
if (b[min]<b[m]) and (b[min]>b[obmen]) then
m:=min;
min:=b[obmen];
b[obmen]:=b[m];
b[m]:=min;
for d:=obmen+1 to razmer-1 do
begin
m:=d;
for kl:=d+1 to razmer do
if b[kl]<b[m] then
m:=kl;
min:=b[m];
b[m]:=b[d];
b[d]:=min;
end;
end;
end;
procedure CallWhile;
var b:array[1..20] of integer;
d,m,kl,min,obmen:integer;
begin
for d:=1 to 20 do
b[d]:=d;
nomvar:=0;
while True do
begin
nomvar:=nomvar+1;
for m:=razmer downto 2 do
if b[m]>b[m-1] then
break;
if m=1 then
Break;
obmen:=m-1;
for min:=obmen+1 to razmer do
if (b[min]<b[m]) and (b[min]>b[obmen]) then
m:=min;
min:=b[obmen];
b[obmen]:=b[m];
b[m]:=min;
for d:=obmen+1 to razmer-1 do
begin
m:=d;
kl:= d + 1;
while kl <= razmer do
begin
if b[kl]<b[m] then
m:=kl;
inc(Kl);
end;
min:=b[m];
b[m]:=b[d];
b[d]:=min;
end;
end;
end;
begin
Sleep(1000);
razmer:=12;
CallFor;
CallWhile;
razmer:=13;
Time1:=GetTickCount;
for d:=1 to 20 do
b[d]:=d;
nomvar:=0;
while True do
begin
nomvar:=nomvar+1;
for m:=razmer downto 2 do
if b[m]>b[m-1] then
break;
if m=1 then
Break;
obmen:=m-1;
for min:=obmen+1 to razmer do
if (b[min]<b[m]) and (b[min]>b[obmen]) then
m:=min;
min:=b[obmen];
b[obmen]:=b[m];
b[m]:=min;
for d:=obmen+1 to razmer-1 do
begin
m:=d;
for kl:=d+1 to razmer do
if b[kl]<b[m] then
m:=kl;
min:=b[m];
b[m]:=b[d];
b[d]:=min;
end;
end;
Time2:=GetTickCount;
Writeln('Count: '+IntToStr(nomvar));
Writeln('Time: '+IntToStr(Time2-Time1)+'(ms)');
Time1:=GetTickCount;
CallFor;
Time2:=GetTickCount;
Writeln('Count: '+IntToStr(nomvar));
Writeln('Time: '+IntToStr(Time2-Time1)+'(ms)');
Time1:=GetTickCount;
CallWhile;
Time2:=GetTickCount;
Writeln('Count: '+IntToStr(nomvar));
Writeln('Time: '+IntToStr(Time2-Time1)+'(ms)');
Readln;
end.
Может я что-то делаю не так?
№ 289 14-06-2006 04:41 | |
Прочитал сообщение Максима и удивился!!! Кто же ТАК сравнивает компиляторы, дорогой товарищ :) Господа из Борланд инфаркт бы схватил, если бы узнали о Ваше методике. Компиляторы сравниваются на реальной задаче, где активно используются мат.вычисления, постоянно используется оперативная память... Просто запустить цикл, и все? Как-то в Компьютерном обозрении была опубликована статья на тему сравнения компиляторов. Автор использвал задачу решения дифференциальных уравнений численными методами. Там был Delphi, Borland C++, MSVC++, GCC, Fortran, Intel C++, VB(!) и некоторые другие... Так вот по рещультатам забега первое место занял Intel Fortran, за ним Intel C++, GCC и все остальные. Delphi и Borland C++ показали одинаковый результат.
Кстати, в Borland C++ нужно еще выбрать конфигурацию проекта Release, вот тогда все будет работать очень быстро, быстрее чем в Delphi.
Сам я тоже такими вещами баловался когда-то... Только тест немного посложнее делал: в цикле давал вычислительную нагрузку, потом рекурсивно реализовывал вычисление числа сочетаний из n по k (C(n, k)), в общем в таком духе :) Так у меня C++ всегда ощутимо быстрее оказывался. Такие дела.
Если Вам нужна качественная оптимизация кода и поддержка современых процессоров - выбирайте компилятор Intel, не пожалеете! Он многое умеет (почитайте спецификации на сайте ИНтел), хотя и денег стоит.
p.s.: это не реклама
№ 288 Удалено модератором | |
№ 287 08-07-2005 07:20 | |
Просто факт.
MSVC7 и C# используют в FPU Control Word
дефолтное значение (PrecisionMode = double)
BC++ и Delphi - PrecisionMode = extended
Это, что жульничество MS или недоработка Borland?
Ведь (PrecisionMode = double) ускоряет вычисления с
плавающей точкой процентов на 10 по отношению к
(PrecisionMode = extended).
Добавить свое сообщение
Отслеживать это обсуждение
Дополнительная навигация: |
|