Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2003.06.26;
Скачать: CL | DM;

Вниз

Глюки в Дэлфе   Найти похожие ветки 

 
Neft ©   (2003-06-03 17:12) [0]

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


 
Mike B. ©   (2003-06-03 17:14) [1]

Действительно фигня стопудов.


 
Polevi ©   (2003-06-03 17:21) [2]

это хорошие глюки, добрые


 
Юрий Зотов ©   (2003-06-03 17:24) [3]

А у меня дома лампочка глючит. Пока выключателем не щелкнешь - ни фига гореть не хочет. Стопудово!

А раз щелкнул - все равно не горит. И холодильник не работает. Потом сосед пришел - говорит, и у него то же самое. Позвонили еще соседям - и у них то же. Короче, во всем доме такая фигня. А потом само собой у всех загорелось. И холодильники включились. Стопудовый глюк! Честно, сам видел. Че за фигня в датском государстве?


 
Digitman ©   (2003-06-03 17:34) [4]

или чо то типа того !


 
DrPass ©   (2003-06-03 17:57) [5]

Ну ты типакороче там как тибе говорят аптимизатор кода походу выключи да? Ну дык там глюки типа прападут


 
Neft ©   (2003-06-03 20:09) [6]


> Юрий Зотов

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


 
Юрий Зотов ©   (2003-06-03 20:25) [7]

> Neft © (03.06.03 20:09)

> не видел чтобы у всез одновременно глючила делфя

Уверяю Вас, такие "глюки", как Вы описали, есть именно у всех и именно одновременно.


> если это оптимизатор, то как обходить такие глюки, не отрубая
> его

Очень просто - надо писать ТАКОЙ код, чтобы НИ ОДНУ Вашу переменную оптимизатор не считал лишней. Тогда он ее и выбрасывать не будет.


 
Neft ©   (2003-06-03 20:56) [8]

Вот код.

For I:=0 to n-1 do
Begin
For J:=I+1 to n-1 do
Begin
fLambda[0]:=fLambda[0]+KF.c[I,J]*XTemp[I,1]*XTemp[J,1];
fLambda[1]:=fLambda[1]+KF.c[I,J]*XTemp[I,0]*XTemp[J,1]+KF.c[I,J]*XTemp[I,1]*XTemp[J,0];
End;
End;

If fLambda[0]<>0 Then fLambda[0]:=-fLambda[1]/2/fLambda[0] Else fLambda[0]:=0;
if fLambda[0]>1 Then fLambda[0]:=1;//здесь вместо fLambda[0]должна была быть другая переменная, чтобы использоваться в следующем цикле.

For I:=0 to n-1 do
PNew[I]:=P[I]+fLambda[0]*(Z[I]-P[I]);



Ну так вот. Вот тебе пример. если тут реально что то используется неоптимально, то прошу рассказать в чем фишка.
P.S. Я понимаю, что компилятор выдает сообщение о неиспользуемых переменных, но чтобы не выполнять команду... в чем моя ошибка???

> Юрий Зотов



 
Neft ©   (2003-06-03 21:18) [9]

Зотов ответь...


 
Ihor Osov'yak ©   (2003-06-03 21:35) [10]

> здесь вместо fLambda[0]должна была быть другая переменная, чтобы использоваться в следующем цикле.

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

Ты не вумничай, ты код приведи as is.. Тот, к которому у тебя якобы претензии..


 
Neft ©   (2003-06-03 21:38) [11]


> Ihor Osov"yak

а ты не груби

If fLambda[0]<>0 Then fLambda[0]:=-fLambda[1]/2/fLambda[0] Else fLambda[0]:=0;
if fLambda[0]>1 Then fLambda[0]:=1

а нужно было:

If Lambda[0]<>0 Then Lambda:=-fLambda[1]/2/fLambda[0] Else fLambda[0]:=0;
if Lambda>1 Then Lambda:=1


 
Ihor Osov'yak ©   (2003-06-03 21:47) [12]

> а ты не груби

Ну-ну.. Это еще вопрос, кто первым начинает (не по отношению ко мне, а вообще)

> if Lambda>1 Then Lambda:=1


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



 
Юрий Зотов ©   (2003-06-03 21:49) [13]

> Neft

