基礎勉強会 #4

低レイヤの開発ツール

今回の話

  • ソフトウェア開発につかう解析ツール
  • デバッガ: gdb
  • メモリプロファイラ: valgrind
  • トレーサ: strace, ltrace
  • パフォーマンスプロファイラ: time, gprof, perf

ツール

ツール

  • 動的解析ツール
  • 静的解析ツール

動的解析ツール

  • デバッガ
  • プロファイラ
    • パフォーマンスプロファイラ
    • メモリプロファイラ
  • トレーサ

静的解析ツール

  • フォーマッタ
  • リンタ or リント
  • メトリクス計測ツール
  • 並列性バグ検出ツール
  • OSS ライセンス検出ツール

コンパイラ・インタプリタ自体

  • エラーだけでなく警告にも目を通そう

デバッグ

デバッグ

  • print デバッグ
  • デバッガを使ったデバッグ

print デバッグ

  • 簡単なデバッグ方法
  • 簡単にできるが非効率的になりがち
  • そもそもログで出すべきかもしれない

デバッガを使ったデバッグ

  • デバッグといえばこれ
  • ツールを直に使う場合もあるが
  • IDE に統合されている場合が多い
    • 今回の説明ではツールをそのまま使う
    • IDE は好きに使ってください

gdb

gdb

  • GNUプロジェクトのデバッガ
  • 現在バージョン 8
    • 他のデバッガも gdb を参考に作られたものが多い
    • コマンドは似ている

gdb の対応言語

  • C/C++
  • D
  • Go
  • Objective-C
  • OpenCL C
  • Fortran
  • Pascal
  • Rust
  • Modula-2
  • Ada

デモ

gdb の起動

  • プログラムの実行
  • コアファイルの読み込み
  • プロセスへのアタッチ

TUI

  • C-x C-a で TUI 切り替え
  • アセンブリやレジスタの表示もできる
    • layout asm
    • layout regs

ステップ実行

  • continue
  • step
  • next

リバースステップ実行

準備として record コマンドを実行する

  • reverse-continue
  • reverse-step
  • reverse-next

print / p

式の値を表示する

(gdb) print 100
$7 = 100
(gdb) print/x 100
$8 = 0x64
(gdb) print/o 100
$9 = 0144
(gdb) print/t 100
$10 = 1100100
(gdb) p p
$11 = (person_t) 0x5555557572a0
(gdb) p (char*)p.name
$12 = 0x5555557572c0 "Alice"

break / b

ブレークポイントを設定する

  • 関数
  • ファイル中の行
  • 条件も設定可能

 

作ったものは削除・無効化可能

  • delete
  • disable, enable

break

(gdb) b main.c:89 if *name == 'A'
Breakpoint 8 at 0x555555554aca: file main.c, line 89.

watch

式の値が変わった場合にブレイクする

backtrace / bt

バックトレースを表示する

(gdb) bt
#0  print_persons (p=0x555555757260) at main.c:78
#1  0x0000555555554b5a in main (argc=1, argv=0x7fffffffd698) at main.c:98

フレーム間の移動は up, down

その他

  • info
  • help

valgrind

valgrind とは

  • 動的解析ツールをつくるためのフレームワーク
  • 次のようなツールが提供されている
    • memcheck
    • cachegrind
    • callgrind
    • helgrind
    • DRD
    • massif
    • DHAT
    • SGcheck
    • BBV

メモリーリーク

  • やっかいなバグのひとつ
  • 検出しづらい
    • 単体テスト、結合テストでは見つからない
    • 長時間実行してもメモリ使用量が増えてもバグかどうかは判断しづらい
      • 時間経過につれてメモリ使用量は増える
  • エラーが出ても気づきづらい
    • OOM killer が出てているのでログを見れば分かる
    • が、他のエラーを想定しがち

デモ

Valgrind

$ valgrind --leak-check=full <program>
==17417== Memcheck, a memory error detector
==17417== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==17417== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==17417== Command: ./main
==17417== 
==17417== 
==17417== HEAP SUMMARY:
==17417==     in use at exit: 2,048 bytes in 2 blocks
==17417==   total heap usage: 2 allocs, 0 frees, 2,048 bytes allocated
==17417== 
==17417== 1,024 bytes in 1 blocks are definitely lost in loss record 1 of 2
==17417==    at 0x4C2FB0F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==17417==    by 0x10865B: f (main.c:6)
==17417==    by 0x108689: main (main.c:20)
==17417== 
==17417== 1,024 bytes in 1 blocks are definitely lost in loss record 2 of 2
==17417==    at 0x4C2FB0F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==17417==    by 0x108674: g (main.c:13)
==17417==    by 0x108693: main (main.c:21)
==17417== 
==17417== LEAK SUMMARY:
==17417==    definitely lost: 2,048 bytes in 2 blocks
==17417==    indirectly lost: 0 bytes in 0 blocks
==17417==      possibly lost: 0 bytes in 0 blocks
==17417==    still reachable: 0 bytes in 0 blocks
==17417==         suppressed: 0 bytes in 0 blocks
==17417== 
==17417== For counts of detected and suppressed errors, rerun with: -v
==17417== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 0 from 0)

