Date Редакция Категория comp Теги C / doxygen

Сразу предупрежу: 1) здесь нет единственно верного рецепта, все указанные средства в той или иной мере полезны; 2) никакая автоматизация при анализе логики работы программы не заменит самостоятельного думанья.

Статический анализ кода

Графы вызова: Doxygen

Строим графы вызова функций проекта, например с помощью Doxygen, и находим функции для которых отсутствует caller graph, то есть граф вызова ее самой другими функциями.

Статический анализатор Cppcheck

Статический анализатор кода Cppcheck позволяет, помимо прочего, находить неиспользуемые функции (unused functions).

Динамический анализ кода

GProf и Gprof2Dot

Статического анализа оказывается недостаточно, когда часть кода срабатывает лишь при определенных условиях. Рассмотрим пример, в котором функция f3() вызывается только при запуске программы без аргументов.

// cgtest.cpp
#include <iostream>

using std::cout;
using std::endl;

int f1()
{
    cout << "I'm f1()" << endl;
    return 10;
}

int f2()
{
    cout << "I'm f2()" << endl;
    return f1();
}

int f3()
{
    cout << "I'm f3()" << endl;
    return f2();
}

int main(int argc, char* argv[])
{
    if (argc >= 2)
        cout << f2() << endl;
    else
        cout << f3() << endl;
}

Граф вызова f3(), очевидно, существует

cg0.png

Однако сравнение текстовых записей графа вызовов, построенного профилировщиком GProf при запуске программы без аргументов

Call graph (explanation follows)


granularity: each sample hit covers 4 byte(s) no time propagated

index % time    self  children    called     name
                0.00    0.00       1/1           __libc_csu_init [18]
[8]      0.0    0.00    0.00       1         _GLOBAL__sub_I__Z2f1v [8]
                0.00    0.00       1/1           __static_initialization_and_destruction_0(int, int) [12]
-----------------------------------------------
                0.00    0.00       1/1           f2() [10]
[9]      0.0    0.00    0.00       1         f1() [9]
-----------------------------------------------
                0.00    0.00       1/1           f3() [11]
[10]     0.0    0.00    0.00       1         f2() [10]
                0.00    0.00       1/1           f1() [9]
-----------------------------------------------
                0.00    0.00       1/1           main [6]
[11]     0.0    0.00    0.00       1         f3() [11]
                0.00    0.00       1/1           f2() [10]
-----------------------------------------------
                0.00    0.00       1/1           _GLOBAL__sub_I__Z2f1v [8]
[12]     0.0    0.00    0.00       1         __static_initialization_and_destruction_0(int, int) [12]
-----------------------------------------------

и с аргументами

Call graph (explanation follows)


granularity: each sample hit covers 4 byte(s) no time propagated

index % time    self  children    called     name
                0.00    0.00       1/1           __libc_csu_init [18]
[8]      0.0    0.00    0.00       1         _GLOBAL__sub_I__Z2f1v [8]
                0.00    0.00       1/1           __static_initialization_and_destruction_0(int, int) [11]
-----------------------------------------------
                0.00    0.00       1/1           f2() [10]
[9]      0.0    0.00    0.00       1         f1() [9]
-----------------------------------------------
                0.00    0.00       1/1           main [6]
[10]     0.0    0.00    0.00       1         f2() [10]
                0.00    0.00       1/1           f1() [9]
-----------------------------------------------
                0.00    0.00       1/1           _GLOBAL__sub_I__Z2f1v [8]
[11]     0.0    0.00    0.00       1         __static_initialization_and_destruction_0(int, int) [11]
-----------------------------------------------

показывает, что в последнем случае функция f3() не используется.

Визуализировать созданный GProf граф вызова можно с помощью Gprof2Dot. Это скрипт на Python, который не требует установки.

./graph2dot.py gprof_output.txt > call_graph.dot
dot -Tpng call_graph.dot > call_graph.png # построение графа с помощью Graphviz

Получаем, при запуске без аргументов

out1.png

и с аргументами

out2.png

Valgrind и KCachegrind

KCachegrind (русское руководство) — это интерфейс для программы Cachegrind, которая строит графы вызова и входит в состав Valgrind. KCachegrind позволяет визуализировать графы вызова.

Gcov

Gcov — утилита для исследования покрытия кода. Обычно она используется совместно с gcc для выявления не покрываемых тестами участков кода. Gcov генерирует точное количество исполнений для каждого оператора в программе, что, в частности, позволяет выяснить какие строки кода не выполняются.

Для применения Gcov исходный код необходимо скомпилировать с опциями -fprofile-arcs, -ftest-coverage:

gcc -Wall -fprofile-arcs -ftest-coverage -lgcov cgtest.cpp

-ftest-coverage указывает сохранять статистику исполнения строк исходного файла, а -fprofile-arcs записывает статистику условных переходов (ветвлений).

Для графического представления собранной результатов Gcov статистики служат утилиты Lcov и Gcovr.



Комментарии

comments powered by Disqus