1 of 41

Технологии и разработка СУБД

Лекция 5. Практический C/C++

Анастасия Лубенникова

Александр Алексеев

2 of 41

Лекция 5

  • Системы сборки
  • Тестирование
  • Статический анализ
  • Профайлеры
  • И вот это вот все

3 of 41

Autotools & CMake

  • Autotools
    • Стремное легаси
    • К сожалению, все еще много где используется
    • Только *nix
  • CMake
    • Добрая магия
    • Стандарт де-факто в современном C/C++
  • Есть также SCons и другие

4 of 41

Пример CMakeList.txt

5 of 41

Git Submodules

$ git submodule add https://github.com/glfw/glfw glfw

$ git submodule init

$ git submodule update

(И да, Subversion / Mercurial по факту мертвы, не тратьте на них время)

6 of 41

make vs ninja

$ mkdir build

$ cd build

$ cmake -DCMAKE_BUILD_TYPE=Release -G Ninja ..

$ ninja -j4

$ ninja test

7 of 41

Форматирование кода: CMakeLists.txt

file(GLOB_RECURSE ALL_SOURCE_FILES *.cpp *.h)

add_custom_target(format

COMMAND clang-format --style=file -i ${ALL_SOURCE_FILES} )

8 of 41

Форматирование кода: .clang-format

Language: Cpp

AlignEscapedNewlinesLeft: true

AccessModifierOffset: -4

AlignAfterOpenBracket: Align

AlignConsecutiveAssignments: false

AlignConsecutiveDeclarations: false

...

9 of 41

Основные виды тестирования

  • Модульное
    • На уровне процедур и классов
  • Интеграционное
    • На уровне отдельной библиотеки или микросервиса
  • Системное
    • Тестирование всей системы в целом
  • Прочие виды
    • Тестирование производительности
    • Тестирование безопасности
    • Тестирование совместимости
    • Юзабилити-тестирование
    • И т.д.

10 of 41

Test-Driven Development (TDD)

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

11 of 41

Тестирование: CMakeLists.txt

enable_testing()

add_test(NAME python_tests

COMMAND py.test -s -v ${CMAKE_SOURCE_DIR}/tests/run.py)

12 of 41

Тестирование: PyTest

class TestBasic:

# ...

def test_index(self):

self.log.debug("Running test_index")

res = requests.get('http://localhost:{}/'.format(PORT))

assert(res.status_code == 200)

13 of 41

Property-based тесты: пример

@pytest.mark.randomize(num=int, min_num=3,

max_num=1000, ncalls=100)

def test_quickcheck(self, num):

result = list(fibgen(num))

assert(result[0] < result[-1])

assert(len(result) == num)

14 of 41

Property-based тесты: зачем?

  • Меньше кода, дофига тестов
  • Тесты проверяют случаи, о которых вы могли не подумать
  • Находится минимальный вход, при котором тест не проходит
  • Другие реализации: QuickCheck, ScalaCheck

15 of 41

Code Coverage: CMakeLists.txt

option(USE_GCOV "Create a GCov-enabled build." OFF)

if (USE_GCOV)

set(GCC_COVERAGE_COMPILE_FLAGS "-fprofile-arcs -ftest-coverage")

set(GCC_COVERAGE_LINK_FLAGS "-lgcov")

endif()

set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${GCC_COVERAGE_COMPILE_FLAGS}" )

set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${GCC_COVERAGE_LINK_FLAGS}" )

16 of 41

Code Coverage: генерация отчета

cmake -DUSE_GCOV=ON ..

make

make test

lcov --directory . --capture --output-file summary.info

mkdir report

genhtml -o ./report summary.info

17 of 41

Code Coverage: результат

18 of 41

Code Coverage: построчно

19 of 41

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

  • CppCheck
    • Быстрый, но туповатый
    • Бесплатный
  • CLang Static Analyzer
    • Достаточно хороший статический анализатор
    • Бесплатный
  • PVS-Studio
    • Тоже хороший анализатор
    • За деньги
  • Coverity Scan
    • Считается лучшим
    • Очень дорого
    • Есть веб-версия, бесплатная для открытых проектов

20 of 41

Статический анализ: Clang Static Analyzer

$ cmake -DCMAKE_C_COMPILER=`which clang` \

-DCMAKE_CXX_COMPILER=`which clang++` -G Ninja ..

$ ninja clean

$ mkdir -p ~/temp/report

$ scan-build -o ~/temp/report ninja -j4

21 of 41

Статический анализ: пример отчета

22 of 41

Valgrind: зачем?

  • Находит утечки памяти
  • Находит обращения к неинициализированной памяти
  • В отличие от аналогов (MemorySanitizer) стабилен, гибок, работает везде
  • Из минусов: замедляет выполнение программы в 10-20 раз

23 of 41

