Форум: "Основная";
Текущий архив: 2005.02.20;
Скачать: [xml.tar.bz2];
Внизстатья: Написание оптимального кода под Delphi Найти похожие ветки
← →
Imp (2005-02-02 13:12) [0]
Вынесение инвариантного кода за пределы цикла – не выносится. Наиболее распространенный недочет – условие цикла записывается как:
for i:=0 to memo1.lines.count – 1 do...
Delphi будет при каждой итерации вызывать метод count, вычитать из результата 1 и потом уже сверять. Настоятельно рекомендуется переписывать подобный код как
lin := .lines.count – 1;
for i:=0 to lin do...
Весь код VCL написан с нарушением этого правила. Очевидно, что проще подобного рода оптимизацию встроить в компилятор, нежели переписывать VCL :)
Автор этой статьи, наверное, просто не смотрел ассемблерный код, который генерирует Delphi в этом случае. Вдобавок он не знаком со стандартом Object Pascal. Дело в том, что в любом случае, аргументы, которые необходимы для цикла for do, РАСЧИТЫВАЮТСЯ ТОЛЬКО ОДИН РАЗ. Это не относится к while do или repeat until. Было бы очень неплохо, если бы статьи, перед тем как попасть в руки новичков просматривались профессионалами.
← →
TUser © (2005-02-02 13:35) [1]
> Было бы очень неплохо, если бы статьи, перед тем как попасть
> в руки новичков просматривались профессионалами.
Согласен. Осталось найти профессионала, который готов добровольно читать статьи для новичков.
← →
КаПиБаРа © (2005-02-02 13:40) [2]Imp (02.02.05 13:12)
Достаточно иметь возможность обсуждения статьи на том ресурсе, где статья опубликована. А уж автор прочитав комментарии исправит ошибки в своем творении. Ему же не хочется что бы на него пальцем показывали. И не надо никаких профессионалов напрягать.
← →
Poirot © (2005-02-02 14:29) [3]Ну мб он просто вспомнил си:)))
← →
Virgo_Style © (2005-02-02 14:35) [4]Вероятно, человек просто привык оптимизировать программы, "не дожидаясь милостей" от компилятора... А вы сразу ругаться :)
Imho, именно это и есть профессионализм... Хотя возможности компилятора тоже надо знать :)
← →
REA (2005-02-02 14:39) [5]Мне почему-то кажется, что функция будет вызываться чаще. И если в цикле memo1.lines.count поменяется, то результат правильный. Ассемблерный код смотрел давно. Поправьте, если это не так.
← →
Sha © (2005-02-02 14:40) [6]Еще ошибки:
> Здесь учитывается особенность самой операции div – округление
> в большую сторону.
> Наиболее частая ошибка – for i:=1 to length(str) do... Дело в
> том, что при каждой итерации будет вызываться функция length
Есть спорные моменты:
> b:=random(maxint); // b – заведомо не константа !
> a:=$abcd6123;
> if b>a then b:=a;
> Скомпилированный код будет выглядеть
> mov eax, $7fffffff // MaxInt
> call @RandInt
> mov ebx,eax
> mov eax, $abcd6123
> cmp eax, ebx
> jnl +$02
> А ведь значение, присвоенной переменной «а» являлось
> константой и наш пример можно было бы переписать как:
> b:=random(maxint);
> a:=$abcd6123;
> if b>$abcd6123 then b:= $abcd6123;
← →
Neznaika © (2005-02-02 14:43) [7]Не хочу спорить просто интересно, (ни когда об этом не задумывался, да и вообще больше люблю repeat)!
Предположим что в цикле предложенном автором ветки, memo.lines.count=5
а в процессе цикла туда прибавляются еще строки, так что цикл новые строки будет игнорировать? ,и остановится там где ему сказали первый раз?
← →
MBo © (2005-02-02 14:46) [8]>Neznaika © (02.02.05 14:43) [7]
В заглавном посте уже сказано, что по стандарту языка for задает количество итераций один раз.
← →
Sha © (2005-02-02 14:49) [9]Neznaika © (02.02.05 14:43) [7]
да
← →
Neznaika © (2005-02-02 14:51) [10]Тогда не зря я больше люблю repeat!!! :)
← →
Poirot © (2005-02-02 14:58) [11]А мона на это чудо ссылочку дать?!:))
← →
Gloomer © (2005-02-02 15:13) [12]>Neznaika © (02.02.05 14:43) [7]
ответ на твой вопрос
procedure TForm1.Button1Click(Sender: TObject);
var i,j:integer;
begin
Memo1.Clear;
for i:=1 to 5 do Memo1.Lines.Add("");
j:=0;
for i:=0 to Memo1.Lines.Count-1 do
begin
Memo1.Lines.Add("111");
inc(j);
end;
ShowMessage(IntToStr(j));
end;
← →
Sha © (2005-02-02 15:24) [13]2 Poirot © (02.02.05 14:58) [11]
http://www.delphimaster.ru/articles/optimization.html
Еще что замечено:
> В case of при возможности используйте элементы, расположенные
> в арифметической прогрессии
Неточность: здесь имеется ввиду возрастающая последовательность.
> Не используйте переменные для временного хранения констант ...
по обстоятельствам: иногда полезно, иногда вредно
> или обязательно объявляйте «магические» числа как const,
еще лучше магические числа вычислять на этапе компиляции,
о чем, впрочем, автор упоминает ниже
> либо подставляйте в код непосредственные значения
и получите код, который будет невозможно сопровождать,
к тому же скорость выполнения на процессорах AMD может существенно упасть.
← →
Владислав © (2005-02-02 16:19) [14]Sha © (02.02.05 15:24) [13]
> Неточность: здесь имеется ввиду возрастающая последовательность.
Только пользы от этого все равно никакой :)
← →
Sha © (2005-02-02 16:28) [15]Владислав © (02.02.05 16:19) [14]
а ты проверь ;)
← →
Владислав © (2005-02-02 16:33) [16]Уже проверял. В свое время у меня на эту тему спор (или, скорее, обсуждение) был с Игорем Шевченко. Он сказал то же самое, и я проверил ;)
← →
Sha © (2005-02-02 17:27) [17]Владислав © (02.02.05 16:33) [16]
Теперь и я проверил. Компилятор поумнел.
Похоже, D6 строит таблицы и деревья переходов при первой возможности.
Интересно, начиная с какой версии?
Сам case почти не использую.
На мой взгляд важнее было бы циклы оптимизировать.
← →
pasha_golub © (2005-02-02 17:45) [18]Вот и свершилось. Наконец-то статьи начали обсуждать в форуме. Считаю это, хорошим делом. Есть предложение для каждой новой статьи создавать ветку. Как вам идея?
← →
Dentall (2005-02-02 17:47) [19]Согласен, допустил грубейшую ошибку. (про циклы). Виной тому - моя преступная невнимательность. (не включил оптимизатор). Что касается изменений, то они высланы, и в скором времени будет все исправлено. Тесты проводились на половина на 7.0, половина уже после обновления до 7.01. Еще раз приношу извинеия.
← →
Владислав © (2005-02-02 17:51) [20]> Sha © (02.02.05 17:27) [17]
Мдя... вообще-то я только в шестерке и проверял :о)
Так что хорошо, что версии одинаковые :о)
← →
Dentall (2005-02-02 17:59) [21]Еще хочу заметить - в новой версии статьи также будет указано "не выносится инвариантный код". Например, если в теле цикла сделать "левое" присвоение, оно будет присваиваться каждую итерацию. Неверное "руководство к действию" удалено.
← →
Sha © (2005-02-02 18:04) [22]Dentall (02.02.05 17:59) [21]
Снеси нафиг обновление 7.01.
Компилятор после него генерит медленный код.
← →
ламер © (2005-02-02 18:46) [23]Sha © (05.02.02 15:24) [13]
про case - всё правильно. нет никакой разницы, в каком порядке идут элементы, но если из них можно составить арифметическую прогрессию, то компилятор сгенерирует таблицу ссылок. если нет - будет много сравнений.
← →
JK (2005-02-03 16:13) [24]Sha © (02.02.05 15:24) [13]
к тому же скорость выполнения на процессорах AMD может существенно упасть.
А можно это пояснить?
← →
Alx2 © (2005-02-03 17:09) [25]>Sha © (02.02.05 18:04) [22]
А в чем тогда смысл этого патча в оптимизаторе?
← →
Cosinus © (2005-02-03 17:11) [26]Простите за off
<offtop> Вы видели использованную литературу в конце статьи? Я понимаю, что фамилия просто похожа, но я смеялся долго, потому что автоматом вспомнился основной продукт этой компании...Касперски К. Техника оптимизации программ. Эффективное использование памяти
</offtop>
← →
miek © (2005-02-03 17:45) [27]По поводу якобы несовершенства дельфийского оптимизатора. Его и нельзя было сделать таким же, как С++ по той простой причине, что при написании компилятора было взято правило: ассемблерный код каждой строки не должен зависеть от кода других строк. Это нужно для того, чтобы можно было в ассемблерных вставках свободно без PUSH/POP использовать регистры общего назначения. Это в справке в BASM написано. Умейте вчитываться, камрады. За все надо платить.
← →
Sha © (2005-02-03 18:32) [28]> JK (03.02.05 16:13) [24]
>> к тому же скорость выполнения на процессорах AMD может
>> существенно упасть.
> А можно это пояснить?
AMD в руководстве по оптимизации кода для своих процессоров
не рекомендует употреблять константы в нескольких последовательно
идущих (или близких) командах. Это дейтвительно так для 3-4
подряд идущих констант.
> Alx2 © (03.02.05 17:09) [25]
> А в чем тогда смысл этого патча в оптимизаторе?
Компилятор Delphi сначала генерирует код на основе паттернов, а
затем оптимизирует получившийся код, в частности удаляет лишние
команды. В большинстве случаев он справляется с этим неплохо.
Данныйт патч, помимо чего-то, для чего он предназначен, по
ошибке разработчиков даунгрэйдит оптимизатор.
Я сам этот патч не ставил. Но по коду, который приводили другие
товарищи, похоже, что качество удаления лишнего резко ухудшается.
> miek © (03.02.05 17:45) [27]
> ... при написании компилятора было взято правило: ассемблерный
> код каждой строки не должен зависеть от кода других строк.
Это не так. Зависит. Например, если два последовательных
оператора используют общее выражение (например, адрес элемента
массива), то оно вычисляется один раз, помещается на регистр,
и потом используется повторно.
> Это нужно для того, чтобы можно было в ассемблерных вставках
> свободно без PUSH/POP использовать регистры общего назначения.
Вовсе нет. Регистры eax, edx, ecx можно свободно использовать
только потому, что в отношении их содержимого компилятор
не делает никаких предположений после ассемблерной вставки.
Если вставки не было, то компилятор в них как правило хранит
индексы и другие часто используемые данные или результаты
текущих вычислений. Другие регистры (еbx, esi, edi, ebp) надо
пушить всегда.
Примерно так написано в справке :)
← →
icWasya © (2005-02-03 20:13) [29]Кстати про эффективное использование памяти
Вот такая задачка возникла при обработке изображений//TestSpeed.dpr
//=============================================
program TestSpeed;
uses
Forms,
UMain in "UMain.pas" {TestForm};
{$R *.RES}
begin
Application.Initialize;
Application.CreateForm(TTestForm, TestForm);
Application.Run;
end.
//UMain.dfm
object TestForm: TTestForm
Left = 309
Top = 168
Width = 264
Height = 145
Caption = "TestForm"
Color = clBtnFace
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -11
Font.Name = "MS Sans Serif"
Font.Style = []
OldCreateOrder = False
OnCreate = FormCreate
PixelsPerInch = 96
TextHeight = 13
object Label1: TLabel
Left = 152
Top = 40
Width = 32
Height = 13
Caption = "Label1"
end
object Label2: TLabel
Left = 152
Top = 72
Width = 32
Height = 13
Caption = "Label2"
end
object ButtonTest1: TButton
Left = 24
Top = 32
Width = 110
Height = 25
Caption = "Test1"
TabOrder = 0
OnClick = ButtonTest1Click
end
object ButtonTest2: TButton
Left = 24
Top = 64
Width = 110
Height = 25
Caption = "Test2"
TabOrder = 1
OnClick = ButtonTest2Click
end
end
//=========================================unit UMain;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls;
type
TTestForm = class(TForm)
ButtonTest1: TButton;
ButtonTest2: TButton;
Label1: TLabel;
Label2: TLabel;
procedure FormCreate(Sender: TObject);
procedure ButtonTest1Click(Sender: TObject);
procedure ButtonTest2Click(Sender: TObject);
private
H,W:Integer;
T1,T2:TDateTime;
S:string;
Sum:Integer;
Massive : array[0..$1000000] of Byte;
Pointers : array[0..4000] of PByteArray;
procedure Init(aW:Integer);
function Test:Integer;
{ Private declarations }
public
{ Public declarations }
end;
var
TestForm: TTestForm;
implementation
{$R *.DFM}
{ TForm1 }
procedure TTestForm.Init(aW: Integer);
var
I:Integer;
begin
H:=High(Pointers);
W:=aW;
for I:=0 to H do Pointers[I]:= @Massive[I*W];
end;
procedure TTestForm.FormCreate(Sender: TObject);
var
I:Integer;
begin
Randomize;
for I:=0 to High(Massive) do Massive[I]:=Random(255);
end;
procedure TTestForm.ButtonTest1Click(Sender: TObject);
begin
Init(4096);
Sum:=Test;
Label1.Caption:=S;
end;
procedure TTestForm.ButtonTest2Click(Sender: TObject);
begin
Init(4097);
Sum:=Test;
Label2.Caption:=S;
end;
function TTestForm.Test:Integer;
var
I,J,K:Integer;
begin
T1:=Now;
Result:=0;
for J:=0 to W-1 do
for I:=0 to H-1 do
Result:=Result+Pointers[I][J];
T2:=Now;
S:=FormatFloat("### ##0.0## ms",(T2-T1)*86400*1000);
end;
end.
//===========================================================
А теперь вопрос - какой тест будет выполнен быстрее и почему??
← →
Sha © (2005-02-03 23:03) [30]> icWasya © (03.02.05 20:13) [29]
В твоем случае быстрее будетfor I:=0 to W*H-1 do Result:=Result+Massive[I];
Как думаешь, почему?
И еще вот такая задачка по арифметике у меня возникла
при прочтении твоего сообщения: что больше$1000000 = 16777216
или5000 * 4096 = 20480000
?
← →
Sha © (2005-02-03 23:25) [31]> icWasya
Задачку можешь не решать :)
Я твои 4000 почему-то прочитал как 5000.
← →
GrayFace © (2005-02-04 06:41) [32]Gloomer © (02.02.05 15:13) [12]
Достаточно этого:for i:=0 to Memo1.Lines.Count do Memo1.Lines.Add("111");
Если бы он вычислял на каждом шаге, был бы бесконечный цикл.
Dentall (02.02.05 17:59) [21]
Еще ошибка:
Не используйте конструкции типа a:=10*sin(45*pi/180); Delphi не вычислит эту константу на этапе компиляции, напротив, будет послушно вызывать sin и pi по ходу выполнения программы! В случае, если угол является переменной, по крайней мере pi можно заменить константой 3,1415...
При включенной оптимизации pi всегда заменяется константой. 45*pi/180 - тоже. При выключенной я не проверял.
Страницы: 1 вся ветка
Форум: "Основная";
Текущий архив: 2005.02.20;
Скачать: [xml.tar.bz2];
Память: 0.55 MB
Время: 0.037 c