Форум: "Прочее";
Текущий архив: 2017.05.21;
Скачать: [xml.tar.bz2];
ВнизПолучить уровень вложенности кода. Найти похожие ветки
← →
ВладОшин © (2016-04-29 09:59) [0]Хочу получать уровень вложенности во время выполнения кода в процедурах/функциях..
Понимаю .что это совсем не тривиально. С др. стороны, наверняка есть инструмент, т.к. думаю часто нужно, да и реализуемо, принципиально
т.е. внутри процедуры что бы вызвать
ToLog("Сам напишу название" + IntToStr(Переменная_вложенности));
и
при коде
procA вызывает(->) procB -> procC -> procB
в лог записано
procA1
procB2
procC3
procB4
т.е .что-то подобное как в MSSQL переменная @@NESTLEVEL
Каждый раз, когда хранимая процедура вызывает другую хранимую процедуру или выполняет управляемый код путем обращения к подпрограмме, типу или статистическому выражению среды CLR, уровень вложенности возрастает.
Что было сделал - написал парсер, который просто после первого begin
вставлял инкремент глобальной переменной, а перед выходом - декремент, соотв. Натравил на исходники, переписал он мне их.
Но, ошибка уже очевидна - выход может быть не только в конце. Переписал все Exit; на begin dec(Lvl); Exit; end; Лучше, но тоже неправильно. Выход может быть по исключению.
Как бы "сесть" своим кодом на выход и вход в своих процедурах/функциях/методах?
← →
Игорь Шевченко © (2016-04-29 10:24) [1]
> Хочу получать уровень вложенности во время выполнения кода
> в процедурах/функциях..
Зачем ?
> т.к. думаю часто нужно
За свои 30 с небольшим лет работы программистом не встречал надобности в таком знании...
← →
ВладОшин © (2016-04-29 10:41) [2]
> Зачем ?
да есть зачем..
регулировать уровень расчетов. Если серверу будет тяжело, можно поставить максимум Ч, например. При rsltБузы или уровне вложенности Ч , дальнейшее уточнение результата считать несущественным
логгировать процесс в приятном виде: уровень - кол-во табуляторов в начале строки
← →
ВладОшин © (2016-04-29 10:42) [3]пунто зло )
rsltБузы => rslt < eps
← →
Kerk © (2016-04-29 10:47) [4]
> Но, ошибка уже очевидна - выход может быть не только в конце.
В try/finally оберни внутренности процедуры.
← →
ВладОшин © (2016-04-29 11:15) [5]сейчас про Эврику вспомнил
если подключить, то так можно
ECS: TEurekaStackList;
sLvl: string;
begin
ECS := GetCurrentCallStack;
sLvl := inttostr(ECS.Count);
но там безумные значение - 150, 160 )
оно и понятно - она все, наверное, считает, вроде как label.text := Fnc1()
- сначала getter метки, потом fnc, потом setter метки..
← →
ВладОшин © (2016-04-29 11:23) [6]хотя.. в принципе..
оно же меня не абсолютно интересует, а только возрастает или убывает "функция"
> В try/finally оберни
вариант, конечно
но хотелось бы изящнее
всю свою лабуду стереть хочу
- ну, вроде inc на входе и dec на выходе и Exit => begin dec(Lvl); Exit; end
← →
ВладОшин © (2016-04-29 11:55) [7]эх, можно было бы, если 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_ © (2016-04-29 13:17) [8]Я бы в принципе посоветовал вот в эту сторону смотреть: https://msdn.microsoft.com/en-us/library/windows/desktop/ms680650(v=vs.85).aspx
но по скорости не тестировал, в моей утилите работает в принципе с устраивающей меня скоростью
← →
DayGaykin © (2016-04-29 14:02) [9]
> Я бы в принципе посоветовал вот в эту сторону смотреть:
> https://msdn.microsoft.com/en-us/library/windows/desktop/ms680650(v=vs.
> 85).aspx
Неужели во время вызова call помимо того что в стек кладется адрес возврата, еще куда-то сохраняется информация о вызове?
← →
Rouse_ © (2016-04-29 14:12) [10]Не понял вопроса. Эта функция как раз данные со стека и раскручивает.
← →
DayGaykin © (2016-04-29 14:25) [11]
> Rouse_ © (29.04.16 14:12) [10]
Так, а если я просто в стек положу адрес какой-то процедуры, то эта функция не отличит этот адрес от вызова?
К примеру, процедура:
procedure test(..., callback: pointer, ...); // Параметров такое количество, что бы callback передался через стек.
Внутри вызываем StackWalk64.
StackWalk64 определит что это просто параметр, а не вызов?
← →
Игорь Шевченко © (2016-04-29 14:50) [12]ВладОшин © (29.04.16 10:41) [2]
http://www.gunsmoker.ru/2008/10/x-y-z.html
← →
KSergey © (2016-04-29 18:00) [13]> ВладОшин © (29.04.16 11:15) [5]
> ECS := GetCurrentCallStack;
> sLvl := inttostr(ECS.Count);
>
> но там безумные значение - 150, 160 )
> оно и понятно - она все, наверное, считает, вроде как label. text := Fnc1()
Вашего кода не вижу, но 150, 160 видится странноватыми значениями.
У вас рекурсивный алгоритм?
А можно вообще поподробнее, но попонятнее рассказать как так вышло, что необходимо знать вложенность? рекурсивный алгоритм?
← →
Rouse_ © (2016-04-29 18:34) [14]
> StackWalk64 определит что это просто параметр, а не вызов?
Должен по идее.
Параметры будут внутри стекового фрейма, адрес возврата на его границе.
← →
DayGaykin © (2016-04-29 18:57) [15]
> Rouse_ © (29.04.16 18:34) [14]
Бегло почитал про стековый фрейм. Не понятно как функция может обнаружить его границу.
← →
Pavia © (2016-04-29 20:17) [16]Функция раскрутки начинает анализировать с себя. Она знает сколько у неё параметров и как они передаётся. Поэтому просто отнимает требуемое число параметров до границы.
Затем вычитает 4 байта. В стеке все параметры кратны 4 байта.
Там лежит адрес возврата.
Процедура переходит в некоторый код. Далее применяется функция обратной трассировки длины инструкций. Которая работает с 95% успехом.
В случае провала пробуется разные границы что доводит успех до 99%.
После восстановления начала функции. Анализируется уже тело. Выявляется число параметров в стеке. Тем самым получается вторая граница.
Потом анализируется конец функции. Выясняется тип вызова Far или не Near.
После второго вызова раскрутка продолжается с предыдущего шага.
Опять вычитается 4 байта или 8 для FAR.
Что-бы не мучиться с обратной трассировкой. Так как это не очень корректный метод применяются отладочные таблицы которые зашиты в конце PE файла. Они передаются через параметр FuncTableEntry В них уже прописано для каждой функции её начало и конец функции, а также её тип и вроде количество параметров.
← →
Kerk © (2016-04-29 22:44) [17]Из пушки по воробьям по-моему.
Если тебе нужно остановить вычисления в тот момент, когда достигнута требуемая точность, то и нужно решать именно эту задачу, а не изобретать звездолет :)
← →
ВладОшин © (2016-05-04 19:33) [18]писал-писал, и ..закрыл окно (
Вот, жаль))
Да мне не нужен, пожалуй, стек знать. Хотел схитрить.
>>Вашего кода не вижу, но 150, 160 видится странноватыми значениями.
Попробую коротко повторить
Код жив 17 лет, писался разными людьми. Некоторые, кроме первого, (по комментам сужу) не разбирались в коде, решая свою задачу на тот момент. Нотификаторы из нотификаторов + сообщения из сообщений - в общем, полное спагетти.
Иногда все это циклится, не понимаю пока почему.
Если не разбираться, то можно было бы выкрутится через уровень вложенности.
Но похоже, придется разбираться.
← →
KSergey © (2016-05-05 10:12) [19]О, кстати, еще вспомнил.
Все виндовые функции про раскрутку стека вызовов начинают абсолютно врать, выдавая неразумные значения, если по пути вызовов есть вложенные функции.
Может это как раз тот случай?
Как с этим справляются разные Eureka и справляются ли - не знаю.
← →
KSergey © (2016-05-05 10:17) [20]> ВладОшин © (04.05.16 19:33) [18]
> Иногда все это циклится, не понимаю пока почему.
Тогда 160 - это еще какое-то весьма малое значение )
Вероятно тут всё зависит от условий: один из вызовов (обработчиков сообщений) прерывает "зацикленность" по какому-то условию.
А дальше всё зависит от производительности процессора, особенностей разбора очереди в конкретной версии Windows и т.п. Если повезёт - то нужное сообощение, прерывающее цепь вечности, успеет обработаться, пока стек ен переполнился, если не повезёт - то не успевает.
(несколько притянуто за уши, конечно, при наличии лишь одного потока, понимаю; однако почему нет)
Страницы: 1 вся ветка
Форум: "Прочее";
Текущий архив: 2017.05.21;
Скачать: [xml.tar.bz2];
Память: 0.5 MB
Время: 0.002 c