ОК, давайте разбираться. Раз уж речь идет об оптимизаторе, то надо иметь в виду, что с локальными и глобальными переменными он обращается по-разному. Значит, если Вы хотите услышать что-то конкретное, то Вы должны дать, как минимум, такую информацию по КАЖДОМУ используемому идентификатору:

1. Его реальное объявление;
2. Где это объявление стоит;

И, кроме того, где находится приведенный Вами код.

Жду.


 
Neft ©   (2003-06-03 21:53) [14]


> Юрий Зотов

приятно разговаривать с вежливым человеком ))
просто игнорировалась такая строчка
Lambda:=-fLambda[1]/2/fLambda[0];
без всяких ифов и с ними она просто не вычислялась, пришлось делать как сделал. я же говорю что это глюк. неужели никто ни разу не видел как,поднимаеш например одну строчку на позицию вверх и ошибка пропадает. я честно не вру.



 
Ihor Osov'yak ©   (2003-06-03 22:08) [15]

2 Neft © (03.06.03 21:53)

Если Lambda потом нигде не использовалась, то оптимизатор выбрасывал ненужный код.

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

Зы. Это не глюк. Это нормальная работа оптимизирующего компилятора.


 
Юрий Зотов ©   (2003-06-03 22:08) [16]

> Neft © (03.06.03 21:53)

> приятно разговаривать с вежливым человеком

Вы даже более чем правы. Мне тоже.


> я честно не вру.

Я знаю, что Вы не врете. Я даже это очень хорошо знаю. Речь идет не об этом, а о том, чтобы разобраться с причиной. Но я не могу ее показать, потому что не знаю, где и как у Вас объявлены все эти переменные - а именно от этого и зависит поведение оптимизатора.

Поэтому Вам нужно эти объявления привести, иначе я могу сказать только одно - никакой это не глюк, а совершенно нормальная (и очень полезная!) особенность оптимизируещего компилятора. Так что, Вы сами понимаете, что Ваш первый постинг, в котором прозвучала эдакая тинейджерская самоуверенность при полном незнании предмета, был просто смешным. Вот почему над ним и смеялись.

Давайте информацию о переменных - будем смотреть дальше.


 
Neft ©   (2003-06-03 22:14) [17]

Function Search;
Var Proisv : TSyst;
I,J : Integer;
Grad : TPoint;
Z : Array of Real;
Syst : TSyst;
PNew : TPoint;
Res : Byte;
XTemp : Array of Array[0..1] of Real;
fLambda : Array[0..1] of Real;


Lambda была типа Real.
насчет тинейджерской самоуверенности. просто я пишу так как я разговариваю, только маты убираю. вы же понимаете что я в 22 года разговариваю на соответсвующим сленге.


 
Ihor Osov'yak ©   (2003-06-03 22:20) [18]

2 Юрий Зотов

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

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

Приношу еще раз извинения за резкий выпад.


 
Neft ©   (2003-06-03 22:21) [19]


> Юрий Зотов

кстати прогу когда седня посмотрел, вспомнил, что я там недоделал)), так бы вообще пропустил


 
Юрий Зотов ©   (2003-06-04 01:26) [20]

Что-то тут не срастается. Например, объявление
PNew : TPoint;
никак не вяжется с PNew[i] в коде. А объявления P вообще нет. И даже непонятно, все приведенные Вами объявления - локальные по отношению к коду, или внешние (например, локальные в охватывающей функции Search).

Так не годится, или давайте всерьез, или не будем тратить время.


 
k-man ©   (2003-06-04 08:32) [21]

Можно ли параллельно задать вопрос по данной теме Юрию Зотову?
Вопрос такой: Часто при отладке пытаюсь смотреть значения разных переменных из окна Watch. Но бывает натыкаюсь на такое препятствие: вместо значения переменной получаю строку типа "Значение переменной недоступно из-за оптимизации"
Вопрос: Если я отключу ее (оптимизацию) будут ли значения этих переменных видны всегда? И еще: Это происходит далеко не со всеми переменными, Почему? И что дает это не показывание значений в коде?


 
Юрий Зотов ©   (2003-06-04 11:01) [22]

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

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

Если транслятор написан корректно (будем считать, что так оно и есть - а что нам остается?), то на работоспособности программы все это сказывается только в лучшую сторону. Но затрудняет отладку - поэтому и вводится опция отключения оптимизации (а иногда и опции типа "что оптимизировать - размер или скорость").

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

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


 
k-man ©   (2003-06-04 11:29) [23]

