2016-12-28 21 views
4

Мы проводим исследования библиотек LLVM, и мы обнаружили, что ИК-библиотека иногда достигает стеков вызовов до 29 вызовов методов.Является ли код, который производит глубокие стеки вызовов, считается анти-шаблоном?

Иногда, когда я вижу некоторые сбои в инфраструктурах iOS, я также наблюдаю довольно глубокие стеки вызовов.

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

Вот пример:

/usr/local/LLVM/llvm/unittests/IR/AttributesTest.cpp:54 
    /usr/local/LLVM/llvm/lib/IR/LLVMContext.cpp:162 
    /usr/local/LLVM/llvm/lib/IR/LLVMContext.cpp:162 
     /usr/local/LLVM/llvm/lib/IR/LLVMContextImpl.cpp:54 
     /usr/local/LLVM/llvm/lib/IR/LLVMContextImpl.cpp:59 
      /usr/local/LLVM/llvm/lib/IR/Module.cpp:60 
      /usr/local/LLVM/llvm/lib/IR/Module.cpp:62 
       /usr/local/LLVM/llvm/lib/IR/Module.cpp:456 
       /usr/local/LLVM/llvm/lib/IR/Function.cpp:350 
        /usr/local/LLVM/llvm/lib/IR/BasicBlock.cpp:98 
        /usr/local/LLVM/llvm/include/llvm/ADT/ilist.h:282 
         /usr/local/LLVM/llvm/include/llvm/ADT/ilist.h:267 
         /usr/local/LLVM/llvm/lib/IR/SymbolTableListTraitsImpl.h:76 
          /usr/local/LLVM/llvm/lib/IR/BasicBlock.cpp:90 
          /usr/local/LLVM/llvm/lib/IR/SymbolTableListTraitsImpl.h:58 
           /usr/local/LLVM/llvm/lib/IR/ValueSymbolTable.cpp:75 
           /usr/local/LLVM/llvm/lib/IR/ValueSymbolTable.cpp:47 
            /usr/local/LLVM/llvm/include/llvm/Support/Casting.h:132 
            /usr/local/LLVM/llvm/include/llvm/Support/Casting.h:112 
             /usr/local/LLVM/llvm/include/llvm/Support/Casting.h:122 
             /usr/local/LLVM/llvm/include/llvm/Support/Casting.h:96 
              /usr/local/LLVM/llvm/include/llvm/IR/Value.h:777 
              /usr/local/LLVM/llvm/include/llvm/Support/Casting.h:132 
               /usr/local/LLVM/llvm/include/llvm/Support/Casting.h:122 
               /usr/local/LLVM/llvm/include/llvm/Support/Casting.h:75 
                /usr/local/LLVM/llvm/include/llvm/IR/Value.h:771 
                /usr/local/LLVM/llvm/include/llvm/Support/Casting.h:132 
                 /usr/local/LLVM/llvm/include/llvm/Support/Casting.h:122 
                 /usr/local/LLVM/llvm/include/llvm/Support/Casting.h:75 
                  /usr/local/LLVM/llvm/include/llvm/IR/Value.h:759 

P.S. Примерный стек вызовов фактически создается деструктором класса LLVMContext: LLVMContext::~LLVMContext(). Это еще один пример из очень старого сообщения из Java-мира: Java call stack – from HTTP upto JDBC as a picture.

+2

Зависит от того, как «глубокие» масштабы. Например, для обхода дерева достаточно стандартно производить масштабирование таблиц вызовов с глубиной дерева. – user2357112

+0

Его в глаза смотрящего. Возможно, виртуальные методы - это анти-шаблон. Возможно, даже C++ или объектная ориентация - это анти-шаблон. – wildplasser

+0

Обход дерева и другой рекурсивный шаблон не должны использовать стек вызовов для рекурсии, но итеративную реализацию, если у нас нет гарантии на глубину рекурсии, чтобы избежать взрыва ограничения размера стека. Это справедливо в Clang/LLVM. – Joky

ответ

5

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

Я собираюсь выйти на конечность и сказать «да», но есть проблемы с вашим вопросом и этим ответом.

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

Нет стандарта, без метрики, никакие полномочия не скажут вам, насколько глубока панель вызовов слишком глубокая. Имейте в виду, что почти любой стек можно избежать: стек вызовов является артефактом «факторизации» (если хотите) библиотеки. Можно представить себе замену вызова функции макросом или шаблоном C++. Тот же логический эффект, немного меньший подсчет команд. Возможно, дешевле, потому что он-лайн или дороже, потому что дублируется код. Но по крайней мере указатель стека не изменился!

Итак, я интерпретирую ваш вопрос как: Является ли большой стек вызовов относительно реализованной функциональности причиной тщательного анализа кода для ненужной сложности? К тому, я говорю «Да».

Столкнувшись с ситуацией, подобной той, которую вы описываете, я бы задался вопросом, были ли некоторые из этих вызовов «управляющими» функциями: какая-то обобщенная обертка, которая не очень-то работает. Я помню, как несколько лет назад читал библиотеку-маршаллинг, где стек вызовов до написал (2) был 14 глубиной. Большая часть кода ничего не делала, кроме как перетасовывать данные в другую абстракцию.

Не случайно: эта библиотека и ваши являются как C++. C++ упрощает выполнение неявных вызовов функций, а деструкторы - пример. Если вы пишете этот деструктор как функцию C, я уверен, что он будет длинным и плоским. Деструкторы также склонны совершать много «очистки» непосредственно перед освобождением памяти; в C вы могли бы просто позвонить бесплатно (3) несколько раз, и с ним было сделано.

Так что это не действительно глубина звонка per se Это проблема. Но ИМО ваш инстинкт прав: большой стек вызовов на небольшом количестве функциональности указывает на своего рода супер-организованный код спагетти.Это, конечно, не может повредить, чтобы взглянуть на функциональность заново, и, возможно, искать способы уменьшить количество абстракций.

+0

Связанный/тангенциальный параметр «* Нет стандартного, без метрики, никакие полномочия не скажут вам, насколько глубокий стек вызовов слишком глубокий. *": ... если вы не говорите о коде ядра, который должен работать с 4kiB или 8kiB размер стека ([например, в Linux] (http://elinux.org/Kernel_Small_Stacks)). Но это не только уровень вложенности, но и объем пространства, который используются конкретными функциями для автоматического хранения. –