Helgrind

$ valgrind --tool=helgrind ./main

略

==18542== This conflicts with a previous write of size 4 by thread #2
==18542== Locks held: none
==18542==    at 0x10874B: f (main.c:8)
==18542==    by 0x4C36C26: ??? (in /usr/lib/valgrind/vgpreload_helgrind-amd64-linux.so)
==18542==    by 0x4E496DA: start_thread (pthread_create.c:463)
==18542==    by 0x518288E: clone (clone.S:95)
==18542==  Address 0x309014 is 0 bytes inside data symbol "var"

略

トレーサ

トレーサ

  • strace
    • システムコールをトレース
  • ltrace
    • ライブラリ API をトレース

デモ

パフォーマンスプロファイラ

パフォーマンスの測定

  • time
  • gprof
  • perf

time

% time sleep 3  
sleep 3  0.00s user 0.00s system 0% cpu 3.003 total

コマンドの実行だけで終わる単純な計測

gprof

  • コンパイル時にコード中の関数に仕組みし、計測する
  • コンパイルの際にオプションが必要
$ gprof main gmon.out
Flat profile:

Each sample counts as 0.01 seconds.
  %   cumulative   self              self     total           
 time   seconds   seconds    calls  us/call  us/call  name    
 51.65      0.56     0.56     1000   562.99   562.99  g
 48.88      1.10     0.53     1000   532.83   532.83  f

(以下略)

perf

プロファイリングとトレーシングのツールコレクション

  • サブコマンドの例
    • top
    • stat
    • record, report
    • timechart

perf record

コマンドを実行し、プロファイルをとる

% sudo perf record -a -g -F 997 sleep 10
[ perf record: Woken up 11 times to write data ]
[ perf record: Captured and wrote 6.181 MB perf.data (20127 samples) ]
% sudo perf report --stdio 
# Total Lost Samples: 0
#
# Samples: 20K of event 'cycles:ppp'
# Event count (approx.): 14794093886
#
# Children      Self  Command          Shared Object                    Symbol                                                                                                                             
# ........  ........  ............... ...............................................................
#
    37.91%     0.00%  swapper          [kernel.kallsyms]                [k] secondary_startup_64
            |
            ---secondary_startup_64
               |          
               |--33.30%--start_secondary
               |          cpu_startup_entry

perf top

システム全体での関数ごとの CPU 使用率

Samples: 55K of event 'cycles:ppp', Event count (approx.): 10091157696
Overhead  Shared Object                           Symbol
   3.20%  [kernel]                                [k] dw_readl
   1.61%  chrome                                  [.] 0x0000000004e67400
   1.56%  chrome                                  [.] 0x00000000033b0b83
   1.50%  chrome                                  [.] _fini
   1.33%  [kernel]                                [k] module_get_kallsym
   1.29%  [kernel]                                [k] syscall_return_via_sysret
   0.97%  libpthread-2.27.so                      [.] __pthread_mutex_lock
   0.83%  perf                                    [.] 0x00000000001f78a0

perf stat

パフォーマンスカウンタの統計を取得する

$ sudo perf stat date
Thu Jan 10 01:19:27 JST 2019

 Performance counter stats for 'date':

          1.113312      task-clock (msec)         #    0.607 CPUs utilized          
                 0      context-switches          #    0.000 K/sec                  
                 0      cpu-migrations            #    0.000 K/sec                  
                59      page-faults               #    0.053 M/sec                  
            993714      cycles                    #    0.893 GHz                    
            785347      instructions              #    0.79  insn per cycle         
            151250      branches                  #  135.856 M/sec                  
              7899      branch-misses             #    5.22% of all branches        

       0.001833304 seconds time elapsed

参考文献

次回の候補

  • アルゴリズム

  • データ構造→次回

  • ネットワーク

  • 仮想化・コンテナ
  • RDBMS, NoSQL
  • オブジェクト指向プログラミング
  • 関数型プログラミング
  • 継続的インテグレーション
  • 言語処理系
  • 文章術
  • 量子コンピューティング

低レイヤの開発ツール

By Shingo Suzuki

低レイヤの開発ツール

  • 928