Вверх ↑
Этот топик читают: Гость
Ответов: 9906
Рейтинг: 351
#196: 2007-07-11 14:48:19 ЛС | профиль | цитата
Dilma писал(а):
очень даже имеем

А вот дулю с маком

Придумал я более научное объяснение происходящему
Вот послушай:

Ровно в тот момент, когда мы поместили "выражение" в поток, мы стали сотворять оптимизационную процедуру moving code
Никто и не говорит, что выполнять такую процедуру не корректно.
Даже нужно, если говорить об оптимизации вообще.

Но делать это надо как-то по-научному, проверяя: ЗЯ, или НИЗЯ
И есть ебщее правило: если неуверен, что ЗЯ, значит НИЗЯ
В простых примерах, что мы ДО этого смотрели - ЗЯ
А вот в таких примерах - НИЗЯ
Add(Button,11036070,98,210)
{
Left=100
Top=20
Caption="Hello"
Data=String(4)
link(onClick,14860139:doStrCat,[])
}
Add(Hub,4606655,224,217)
{
link(onEvent1,5994167:doStrCat,[(271,223)(271,201)(156,201)(156,167)])
link(onEvent2,16577163:doMessage,[])
}
Add(StrCat,5994167,168,161)
{
Str2="222"
}
Add(StrCat,14860139,168,217)
{
Str2="55"
link(onStrCat,4606655:doEvent,[])
link(Str1,5994167:Result,[])
}
Add(Message,16577163,287,224)
{
}


[size=-2]------ Добавлено в 14:48
Собственно я тоже пока не знаю как с таким разобраться.
Знаю же, что нужно.
И думаю, что можно

Надо ли добавлять, что про "однопроходной" вариант преодоления этой проблемы - я и думать не буду
карма: 9

0
Администрация
Ответов: 15295
Рейтинг: 1519
#197: 2007-07-11 15:05:49 ЛС | профиль | цитата
эххе Вот это уже пример на 5+... Тут подумать надо...

[size=-2]------ Добавлено в 14:52
Galkov писал(а):
что про "однопроходной" вариант преодоления этой проблемы - я и думать не буду

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

[size=-2]------ Добавлено в 15:05
Дошло: проблема при таком подходе в хабе. И во всех элементах, безусловно дублирующих входной поток. Грубо говоря однопроходным может быть примерно такое решение:
1) данным добавляется атрибут volatile - признак изменения данных
2) любой элемент, который выпускает из-под себя копии одних и тех же данных должен проверить их на наличие этого атрибута
3) если таковой имеется, то данные нужно сохранить.

Скажем счетчик цикла for не является volatile данными. Конкатенация строк должна перед выдачей в поток проверить на наличие такого флага у каждого операнда и присвоить его всему выражению, если он есть.
карма: 27
0
Ответов: 9906
Рейтинг: 351
#198: 2007-07-11 15:49:40 ЛС | профиль | цитата
Dilma писал(а):
Дошло: проблема при таком подходе в хабе. И во всех элементах, безусловно дублирующих входной поток

Не совсем так.
HUB - это бедный несчастный элемент, на которого всех собак вешают
В FASM-е, к примеру, его вообще заставили быть функциональным вызовом...

Внутри какого-то элемента, не HUB-а вовсе, может произойти (а может и нет, а может это и не разрешимо в Design-Time) вызов события c данными вовсе к данным потока не имеющим отношение.
И после этого произойдет использование данных потока.
А событие ДО могло и изменить один из параметров выражения.

Dilma писал(а):
Скажем счетчик цикла for не является volatile данными. Конкатенация строк должна перед выдачей в поток проверить на наличие такого флага у каждого операнда и присвоить его всему выражению, если он есть

