CnCのデバッグ機能
CnCをtagのputをトリガとして対応するstepに着火するのですが、このときCnCは「どのスレッドにどのステップを割り当てるか」をスケジュールします。スケジュール次第で実際の着火順序はコロコロ変わります。どんな着火順序でもきちんと処理できるようにstep/item/tagを組み上げなくてはなりません。
トレース
CnCにはstep/item/tagの動作状況をトレース機能がついてます。トレース機能を使うには#include <cnc/debug.h>をお忘れなく。
トレースを仕掛けるのはとっても簡単、トレース対象となるstep_collection/item_collection/tag_collectionを引数にCnC::trace(トレース対象)するだけ。
例えばフィボナッチ・プログラムで、
fib_context ctxt; CnC::debug::trace(ctxt.m_steps); // m_stepsをトレース
fib(4)の実行結果はこんなカンジ。
同様にitem_collection/tag_collectionに対してもトレースを仕掛けることができますし、CnC::debug::trace_all(コンテキスト)すれば、コンテキストに属する全コレクションがトレース対象です。
fib_context ctxt; CnC::debug::trace_all(ctxt); // コンテキスト内のすべてをトレース /* CnC::debug::trace(ctxt.m_steps); CnC::debug::trace(ctxt.m_fibs); CnC::debug::trace(ctxt.m_tags); と同じ */
複数のstep/item/tag_collectionをトレースすると出力される各行のドレがドレやら分からなくなるのを避けるべく、各コレクションのコンストラクタで名前を与えて置くことができます。
fib_context::fib_context() : CnC::context< fib_context >(), m_steps( *this, "ステップ" ), m_fibs( *this , "アイテム"), m_tags( *this , "タグ" ) { m_tags.prescribes( m_steps, *this ); // m_tags は m_step に指示する m_steps.consumes( m_fibs ); // m_steps は m_fibs を消費する m_steps.produces( m_fibs ); // m_steps は m_fibs を生産する }
統計情報
コンテキスト内での一連の実行にわたり、着火されたstep数やスケジュールされたstep数を調べることができます。
コンテキストを引数にCnC::debug::collect_schedular_statistics(コンテキスト)しておけば、コンテキストのデストラクト時に統計情報が標準出力に出てきます。
fib_context ctxt; CnC::debug::collect_scheduler_statistics(ctxt);
プロファイル
着火された各ステップが消費したCPU-clock数や時間を調べることができます。
// コンテキストを生成し fib_context ctxt; CnC::debug::init_timer(); // 初期化 CnC::debug::time(ctxt.m_steps); // 計測開始 // tagをputして for( int i = 0; i <= n; ++i ) ctxt.m_tags.put( i ); // 終了を待ち ctxt.wait(); CnC::debug::finalize_timer(nullptr); // 計測終了/出力
init_timer()ののちstart_timer(ステップ)で計測開始、finalize_timer(ファイル名)で計測終了/出力します。ファイル名が「-」もしくはnullptrであれば標準出力が出力先です。TSV(タブ区切りフォーマット)なのでExcelで読めるのがうれしいところ。