Из Вашего ответа я могу сделать вывод о том
1) При отладке приложения оптимизацию можно исключить и включить только при окончательной сборке.(Тут параллельно возникает вопрос, а насколько полезна оптимизация для современных компьютеров с большим кол-вом памяти и высокой часотой процессора).
2) При правильном построении кода не будет этих самых "глюков".
(Тут опять возникает вопрос о том, что есть правильное построение кода....)


 
Юрий Зотов ©   (2003-06-04 11:50) [24]

1. Я всегда так и делаю.

2. Если уж мы пишем не на ассемблере, да еще используем RAD, то говорить об особой уж там оптимизации как-то все же немного странно. Поэтому я стараюсь писать код, руководствуясь, прежде всего, критериями надежности, читабельности, простоты, легкости его будущей модификации, универсальности, повторной используемости и пр. Но и в то же время буквально в каждом слове и в каждой строке думаю, а как это воспримет компилятор и во что это в итоге превратится - то есть, оптимизирую код САМ (кстати, это и есть лучший способ оптимизации, потому что транслятор не гений и много он там наоптимизировать все равно не сможет, да и оптимизировать уже оптимизированный программистом код ему проще, и вероятность внесения им глюков при этом тоже меньше).

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


 
NailMan ©   (2003-06-04 13:35) [25]

Ну тогда я тоже задам такой вопрос касающийся глюков Дельфинариума:

В функции есть цикл, в котором создается объект.
Все бы хорошо, но счетчик цикла почему то не инициализируется с нуля хотя указано прямо:
for i:=0 to ActorCount-1 do ...

var i:integer;

переменная i локальная, в теле for она не изменяется и работает только как счетчик, тоесть не используется для индексации.

Ловлю значение в i при пошаговом выполнении программы и наблюдаю что при первом входе в цикл переменная i либо заблокирована(при наведении мыша значение не показывается) либо в ней значение ActorCount и дальше увеличивается.

Сделал для счетчика переменную NN:integer - все нормально.
Цикл выполняется как положено, с нуля.

Ну и что это за баг такой? Кто мне объяснит?


 
k-man ©   (2003-06-04 13:40) [26]

Опять таки я думаю тебе надо привести полный код функции
со всеми объявлениями.
Говоришь, что если другой идентификатор то все нормально?
Посмотри где у тебя еще может быть описана i.


 
Юрий Зотов ©   (2003-06-04 13:47) [27]

В первом случае компилятор строит код с декрементированием регистра ECX (или EDX) и с переходом JZ (или JNZ) - то есть, как нисходящий. Это хорошо видно в окне CPU и это действительно оптимально. Как он строит его во втором случае - зависит от того, где объявлена переменная NN и как она используется, помимо счетчика цикла.


 
Ihor Osov'yak ©   (2003-06-04 13:57) [28]

2 NailMan © (04.06.03 13:35)

Поставьте точку останова в начале цыкла и после ее срабатывания сделайте CTRL_ALT_C. Если в ассемблере немного разбираетесь, сразу все станет ясно.. Если нет - то в общих чертах дело обстоит так:
для цыклов for если переменная цыкла не используется в цыкле, то в регистр ecx заносится количество выполнений цыкла, а потом при каждом прохождении цыкла делается декремент ecx. Условие окончания цыкла - равенство ecx нулю. Почему компилятор для этого случая делает так? наверное потому, что сравнение с нулем происходит быстрее. Вернее, даже сравнения не нужно - просто анализируется соотв. флаг из регистра флагав после декремента.. И анализ идет не отдельной командой, а командой условного перехода. То есть код получается достаточно компактный и эффективный..

Зы - см. ЮЗ, там где он говорил о переводе смысла, а не о дословном переводе..



 
NailMan ©   (2003-06-04 14:06) [29]

To -> k-man ©
полный код привести не могу, так как функция габаритная, да и глюкает почти в самом начале, привожу краткий кусок:

Function TScene.Load(name:string):boolean;
var i:integer;
Z:integer;
st:string;
begin
... открываю файл сцены и считываю переменные ActorCount, LightCount

//ActorCount считывается со значением 2