Давай по порядку.
В вышеприведенном примере начинаем плясать от кнопки.
1) Вызывается doStrCat (нижний)
2) У него внутри идет обращение к верхней точке. Какие данные и с каким аттрибутом вернутся ???
3) Вызывается Result верхнего элемента - он увидел "подключенность" doStrCat и вернул ссылку на переменную, а не выражение
4) Причин в качестве аттрибута возвращать что-то экстраординарное вроде никаких, совершенно штатная ситуация. Мало ли куда его doStrCat подулючен...
5) В нижнем StrCat для Str2 - тоже все штатно.
6) Начинаем парсить выходное событие. Начинаем, а данных то и нет. В смысле - не все с ними ясно.

Но возможен иной вариант:
если по п.3 предыдущего списка мы взвели некий флажок (Using) для некой переменной (S) которая возвращается методом Result, ТОГДА - если при парсинге по п.7 мы напоролись на такой флажок, то это уже информативное событие. Переключаем флажок в состояние Chanded.

И только после парсинга, нам надо как-то узнать о состоянии этого флажка. Который до парсинга был установлен в Using. Снова вызывать событие Str1 - нельзя, мало ли какие коды при этом в каких блоках сгенерируются...
Но использовать это результат сравнения можно будет только на втором проходе

Т.е., однопроходных возможностей я совсем не понял....
карма: 9

0
Администрация
Ответов: 15295
Рейтинг: 1519
#199: 2007-07-11 16:20:27 ЛС | профиль | цитата
Galkov писал(а):
Т.е., однопроходных возможностей я совсем не понял....

примерно так:

func doStrCat()
  fvar(s1,s2)
s1 = Str1
s2 = Str2
if( isVolatile(s1) or isVolatile(s2) )
println(buf, ' := ', s1 & s2, ';')
event(onStrCat, volatile(buf))
else
event(onStrCat, s1 & s2)
end
end

собственно реализуем весь этот код в lng как метод буферизации данных в случае наличия Volatile и получаем:
func doStrCat()
  fvar(s1,s2)
s1 = Str1
s2 = Str2
event(onStrCat, lng.bufIfVolatile(s1 & s2))
end

либо тоже самое, но в хабе:
func doEvent()
  fvar(buf)
buf = lng.bufIfVolatile(_data_)
for(...)
ebent(onEvent, buf)
end
end
карма: 27
0
Ответов: 9906
Рейтинг: 351
#200: 2007-07-11 16:28:47 ЛС | профиль | цитата
Я понимаю, что isVolatile(s1) это возврат какого-то бита.
Я не понимаю мехенизма установки этого бита для S1 таким образом, чтобы все сработало за один проход.
карма: 9

0
Администрация
Ответов: 15295
Рейтинг: 1519
#201: 2007-07-11 17:36:10 ЛС | профиль | цитата
Каджый элемент при выдаче данных в поток должен решить могут ли они(данные) меняться не зависимо. Грубо говоря в общем случае данные Volatile, если про них знает не только данный элемент. Скажем элемент for выдает в поток индекс, который может поменять только он сам. Элемент memory обладает внутренней ячейкой, которую может изменять только он. В примере со Stream данные читаемые из потока всегда Volatile. и т.д. Т.е. каждый элемент по идее должен обладать достаточной иниформацией о данных, которые к нему приходят и от него уходят.
карма: 27
0
Ответов: 9906
Рейтинг: 351
#202: 2007-07-11 19:41:17 ЛС | профиль | цитата
Ну расскажи тогда, чего знает элемент StrCat в вышеприведенном примере

[size=-2]------ Добавлено в 19:41
Можно ли конкретно в однопроходном варианте предложить схему для разрешения этого конфликта именно в этом примерчике, с двумя StrCat...
карма: 9

0
Администрация
Ответов: 15295
Рейтинг: 1519
#203: 2007-07-11 22:42:10 ЛС | профиль | цитата
Galkov писал(а):
Ну расскажи тогда, чего знает элемент StrCat в вышеприведенном примере

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

Galkov писал(а):
Можно ли конкретно в однопроходном варианте предложить схему для разрешения этого конфликта именно в этом примерчике, с двумя StrCat..

