Конференция "Прочее" » Получить уровень вложенности кода.
 
  • ВладОшин © (29.04.16 09:59) [0]
    Хочу получать уровень вложенности во время выполнения кода в процедурах/функциях..
    Понимаю .что это совсем не тривиально. С др. стороны, наверняка есть инструмент, т.к. думаю часто нужно, да и реализуемо, принципиально

    т.е. внутри процедуры что бы вызвать
    ToLog('Сам напишу название' + IntToStr(Переменная_вложенности));
    и
    при коде
    procA вызывает(->) procB -> procC -> procB
    в лог записано
    procA1
    procB2
    procC3
    procB4

    т.е .что-то подобное как в MSSQL переменная @@NESTLEVEL
    Каждый раз, когда хранимая процедура вызывает другую хранимую процедуру или выполняет управляемый код путем обращения к подпрограмме, типу или статистическому выражению среды CLR, уровень вложенности возрастает.

    Что было сделал - написал парсер, который просто после первого begin
    вставлял инкремент глобальной переменной, а перед выходом - декремент, соотв. Натравил на исходники, переписал он мне их.
    Но, ошибка уже очевидна - выход может быть не только в конце. Переписал все Exit; на begin dec(Lvl); Exit; end; Лучше, но тоже неправильно. Выход может быть по исключению.

    Как бы "сесть" своим кодом на выход и вход в своих процедурах/функциях/методах?
  • Игорь Шевченко © (29.04.16 10:24) [1]

    > Хочу получать уровень вложенности во время выполнения кода
    > в процедурах/функциях..


    Зачем ?


    > т.к. думаю часто нужно


    За свои 30 с небольшим лет работы программистом не встречал надобности в таком знании...
  • ВладОшин © (29.04.16 10:41) [2]

    > Зачем ?

    да есть зачем..

    регулировать уровень расчетов. Если серверу будет тяжело, можно поставить максимум Ч, например. При rsltБузы или уровне вложенности Ч , дальнейшее уточнение результата считать несущественным

    логгировать процесс в приятном виде:  уровень - кол-во табуляторов в начале строки
  • ВладОшин © (29.04.16 10:42) [3]
    пунто зло )
    rsltБузы => rslt < eps
  • Kerk © (29.04.16 10:47) [4]

    > Но, ошибка уже очевидна - выход может быть не только в конце.

    В try/finally оберни внутренности процедуры.
  • ВладОшин © (29.04.16 11:15) [5]
    сейчас про Эврику вспомнил
    если подключить, то так можно

     ECS: TEurekaStackList;
     sLvl: string;
    begin
     ECS := GetCurrentCallStack;
     sLvl := inttostr(ECS.Count);

    но там безумные значение - 150, 160 )
    оно и понятно - она все, наверное, считает, вроде как label.text := Fnc1()
    - сначала getter метки, потом fnc, потом setter метки..
  • ВладОшин © (29.04.16 11:23) [6]
    хотя.. в принципе..
    оно же меня не абсолютно интересует, а только возрастает или убывает "функция"


    > В try/finally оберни

    вариант, конечно
    но хотелось бы изящнее  
    всю свою лабуду стереть хочу
    - ну, вроде inc на входе и dec на выходе и Exit => begin dec(Lvl); Exit; end
  • ВладОшин © (29.04.16 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_ © (29.04.16 13:17) [8]
    Я бы в принципе посоветовал вот в эту сторону смотреть: https://msdn.microsoft.com/en-us/library/windows/desktop/ms680650(v=vs.85).aspx

    но по скорости не тестировал, в моей утилите работает в принципе с устраивающей меня скоростью
  • DayGaykin © (29.04.16 14:02) [9]

    > Я бы в принципе посоветовал вот в эту сторону смотреть:
    > https://msdn.microsoft.com/en-us/library/windows/desktop/ms680650(v=vs.
    > 85).aspx

    Неужели во время вызова call помимо того что в стек кладется адрес возврата, еще куда-то сохраняется информация о вызове?
  • Rouse_ © (29.04.16 14:12) [10]
    Не понял вопроса. Эта функция как раз данные со стека и раскручивает.
  • DayGaykin © (29.04.16 14:25) [11]

    > Rouse_ ©   (29.04.16 14:12) [10]

    Так, а если я просто в стек положу адрес какой-то процедуры, то эта функция не отличит этот адрес от вызова?

    К примеру, процедура:
    procedure test(..., callback: pointer, ...); // Параметров такое количество, что бы callback передался через стек.

    Внутри вызываем StackWalk64.
    StackWalk64 определит что это просто параметр, а не вызов?
  • Игорь Шевченко © (29.04.16 14:50) [12]
    ВладОшин ©   (29.04.16 10:41) [2]

    http://www.gunsmoker.ru/2008/10/x-y-z.html
  • KSergey © (29.04.16 18:00) [13]
    > ВладОшин ©   (29.04.16 11:15) [5]
    >  ECS := GetCurrentCallStack;
    >  sLvl := inttostr(ECS.Count);
    >
    > но там безумные значение - 150, 160 )
    > оно и понятно - она все, наверное, считает, вроде как label. text := Fnc1()

    Вашего кода не вижу, но 150, 160 видится странноватыми значениями.
    У вас рекурсивный алгоритм?

    А можно вообще поподробнее, но попонятнее рассказать как так вышло, что необходимо знать вложенность? рекурсивный алгоритм?
  • Rouse_ © (29.04.16 18:34) [14]

    > StackWalk64 определит что это просто параметр, а не вызов?

    Должен по идее.
    Параметры будут внутри стекового фрейма, адрес возврата на его границе.
  • DayGaykin © (29.04.16 18:57) [15]

    > Rouse_ ©   (29.04.16 18:34) [14]

    Бегло почитал про стековый фрейм. Не понятно как функция может обнаружить его границу.
  • Pavia © (29.04.16 20:17) [16]
    Функция раскрутки начинает анализировать с себя. Она знает сколько у неё параметров и как они передаётся. Поэтому просто отнимает требуемое число параметров до границы.
    Затем вычитает 4 байта. В стеке все параметры кратны 4 байта.
    Там лежит адрес возврата.

    Процедура переходит в некоторый код. Далее применяется функция обратной трассировки длины инструкций. Которая работает с 95% успехом.
    В случае провала пробуется разные границы что доводит успех до 99%.
    После восстановления начала функции. Анализируется уже тело. Выявляется число параметров в стеке. Тем самым получается вторая граница.
    Потом анализируется конец функции. Выясняется тип вызова Far или не Near.

    После второго вызова раскрутка продолжается с предыдущего шага.
    Опять вычитается 4 байта или 8 для FAR.

    Что-бы не мучиться с обратной трассировкой. Так как это не очень корректный метод применяются отладочные таблицы которые зашиты в конце PE файла.  Они передаются через параметр FuncTableEntry В них уже прописано для каждой функции её начало и конец функции, а также её тип и вроде количество параметров.
  • Kerk © (29.04.16 22:44) [17]
    Из пушки по воробьям по-моему.

    Если тебе нужно остановить вычисления в тот момент, когда достигнута требуемая точность, то и нужно решать именно эту задачу, а не изобретать звездолет :)
  • ВладОшин © (04.05.16 19:33) [18]
    писал-писал, и ..закрыл окно (
    Вот, жаль))

    Да мне не нужен, пожалуй, стек знать.  Хотел схитрить.

    >>Вашего кода не вижу, но 150, 160 видится странноватыми значениями.
    Попробую коротко повторить
    Код жив 17 лет, писался разными людьми. Некоторые, кроме первого, (по комментам сужу) не разбирались в коде, решая свою задачу на тот момент. Нотификаторы из нотификаторов + сообщения из сообщений - в общем, полное спагетти.
    Иногда все это циклится, не понимаю пока почему.
    Если не разбираться, то можно было бы выкрутится через уровень вложенности.
    Но похоже, придется разбираться.
  • KSergey © (05.05.16 10:12) [19]
    О, кстати, еще вспомнил.
    Все виндовые функции про раскрутку стека вызовов начинают абсолютно врать, выдавая неразумные значения, если по пути вызовов есть вложенные функции.
    Может это как раз тот случай?

    Как с этим справляются разные Eureka и справляются ли - не знаю.
  • KSergey © (05.05.16 10:17) [20]
    > ВладОшин ©   (04.05.16 19:33) [18]
    > Иногда все это циклится, не понимаю пока почему.

    Тогда 160 - это еще какое-то весьма малое значение )

    Вероятно тут всё зависит от условий: один из вызовов (обработчиков сообщений) прерывает "зацикленность" по какому-то условию.
    А дальше всё зависит от производительности процессора, особенностей разбора очереди в конкретной версии Windows и т.п. Если повезёт - то нужное сообощение, прерывающее цепь вечности, успеет обработаться, пока стек ен переполнился, если не повезёт - то не успевает.

    (несколько притянуто за уши, конечно, при наличии лишь одного потока, понимаю; однако почему нет)
 
Конференция "Прочее" » Получить уровень вложенности кода.
Есть новые Нет новых   [134434   +27][b:0][p:0.001]