for i:=0 to ActorCount-1 do
begin
z:=GetFreeIndex(FREE_ACTOR);
Actor[Z]:=TActor.Create;
...считывание строки с именем конфига в st и параметры расположения в мире
Actor[Z].LoadINI(st);
Actor[Z].MoveToS(0,0,0);
end;

For i:=0 to LightCount-1 do
begin
... считывание данных о источнике света и установка их в i-й источник Light[i]
end;

end;


Собсно глюкает именно в первом цикле c Actor. Второй цикл проходит нормально. Добавляю в var nn:integer; и юзаю его в первом цикле - все нормально.

Посмотри где у тебя еще может быть описана i.
В глобальных переменных никаких счетчиков не описано. Юзается именно локальная.


To -> Юрий Зотов ©
Как он строит его во втором случае - зависит от того, где объявлена переменная NN и как она используется, помимо счетчика цикла.
как я уже говорил NN есть только в локальных переменных данной функции. Нигде больше я не создавал переменных с подобным именем.


Ну что скажете, мастера?


 
evvcom ©   (2003-06-04 14:34) [30]

Тебе она нужна эта i или NN? Ну и чего ты голову всякими пустяками забиваешь? Ну наоптимизировал там чего-то компилятор, что прога не работает разве? Разберись лучше с ассемблером, и тогда на подобные вопросы сможешь сам отвечать без труда.


 
NailMan ©   (2003-06-04 14:40) [31]

To -> evvcom ©
дык работать-то работает, важен сам факт. Я вообще пробовал через repeat until и все прекрасно работает с одной i.


 
Danilka ©   (2003-06-04 14:44) [32]

NailMan © (04.06.03 14:06)
а в каком месте в этом коде точка останова обозначается как "ну вы знаете как обозначются брейпоинты на эндах"?
:))
что-то я не вижу таких мест в этом коде.


 
evvcom ©   (2003-06-04 14:45) [33]

Ну и хорошо, что работает. Компилятор видит, что тебе в этом коде эта i нужна только как счетчик безо всякой индексации и др. расчетов. Вот он и оптимизирует насколько может. Возможно, что в первом случае у него хватило регистров для хранения счетчика, а во втором уже не хватило, и он отвел под эту переменную место в памяти. Соответственно и код уже другой получился.


 
McSimm ©   (2003-06-04 15:04) [34]

Господа, темы с радостными известиями о том что наконец-то найдены глюки в компиляторе поднимались уже очень много раз.
(Причем, похоже, первое место по частоте здесь занимает обратный отсчет в цикле :)
И всегда выяснялось, что никаких глюков на самом деле нет, а имеет место быть нормальная работа оптимизатора кода.


 
McSimm ©   (2003-06-04 15:16) [35]

Вот, думаю в тему будет.
Не далее как вчера некоторое время с удивлением рассматривал фрагмент кода (причем довольно типичный):

K := Arr^[J]; //1
Arr^[J] := Arr^[I]; //2
Arr^[I] := K; //3


Удивляло в этом фрагменте то, что строка //1 не имела исполняемого кода, отладчик проходит только по //2 и по //3.
При этом значение переменной K можно было посмотреть только в строке //3 и оно было верным!
Не правда ли, на первый взгляд кажется загадочным :)

Оказалось все очень просто:

if Arr^[J] < Arr^[I] then // <-здесь отгадка :)
begin
K := Arr^[J];
Arr^[J] := Arr^[I];
Arr^[I] := K;
end;


Чтобы выполнить сравнение компилятор взял значение Arr^[J] в регистр, поскольку выполнить сравнение с двумя индексируемыми ячейками памяти непосредственно он не имеет возможности.
Оптимизатор справедливо рассудил, что значение в регистре вполне заменит использование переменной K и удалил саму переменную и код. А умный отладчик сумел в строке //3 распознать значение, используемое вместо переменной K.


 
Юрий Зотов ©   (2003-06-04 15:38) [36]

> NailMan © (04.06.03 14:06)

> как я уже говорил NN есть только в локальных переменных данной
> функции

Вот этого Вы как раз и не говорили, а говорили вот что:
"Сделал для счетчика переменную NN:integer"
Заметьте - здесь ничего не сказано о том, локальная она, или глобальная, используется ли где-то еще, или нет. А как раз от этого многое и зависит.