да. Схему уже описал выше:
1) Верхний StrCat выдает данные с нижней точки с признаком Volatile
2) Hub перед трансляцией данных на правые точки проверяет наличие этого признака
3) если признак есть, то данные в хабе буферизируются
4) в итоге получаем код:

procedure onClick();
begin
hub_data := s1 + 55;
s1 := hub_data + 222;
Message(hub_data);
end;

то, что это защита от дурака взамен качества - я понимаю прекрасно. Конечно же нужно иметь счетчики использований и присваиваний для выполнения тех же самых операций, но в самих элементах, пораждающих такие данные.
карма: 27
0
Ответов: 9906
Рейтинг: 351
#204: 2007-07-12 13:05:11 ЛС | профиль | цитата
Ну хорошо... Будем считать, что понял.
Если в верхнем StrCat "не подключена" точка doStrCat, то нет признака в результате. И следовательно нет его в выходных данных нижнего StrCat, и ничего HUB-ом не буферизируется...

Тогда уж надо, чтобы "конструктора" кодов из CG делали этот аттрибут автоматически из аттрибутов операндов, по логическому ИЛИ
В смысле, чтобы данные в таком потоке
event(onStrCat, s1 & s2)[/code]содержали код с уже правильным аттрибутом 

Кто ставит этот аттрибут - понятно.
В этой логике, если вспомнить мой первый пример, то Stream всегда должен возвращаться с аттрибутом Volatile - нет вопросов.

Кто же использует этот аттрибут...
Валить все на бедного HUB-а - не правильно, вроде бы :roll:
Ну не виноватый он :!:
Получается, что использовать ДОЛЖЕН кто угодно по одному простому признаку:
[quote]Метод элемента вызывает более одного события (в т.ч. и верхние точки), и события после первого используют данные из потока.[/quote]
HUB под этот признак проходит
Но под него как раз проходит и StrCat из первого примера (а HUB-а там и нет).
Если с HUB-ом все просто - срабатывание этого критерия видно сразу и до компиляции, то с остальными - нет.

Это вообще, только CG может увидеть.

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







[size=-2]------ Добавлено в 13:05 [/size]
Вот чего я еще подумал.
Пока схема грубоватая конечно... А как ее сделать более точной, хотя бы в последствии :?:

[u]Пока в голову пришло такое[/u]:

Вместо аттрибута Volatile надо сделать список "точек достижения"
Если он пустой - нет проблем и с кодом
Элемент StrCat к коду, возвращаемому ф-ей Result аттачит список точек, которые "достают" до doSrtCat. А элемент FileStream - тех, которые "достают" до точки Stream.
Каждый элемент имеет для каждой точки свой список: правые и верхние - список левых и нижних точек, которые могут активизировать именно эту; левые и нижние - список правых и верхних других элементов, связанных по схеме.
Теоретически, первые списки - это схемно-независимая характеристика именно класса элемента, а для создания второго списка методы элементов можно вроде и не парсить
Но всей схемой прошелестеть придется... Но один раз, вроде... Хотя...

Если такие списки готовы, то к данным можно добавить именно "голобальный список точек достижения"
Далее - все просто: "конструкторы данных" из CG объединяют списки; а при реализации [b]event[/b] из этого же метода, где и "сконструировались" данные - делается вышеозначенная языковая буфферизация, если это событие для точки, которая есть в списке "достижения" для передаваемых данных.
Хорошо бы еще различать сам факт использования передаваемых данных...

Кажется, что такое было бы уже по полной программе
карма: 9

