-
Хочу получать уровень вложенности во время выполнения кода в процедурах/функциях.. Понимаю .что это совсем не тривиально. С др. стороны, наверняка есть инструмент, т.к. думаю часто нужно, да и реализуемо, принципиально
т.е. внутри процедуры что бы вызвать ToLog('Сам напишу название' + IntToStr(Переменная_вложенности)); и при коде procA вызывает(->) procB -> procC -> procB в лог записано procA1 procB2 procC3 procB4
т.е .что-то подобное как в MSSQL переменная @@NESTLEVEL Каждый раз, когда хранимая процедура вызывает другую хранимую процедуру или выполняет управляемый код путем обращения к подпрограмме, типу или статистическому выражению среды CLR, уровень вложенности возрастает.
Что было сделал - написал парсер, который просто после первого begin вставлял инкремент глобальной переменной, а перед выходом - декремент, соотв. Натравил на исходники, переписал он мне их. Но, ошибка уже очевидна - выход может быть не только в конце. Переписал все Exit; на begin dec(Lvl); Exit; end; Лучше, но тоже неправильно. Выход может быть по исключению.
Как бы "сесть" своим кодом на выход и вход в своих процедурах/функциях/методах?
-
> Хочу получать уровень вложенности во время выполнения кода > в процедурах/функциях..
Зачем ?
> т.к. думаю часто нужно
За свои 30 с небольшим лет работы программистом не встречал надобности в таком знании...
-
> Зачем ?
да есть зачем..
регулировать уровень расчетов. Если серверу будет тяжело, можно поставить максимум Ч, например. При rsltБузы или уровне вложенности Ч , дальнейшее уточнение результата считать несущественным
логгировать процесс в приятном виде: уровень - кол-во табуляторов в начале строки
-
пунто зло ) rsltБузы => rslt < eps
-
> Но, ошибка уже очевидна - выход может быть не только в конце.
В try/finally оберни внутренности процедуры.
-
сейчас про Эврику вспомнил если подключить, то так можно
ECS: TEurekaStackList; sLvl: string; begin ECS := GetCurrentCallStack; sLvl := inttostr(ECS.Count);
но там безумные значение - 150, 160 ) оно и понятно - она все, наверное, считает, вроде как label.text := Fnc1() - сначала getter метки, потом fnc, потом setter метки..
-
хотя.. в принципе.. оно же меня не абсолютно интересует, а только возрастает или убывает "функция"
> В try/finally оберни
вариант, конечно но хотелось бы изящнее всю свою лабуду стереть хочу - ну, вроде inc на входе и dec на выходе и Exit => begin dec(Lvl); Exit; end
-
эх, можно было бы, если ECS.Count > предыдущего, то +1, если меньше, то -1 но нет, не пойдет GetCurrentCallStack очень ресурсоемкий вызов, на фоне запросов к базе, даже простейших - не заметно, а когда чисто расчетные циклы, просто подсветить хотя бы внешний из циклов - все, интерфейс умер например время # тики # метка 11:48:41# 32 # -1 11:48:41# 47 # psOn 11:48:41# 46 # psOn 11:48:41# 63 # Enter 11:48:41# 62 # State
а ранее в тиках 0 было обычно
чудес не бывает, похоже )
пойду >> В try/finally оберни делать.. В принципе, интересующих процедур штук 50, не так и много Думаю, если бы Розыч или Игорь что-то и присоветовали - было бы все равно неприемлимо по скорости в некоторых местах.
Спасибо )
-
-
-
Не понял вопроса. Эта функция как раз данные со стека и раскручивает.
-
> Rouse_ © (29.04.16 14:12) [10]
Так, а если я просто в стек положу адрес какой-то процедуры, то эта функция не отличит этот адрес от вызова?
К примеру, процедура: procedure test(..., callback: pointer, ...); // Параметров такое количество, что бы callback передался через стек.
Внутри вызываем StackWalk64. StackWalk64 определит что это просто параметр, а не вызов?
-
-
> ВладОшин © (29.04.16 11:15) [5] > ECS := GetCurrentCallStack; > sLvl := inttostr(ECS.Count); > > но там безумные значение - 150, 160 ) > оно и понятно - она все, наверное, считает, вроде как label. text := Fnc1()
Вашего кода не вижу, но 150, 160 видится странноватыми значениями. У вас рекурсивный алгоритм?
А можно вообще поподробнее, но попонятнее рассказать как так вышло, что необходимо знать вложенность? рекурсивный алгоритм?
-
> StackWalk64 определит что это просто параметр, а не вызов?
Должен по идее. Параметры будут внутри стекового фрейма, адрес возврата на его границе.
-
> Rouse_ © (29.04.16 18:34) [14]
Бегло почитал про стековый фрейм. Не понятно как функция может обнаружить его границу.
-
Функция раскрутки начинает анализировать с себя. Она знает сколько у неё параметров и как они передаётся. Поэтому просто отнимает требуемое число параметров до границы. Затем вычитает 4 байта. В стеке все параметры кратны 4 байта. Там лежит адрес возврата.
Процедура переходит в некоторый код. Далее применяется функция обратной трассировки длины инструкций. Которая работает с 95% успехом. В случае провала пробуется разные границы что доводит успех до 99%. После восстановления начала функции. Анализируется уже тело. Выявляется число параметров в стеке. Тем самым получается вторая граница. Потом анализируется конец функции. Выясняется тип вызова Far или не Near.
После второго вызова раскрутка продолжается с предыдущего шага. Опять вычитается 4 байта или 8 для FAR.
Что-бы не мучиться с обратной трассировкой. Так как это не очень корректный метод применяются отладочные таблицы которые зашиты в конце PE файла. Они передаются через параметр FuncTableEntry В них уже прописано для каждой функции её начало и конец функции, а также её тип и вроде количество параметров.
-
Из пушки по воробьям по-моему.
Если тебе нужно остановить вычисления в тот момент, когда достигнута требуемая точность, то и нужно решать именно эту задачу, а не изобретать звездолет :)
-
писал-писал, и ..закрыл окно ( Вот, жаль))
Да мне не нужен, пожалуй, стек знать. Хотел схитрить.
>>Вашего кода не вижу, но 150, 160 видится странноватыми значениями. Попробую коротко повторить Код жив 17 лет, писался разными людьми. Некоторые, кроме первого, (по комментам сужу) не разбирались в коде, решая свою задачу на тот момент. Нотификаторы из нотификаторов + сообщения из сообщений - в общем, полное спагетти. Иногда все это циклится, не понимаю пока почему. Если не разбираться, то можно было бы выкрутится через уровень вложенности. Но похоже, придется разбираться.
-
О, кстати, еще вспомнил. Все виндовые функции про раскрутку стека вызовов начинают абсолютно врать, выдавая неразумные значения, если по пути вызовов есть вложенные функции. Может это как раз тот случай?
Как с этим справляются разные Eureka и справляются ли - не знаю.
-
> ВладОшин © (04.05.16 19:33) [18] > Иногда все это циклится, не понимаю пока почему.
Тогда 160 - это еще какое-то весьма малое значение )
Вероятно тут всё зависит от условий: один из вызовов (обработчиков сообщений) прерывает "зацикленность" по какому-то условию. А дальше всё зависит от производительности процессора, особенностей разбора очереди в конкретной версии Windows и т.п. Если повезёт - то нужное сообощение, прерывающее цепь вечности, успеет обработаться, пока стек ен переполнился, если не повезёт - то не успевает.
(несколько притянуто за уши, конечно, при наличии лишь одного потока, понимаю; однако почему нет)
|