3

私は現在、マルチスレッドの高効率でスケーラブルなアルゴリズムを書いています。コードのパラメーターを推測する必要があり、特定のデータ セットで計算がどのように実行されるかがわからないため、変数を監視したいと考えています。このテストは、実世界の膨大なデータ セットでのみ機能します。プロファイリング後に収集したデータを分析することが可能です。次の単純なコード例を想像してみてください (実際のコードには複数のウォッチ ポイントが含まれる場合があります。

// function get's called by loops of multiple threads
void payload(data_t* data, double threshold) {
    double value = calc(data);
    // here I want to watch the value
    if (value < threshold) {
        doSomething(data);
    } else {
        doSomethingElse(data);
    }
}

私は次のアプローチについて考えました:

  1. coutまたは他のシステム出力を使用する
  2. バイナリ出力 (ファイル、ネットワーク) を使用する
  3. gdb/lldb でブレークポイントを設定する
  4. 変数の監視と gdb/lldb 経由のロギングを使用する

1. と 2. を使用するには、コードを変更する必要がありますが、これはデバッグ/評価タスクです。さらに、1. はロックが必要で、1.+2. I/O 操作が必要なため、コード全体が大幅に遅くなり、実際のデータを使用したテストがほぼ不可能になります。3.も遅すぎる。4. を使用するには、グローバル変数ではないため変数アドレスを知る必要がありますが、動的スケジューラによってスレッドが作成されるため、スレッドごとにブレーク + ステップが必要になります。

したがって、私の結論は、マシン コード レベルで動作し、double->string 変換なしで変数をダンプ/ログ/監視し、非常に効率的なプロファイラー/デバッガーが必要である、または他の言葉で要約すると、次のようになります。大幅なスローダウンや大幅な変更を行わずに、アルゴリズムの内部状態。これができるツールを知っている人はいますか?

4

2 に答える 2

3

OK、これには時間がかかりましたが、今では問題の解決策を提示できます。これはトレースポイントと呼ばれます。毎回プログラムを中断する代わりに、より軽量になり、(理想的には) パフォーマンスやタイミングをあまり変更しません。コードの変更は必要ありません。以下は、gdb を使用してそれらを使用する方法の説明です。

-g(フラグを使用して) デバッグ シンボルを使用してプログラムをコンパイルしたことを確認します。次に、gdb サーバーを起動し、ネットワーク ポート (例: 10000) とプログラム引数を指定します。

gdbserver :10000 ./program --parameters you --want --to use

次に、2 番目のコンソールに切り替えて、gdb を開始します (ここではプログラムのパラメーターは必要ありません)。

gdb ./program

次のすべてのコマンドは、gdb コマンド ライン インターフェイスで入力します。それでは、サーバーに接続しましょう。

target remote :10000

接続の確認を取得したら、traceまたはftraceを使用してトレースポイントを特定のソースの場所に設定します (ftrace最初に試してみてください。高速になるはずですが、すべてのプラットフォームで機能するとは限りません)。

trace source.c:127

これにより、トレースポイント #1 が作成されます。これで、このトレースポイントのアクションをセットアップできます。ここからデータを収集したいmyVariable

action 1
collect myVariable
end

大量のデータが予想される場合、またはデータを後で (再起動後に) 使用したい場合は、バイナリ トレース ファイルを設定できます。

tsave trace.bin

ここで、トレースを開始してプログラムを実行します。

tstart
continue

プログラムの終了を待つか、CTRL-C を使用してプログラムを中断することができます (サーバー側ではなく gdb コンソールで)。トレースを停止することを gdb に指示して続行します。

tstop

次のコードは非常に遅いので、私はあまり満足していません。

set pagination off
set logging file trace.txt
tfind start
while ($trace_frame != -1)
set logging on
printf "%f\n", myVariable
set logging off
tfind
end

これにより、すべての変数データが​​テキスト ファイルにダンプされます。ここでフィルターまたは準備を追加できます。これで完了です。gdb を終了できます。これにより、サーバーもシャットダウンされます。

quit

特にフィルタリングとより高度なトレースポイントの位置の説明に関する詳細なドキュメントについては、次のドキュメントにアクセスしてください: http://sourceware.org/gdb/onlinedocs/gdb/Tracepoints.html

トレース ファイルの書き込みをプログラムの実行から切り離すには、cgroups またはネットワークに接続された別のコンピューターを使用できます。別のコンピュータを使用する場合は、ポート情報にホストを追加する必要があります (例: 192.168.1.37:10000)。後でバイナリ トレース ファイルをロードするには、上記のように gdb を起動し (サーバーは忘れてください)、ターゲットを変更します。

gdb ./program
target tfile trace.bin
于 2013-08-03T20:34:20.077 に答える
1

たとえば、gdb デバッガーを使用してハードウェア ウォッチポイントを設定できます。

bool b;

変数の値が (任意のスレッドによって) 変更されるたびに通知を受けたい場合は、次のようにウォッチポイントを宣言します。

(gdb) watch *(bool*)0x7fffffffe344

例:

root@comp:~# gdb prog
GNU gdb (GDB) 7.5-ubuntu
Copyright ...
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>...
Reading symbols from /dist/Debug/GNU-Linux-x86/cppapp_socket5_ipaddresses...done.
(gdb) watch *(bool*)0x7fffffffe344
Hardware watchpoint 1: *(bool*)0x7fffffffe344
(gdb) start
Temporary breakpoint 2 at 0x40079f: file main.cpp, line 26.
Starting program: /dist/Debug/GNU-Linux-x86/cppapp_socket5_ipaddresses 

Hardware watchpoint 1: *(bool*)0x7fffffffe344

Old value = true
New value = false
main () at main.cpp:50
50                  if (strcmp(mask, "255.0.0.0") != 0) {
(gdb) c
Continuing.
Hardware watchpoint 1: *(bool*)0x7fffffffe344

Old value = false
New value = true
main () at main.cpp:41
41              if (ifa ->ifa_addr->sa_family == AF_INET) { // check it is IP4
(gdb) c
Continuing.
mask:255.255.255.0
eth0 IP Address 192.168.1.5
[Inferior 1 (process 18146) exited normally]
(gdb) q
于 2013-08-03T16:27:56.480 に答える