0
Администрация
Ответов: 15295
Рейтинг: 1519
#205: 2007-07-12 15:57:54 ЛС | профиль | цитата
эта задача решаема приемлема только в рамках честной двупроходности Достаточно всего лишь при первом проходе в CG для каждого кортежа(tsdima(C)) данных завести списки с номерами элементов использования и присваивания. Тогда автоматом получаем количество использований и кроме того получаем информация о том, что происходит раньше - чтение или запись - путем сравнения первых номеров из обоих списков.
карма: 27
0
Ответов: 9906
Рейтинг: 351
#206: 2007-07-12 16:42:55 ЛС | профиль | цитата
Ну да...
Но это не совсем "честная" двухпроходность
Скорее "полуторапроходность": во время "первого" прохода можно не парсить методы элементов, а взаимосвязь от входной точки до выходной брать из какого-нибудь (непридуманного еще) конфига на элемент.




[size=-2]------ Добавлено в 16:42
Есть правда одна заморочка...
В смысле: не совсем полное достижение желаемой оптимальности.

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

Скажем, про любимый нами HUB
Первая его выходная точка "недостижима" для входного кода, а вторая - "достижима" и честно его портит.
Пусть даже, для простоты, это второе событие и данных из потока не берет - например делает doClear какому-нибудь Memory, точка Value которого и начинает наш "зависимый" код

По нашей логике - HUB обязательно забуферизирует это дело.
Хоть и правильно все, но некий дискомфорт от того, что свой великий интеллект мы так до конца и не воплотили - остается

Аналогично в примерчике FileStream - поменяй местами точки Str1 и Str2, и никакой буферизации тоже не надо...
По той же причине: "достижимое" событие происходит после реализации кода...
карма: 9

0
Администрация
Ответов: 15295
Рейтинг: 1519
#207: 2007-07-12 16:53:12 ЛС | профиль | цитата
Galkov писал(а):
брать из какого-нибудь (непридуманного еще) конфига на элемент.

это не очень хорошо. Лишняя работа
карма: 27
0
Ответов: 9906
Рейтинг: 351
#208: 2007-07-13 10:22:33 ЛС | профиль | цитата
Ну я не настаиваю

[size=-2]------ Добавлено в 10:22
Хотя с другой стороны, некие байт-коды элементов, как результат предварительной компиляции скриптов, тоже есть некие "непридуманные еще конфиги"
В философском смысле...
карма: 9

0
Ответов: 9906
Рейтинг: 351
#209: 2007-07-16 15:55:48 ЛС | профиль | цитата
Но все-таки не все ладно в нашем королевстве, мне продолжает казаться...
Специально повторюсь: это все я не специально придумываю, мысли сами в голову лезут


Вроде бы вышеупомянутого перечня зависимости точек для элемента (не важно, каким образом добытого: парсингом, или из конфига) - не достаточно.
В смысле: понятно, что любая информация - это лучше, чем ее отсутствие. Но лучше иметь максимально полную информацию.
Не задаваясь вопросом, нужна ли она именно сегодня. Принимая за аксиому, что все равно понадобится (хотя, возможно - и не сразу). Главное - определить объем этой информации, и сформировать механизмы доступа к ней.
Мне (сегодня) такая информация об элементе представляется примерно в таком виде. Для каждого метода элемента указываем не только вызываемые события, но и их последовательность
doStrCat
  <Str1>,<Str2>,onStrCat
Более того, можем указать альтернативные варианты последовательностей
doCompare: <Op1>Type<Op2>
  <Op1>,<Op2>,onTrue
doCompare: not <Op1>Type<Op2>
<Op1>,<Op2>,onFalse
Смысл необязательных условий на "варианте" имеется только тогда, когда они могут быть вычислены в Design-Time
Естественно.
Но когда это происходит - это оптимизация типа Dead End Elimination.
Ну, к примеру, если никогда не происходящий onFalse меняет какие-то данные, то сия "подключенность" уже никак не добавит точку doCompare в список "достижимых" при определении обсуждаемого ранее качества Volatile