Valgrind: пример использования

$ gcc -O0 -g vgcheck.c -o vgcheck

$ valgrind --leak-check=full --track-origins=yes ./vgcheck

24 of 41

Valgrind: пример отчета

==2205== Conditional jump or move depends on uninitialised value(s)

==2205== at 0x4E800EE: vfprintf (in /usr/lib/libc-2.25.so)

==2205== by 0x4E87EA5: printf (in /usr/lib/libc-2.25.so)

==2205== by 0x4005CA: run_test (vgcheck.c:10)

==2205== by 0x4005F4: main (vgcheck.c:18)

==2205== Uninitialised value was created by a stack allocation

==2205== at 0x400586: run_test (vgcheck.c:6)

25 of 41

Valgrind: что в нем еще есть

  • Флаг --suppressions
  • Callgrind - профилировщик
  • Massif - профилировщик памяти
  • Helgrind - инструмент поиска состояний гонки

26 of 41

Heaptrack: профилировщик памяти

$ heaptrack ./test_rbtree

# или: heaptrack -p PID

$ heaptrack_print --print-leaks \

--print-histogram histogram.data \

--print-massif massif.data \

--print-flamegraph flamegraph.data \

--file ./heaptrack.test_rbtree.22023.gz > report.txt

27 of 41

Heaptrack: визуализация собранных данных

$ massif-visualizer massif.data

28 of 41

Как не нужно делать бенчмарки

  • Неповторяемость
  • Вы измеряете не то, что думаете
  • Взятие среднего
  • Кто будет бенчмаркать бенчмарки?
  • Отсутствие анализа (правка наугад)
  • Игнорирование ошибок
  • Нетипичная нагрузка
  • Маркетинг и подгон
  • А как же другие параметры?

29 of 41

perf top

$ sudo perf top -p 12345

30 of 41

perf record

$ sudo perf record -p 12345 -F 99 -g

$ git clone https://github.com/brendangregg/FlameGraph

$ sudo perf script | \

./FlameGraph/stackcollapse-perf.pl > out.perf-folded

$ ./FlameGraph/flamegraph.pl out.perf-folded > perf.svg

31 of 41

Получаем флеймграф

32 of 41

Один полезный прием с GDB

$ gdb --batch --command=gdb.script -p 12345

… где в gdb.script написано просто:

bt

Иногда позволяет найти, где процесс долго висит в блокировке.

33 of 41

DTrace и компания

Инструменты трассировки ядра операционной системы и пользовательских приложений с целью их профайлинга и отладки (еще иногда для security-аудита).

  • DTrace
    • FreeBSD, MacOS. Есть dtrace4linux.
    • См также DTrace Toolkit: opensnoop, execsnoop и тд
  • SystemTap
    • Linux
    • Больше как инструмент разработчиков ядра, страшно тащить в продакшн.
  • bcc/eBPF
    • Добрая магия в Linux 4.1+ (лучше 4.9+)

34 of 41

DTrace: пример профилирования

$ sudo dtrace \

-n 'profile-4999 /execname == "postgres"/ {@[ustack(1)] = count()}'

$ sudo dtrace \

-n 'profile-4999 /pid == 1234/ { @[ustack()] = count() }' \

-o out.dtrace

35 of 41

DTrace: строим флеймграф

$ git clone https://github.com/brendangregg/FlameGraph

$ perl ./FlameGraph/stackcollapse.pl out.dtrace > out_folded.dtrace

$ perl ./FlameGraph/flamegraph.pl ./out_folded.dtrace > fg.svg

36 of 41

Флеймграфы с bcc/eBPF

$ sudo /usr/share/bcc/tools/profile -df -p 32133 > out.profile

$ git clone https://github.com/brendangregg/FlameGraph

$ ./FlameGraph/flamegraph.pl --colors hot < out.profile > out.svg

37 of 41

Полезняшки из bcc-tools

  • execsnoop
  • opensnoop
  • biotop
  • biolatancy
  • tcplife
  • tcptop
  • cpudist
  • filetop
  • gethostlatency
  • trace
  • argdist

38 of 41

Что осталось за кадром

  • В чем писать код
    • Vim, Sublime Text, CLion, тысячи их
  • Документация
    • Markdown, можно сказать, стандарт
    • Doxygen скорее стоит посмотреть, чем нет
  • Отладчики
    • GDB, LLDB, WinDBG + те, что в IDE
    • reverse debugging, например с RR
  • Ассемблер и дизассемблеры
    • Стоит знать как минимум x86/x64
    • Инструменты: objdump, Hopper, IDA Pro + gdb/lldb
  • CLang-санитайзеры
    • MemorySanitizer, ThreadSanitizer, etc

39 of 41

Дополнительные материалы

40 of 41

Домашние задания

41 of 41

Вопросы и ответы.