Ну, ладно, сказали - и хорошо. Я воспроизвел Вашу ситуацию в D5 (с включенной оптимизацией) на таком макете:

procedure TForm1.Button1Click(Sender: TObject);
var
i: integer;
begin
for i := 0 to 5 do
MessageBeep(0); // Здесь BreakPoint
end;

И затем переменная i заменялась на переменную NN. Так вот, в обоих случаях я прекрасно вижу в отладчике значение счетчика цикла и оно меняется от 6 до 1. А в окне CPU вижу, что в обоих случаях компилятор строит АБСОЛЮТНО одинаковый код:

mov ebx, $00000006 ; начальное значение счетчика цикла в ebx
push $00 ; параметр MessageBeep заталкивается в стек
call -$00000799 ; вызов MessageBeep
dec ebx ; декремент счетчика
jnz TForm1.Button1Click + $6 ; переход на начало по флагу нуля

Что, собственно, и следовало ожидать.

Хорошо, теперь делаем переменную NN глобальной и запускаем тот же самый код. Во-первых, сразу же получаем предупреждение компилятора о том, что этот код он не может оптимизировать. Во-вторых, теперь отладчик показывает, что NN меняется от 0 до 5 - то есть компилятор построил код "в лоб". В-третьих, именно такой "дословный перевод" мы и видим в окне CPU (код не привожу, лень переписывать, хотите - проверьте сами).

Что, собственно, тоже и следовало ожидать.

Делаем выводы:

1. Воспроизвести Вашу ситуацию не удалось. Думаю, потому, что Вы привели неточную или неполную исходную инфоромацию.
2. Никаких глюков не обнаружено.

P.S.
Циклы while и repeat - это другая статья, там нет никаких счетчиков и поэтому к ним такая оптимизация не относится.


 
Neft ©   (2003-06-04 19:49) [37]

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


 
Neft ©   (2003-06-04 19:51) [38]

unit WolfUnit;

interface
Uses GoldSech;
Type
{


 
Neft ©   (2003-06-04 19:54) [39]

Function Search;
Var Proisv : TSyst;
I,J : Integer;
Grad : TPoint;
Z : Array of Real;
Syst : TSyst;
PNew : TPoint;
Res : Byte;
XTemp : Array of Array[0..1] of Real;
fLambda : Array[0..1] of Real;
Begin
SetLength(Proisv,n,n+1);
SetLength(Grad,n);
SetLength(PNew,n);
SetLength(Z,2);

For I:=0 to n-1 do
Begin
For J:=0 to I do
Begin
If I=J Then
Proisv[I,J]:=KF.C[J,I]*2
Else
Proisv[I,J]:=KF.C[J,I];
End;
For J:=I+1 to n-1 do
Begin
Proisv[I,J]:=KF.C[J,I];
End;
Proisv[I,n]:=KF.D[I]
End;


SetLength(Syst,m,n+1);
For I:=0 to m-1 do
For J:=0 to n-1 do
Syst[I,J]:=Ogr.A[I,J];
For I:=0 to m-1 do Syst[I,n]:=Ogr.B[I];


GradCalc(P,Grad,Proisv);
SM(Syst,m,n,Z,Res,Grad);

SetLength(XTemp,n);

For I:=0 to n-1 do
Begin
XTemp[I][0]:=P[I];
XTemp[I][1]:=Z[I]-P[I];
End;

For I:=0 to n-1 do
Begin
XTemp[I][1]:=Z[I]-P[I];
End;

//fLambda[0] -


 
k-man ©   (2003-06-04 20:04) [40]

2Neft
в таких случаях модуль делят.



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

Текущий архив: 2003.06.26;
Скачать: CL | DM;

Наверх




Память: 0.6 MB
Время: 0.026 c
14-84598
nick-from
2003-06-09 11:39
2003.06.26
Подключение контрольно кассовой машины к компу


14-84712
mrcat
2003-06-05 13:04
2003.06.26
Zlib.pas в Delphi 6


14-84623
Vulko
2003-06-06 19:57
2003.06.26
Вам говорит о чем нибудь...


1-84284
delphimun
2003-06-13 12:51
2003.06.26
Как мне приделать, к циклу progressbar?


1-84194
Schredder
2003-06-12 10:45
2003.06.26
Richview или Memo