А разбиение на "вариантность", позволит установить в таком примере
Add(Hub,15612280,182,140)
{
link(onEvent1,9960986:doClear,[(294,146)(294,111)])
link(onEvent2,1693346:doCompare,[])
}
Add(If_else,1693346,238,147)
{
Op2=String(!!!)
link(onTrue,9960986:doValue,[(286,153)(286,104)])
link(onFalse,6964309:doCompare,[])
link(Op1,9158563:Text,[])
}
Add(Memory,9960986,301,98)
{
Default=Integer(0)
}
Add(Edit,9158563,238,98)
{
Left=230
Top=70
}
Add(If_else,6964309,301,154)
{
Op2=Integer(0)
link(Op1,9960986:Value,[])
}
"недостижимость" точки Memory.doValue при вычислении Op1 во втором If_Else И в нем, кстати, условие и посчитается в Design-Time
Если, конечно, мы умеем устанавливать вышеупомянутую "недостижимость"


Это скажем информация о классе элемента. И она должна быть превращена CG в информацию для КОНКРЕТНОГО элемента.
Парсингом, или еще как-то, но в этих "строках" должна появиться информация об использовании входных данных, и именно в нужном месте. Ну например
doCompare:
  Op1,D0,onTrue(data)
doCompare:
Op1,D0,onFalse(data)
- здесь имеется в виду, что: а) условие не разрешимо в design-time б) первый операнд идет с верхней точки в) второй из потока (первые данные из MT-списка) г) на выход попадают данные потока. Если факт одного использования установлен (второй операнд), и точно известно, что он ПОСЛЕ события Op1, и ДО событий onTrue или onFalse, то факт использования в выходном событии - только на последующих проходах (кстати, кроме самого факта использования, лучше бы знать и к какому типу данные приводились при использовании).
А ведь это влияет на принятие решения про "буферизацию"
Если Op1 не "портит" входной код, то буферизацию все равно надо провести, при двойном (или больше) использовании входного кода...
Т.е., при этой реализации, принятие решения зависит от фактора "использования" выходным потоком

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

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


А если еще подумать, когда нам нужна "буферизация", то начинает доходить, что ровно тот же разговор применим и к верхним событиям
Т.е., код, полученный сверху, может прямо в коде элемента использоваться неоднократно
Ну, скажем в неком гипотетическом скрипте написано:
  fvar(s1,s2)
  s1 = Str1
s2 = Str2
println(s1,s2,s1)
Где и кто должен писать код буферизации?
Мне представляется, что именно CG при обработке точки Str1 по информации MultiUsed от предыдущих проходов.
Так же как и для обработки event - мне здесь тоже так кажется.


И все-таки информации, заложенной в SubType - явно не хватает. Ну хорошо, пусть мы установили факт MultiUsed и провели "буферизацию". Все равно в данных у нас код, но того, что дальше заниматься буферизацией уже не умно - у нас ведь никакой...
Add(Hub,15612280,182,140)
{
link(onEvent1,4880539:doWork2,[])
link(onEvent2,1693346:doCompare,[])
}
Add(If_else,1693346,238,147)
{
link(onTrue,4880539:doWork3,[(291,153)])
link(Op1,9158563:Text,[])
}
Add(Memory,9960986,308,140)
{
Default=Integer(0)
}
Add(Edit,9158563,238,98)
{
Left=230
Top=70
}
Add(HubEx,4880539,287,133)
{
link(onEvent,9960986:doValue,[])
}
Add(StrCat,5994167,126,140)
{
Str2="222"
link(onStrCat,15612280:doEvent1,[])
}
Установили мы, что для HUB есть факт MultiUsed
Отлично, проводим "буферизацию"
Но для If_else тоже есть факт MultiUsed
А ведь причин для "буферизации" - уже никаких
Вопрос ведь...
карма: 9

0
Администрация
Ответов: 15295
Рейтинг: 1519
#210: 2007-07-16 16:16:57 ЛС | профиль | цитата
как раз в последнем примере информации очень даже хватает. Проверяем count(_data_) > 1 и в случае успеха занимаемся буферизацией.
карма: 27
0
Сообщение
...
Прикрепленные файлы
(файлы не залиты)