イベントビルダ

[注意] この文書はイベントビルダの概要を説明していますが,実際にシステムを構築するのに必要な項目を網羅しきれていません.実際の使用を検討する際は,メールフォーム(http://www.awa.tohoku.ac.jp/~sanshiro/kinoko-feedback/sendmail.html)より作者に連絡をください.使用状況に合わせた具体的な対応ができると思います.

Home

基本動作

KiNOKO のイベントビルダは,基本的にはどのようなデータでも処理できるように構成されています.ただし,その内容はデータ断片を組み換え,並べ替え,整理することのみで,データ検証や解析的な機能は含みません.これらは別コンポーネントで行うことが想定されています.

KiNOKO のイベントビルダは,一つのデータソース中のデータをビルドする前半部分 (Horizontal Builder) と,複数のデータソースからの部分ビルド済データをビルドする後半部分 (Vertical Builder) から構成されます.それぞれの段階での処理は以下のようになっています.

前半:単一データソース中でのソーティング (Horizontal Builder)
  1. 一つのデータソースから渡されるデータ断片(EventFragment)の列を「イベント番号(EventKey)」と「チャンネル(ChannelKey)」で特徴付けることのできるイベント断片(EventPiece)に再構成(分解と再結合)する.
  2. それぞれのイベント断片をイベント番号順に並べ替える.同じイベント番号の断片はチャンネル番号順に並べる.同じイベント番号で同じチャンネル番号の断片は到着順に並べる.
  3. 同じイベント番号を持つイベント断片を集めてひとかたまりのイベントセグメント(EventSegment)を構成し,出力する.

後半:複数データソースの結合 (Vertical Builder)
  1. 複数のデータストリームから渡されるイベントセグメントをイベント番号順に並べる.同じイベント番号のセグメントはセグメント番号順(ユーザ指定)に並べる.同じイベント番号の同じセグメント番号のセグメントは到着順に並べる.
  2. 同じイベント番号を持つイベントセグメントを集めてひとかたまりの新しいイベントセグメントを構成し,出力する.

これらは通常はコンポーネントとして実装され,典型的にはバッファを介して以下のように接続されます.

KiNOKO のイベントビルダは,入力されるデータのフォーマットについて何も知りません.入力データからイベント断片を切り出し,イベント番号とチャンネルの情報を取得するために,Horizontan Builder の入力部分にユーザ定義の「スキャナ」クラスが登録されています.ビルディングに必要なその他のパラメータはビルダ構成ファイル (Builder Configuration File) に記述され,実行時に解読されます.

イベントビルダを使うために,ユーザは以下のことを行わなければなりません.

  1. 扱うデータフォーマットに合わせてスキャナクラスを作成する
  2. スキャナクラスを Horizontal Builder に登録しコンパイルする
  3. ビルダ構成ファイルを作成し,パラメータを設定する
  4. KCOM スクリプトを編集してビルダコンポーネントを組み込む

イベントビルダの構造

概要

汎用フレームワーク
KiNOKO のイベントビルダは,基本的にはどのようなデータでも処理できるように構成されています.そのため,その内容はデータ断片を組み換え,並べ替え,整理のみで,データ検証や解析的な機能は含みません.これらは別コンポーネントで行うことが想定されています.

ここでいうイベントのビルディングとは,複数の入力から送られてくるデータ列を,意味のあるデータ断片に分割し,同一イベントに属するデータ断片を集約することを指します.すべてのデータ断片にイベント番号がついているなら,この集約部分はデータ断片をイベント番号順にソーティング(並べ替え)することに対応します.加えて KiNOKO は,同一イベントに属するデータ断片を,チャンネル番号順にソーティングします.

結局のところ,ビルディングとは,データの切り分けとソーティングをすることだけなので,データの切り分け方法と各断片のイベント番号およびチャンネル番号の取り出し方法さえ分かれば,ビルディングのほぼ全ての部分を汎用のフレームワークで構成できることになります.KiNOKO では,これらの情報の取得にユーザ定義のスキャナクラスを使うことによって,アプリケーション依存部分を切り分け,主要部分の汎用化を実現しています.ビルダの構成に必要なパラメータ(ビルド対象チャンネルやバッファサイズなど)は実行時に設定ファイルから読み込むようになっています.

破損データストリーム
ビルダに入力されるデータが完全ならば,上記のフレームワークで全ての処理を行うことができますが,データ収集系の不具合などによりデータが不完全だった場合,切り分けやイベント番号の取り出しができないことがあります.また,コンピュータやネットワーク等の状況によっては,一部のデータが遅れて到着し,ビルディングに間に合わないこともあります.KiNOKO では,このような状況でもビルダの安定動作を確保し,かつ,ビルダに入力されたいかなるデータも捨てないという立場から,このようなデータは破損データとしてビルド対象からはずし,適切なタグをつけて正常部分と区別できる状態で出力するようになっています.
ベストエフォート動作
イベントビルダの動作を不安定にさせる原因の一つに,一部のチャンネルからのデータが到着せず,ビルダがそれを長時間待つことによってバッファメモリを使い尽くしてしまうことがあります.これは,ネットワーク負荷などにより単純にデータ到着が遅れるような場合から,何らかの障害によってデータが失われたり,データの一部が破損し正しく認識できなくなる場合などに生じます.KiNOKO では,このような状況においてもビルダ自身の安定性を保ち,正常チャンネルのデータを守るため,到着の遅れたデータを永久に待つような動作をしません.具体的には,バッファメモリの使用量が指定量を越えた場合,それ以上のデータを待たずにバッファメモリ内のデータを強制的にビルディングします.

この動作により,到着の遅れたデータが本来入るべきイベントの中に入らないということが生じえます.KiNOKO では,このようなデータは上記の「破損データストリーム」に Late Arrival として送り出します.Late Arrival データは明確に区別され分けられているので,オフライン解析で再構成することが容易です.また,状況によっては,ビルダの後段のバッファで追いついて,正しい場所に挿入されることもあります(Late Arrival パケットはビルダのバッファを素通りするので,実際に追いつく可能性はかなりあります).

このような多段ビルダの特性を積極的に利用し,Late Arrival を処理するためだけに何もしないビルディングステージを追加することもできます.また,追加のビルディングステージをオフラインで実行すれば,Late Arrival の再構成を性能の高い計算機上で時間をかけて行うことができます.

ダイナミックテーブル
ビルディング対象のチャンネルなどは設定ファイルでビルダに通知されますが,KiNOKO のビルダは他の一般的なビルダと異なり,厳格な入力チャンネルテーブルを構成しません.上述したように,KiNOKO のビルダは入力データを切り分けてソートすることだけに徹するので,厳格なテーブルを持つ必要がないためです.

KiNOKO のチャンネルテーブルは,データ自身によって構成されます.すなわち,新たなチャンネルのデータが到着すれば,その時点でテーブルにエントリが作成されます.チャンネルのアクティビティは常にモニタされており,アクティビティが止まったと判断されると,そのチャンネルはテーブルから削除されます.この判断のためのパラメータはビルダ構成ファイルに記述されます.

チャンネルテーブルは,イベントの構成要素が完全に揃ったかどうかの判断に使用されます.すなわち,チャンネルテーブルの中のすべてのチャンネルが,(実際にそのチャンネルにデータがあるかに関わらず)あるイベント分のデータが揃ったと報告すれば,そのイベントのビルディングが開始されます.テーブルを動的に構成することより,汎用性と安定性が向上します.例えば,ある特定のチャンネルを状況により使わないことにしても,ビルダの変更は必要ありません.特定のチャンネルが突然死亡しデータを送出しなくなったとしても,それによってビルダがデータを待ち続けるという状況が起こりません.

この方法による問題は,最初のイベントをビルドする段階でテーブルが完成していないと,ビルディングが不完全になってしまうことです.すなわち,最初のビルドを試みるときまでに,全ての対象チャンネルから少なくとも一つのデータ断片が届いている必要があります.KiNOKO では,イベントのビルディングを開始するためのいくつかの判断基準を用意しており,これらはビルダ構成ファイルに記述されます.ただし,次に述べる理由により,これが完全である必要はありません.

KiNOKO は,ビルディング開始条件が成立していなくても,バッファメモリが一杯になる直前に強制的にビルディングを開始します.もしこの段階でもデータ断片が一つも届いていないチャンネルがあり,そのチャンネルからのデータ断片が最初のイベントに含まれるなら,ビルドは不完全となります(この場合,当該データ断片が届いた段階で Late Arrival として処理されます).なお,このような状況下では,仮にテーブルがダイナミック構成でなくて最初から完全であったとしても,バッファフルによる強制ビルドの段階で当該データがバッファメモリに届いていないので,いずれにしろ Late Arrival となり,結果は変わりません.

用語

EventKey
一つのイベントに対して一つの値となる識別値で,ビルドの対象となる全てのデータ断片がこの値を保持していることが想定されています.イベントビルダは,同じ EventKey を持つデータ断片を集めて一つのかたまりを構成します.概念的には,データ断片に対する時間方向の識別値です.実際には,一般に,イベントIDやイベントカウンタ,タイムスタンプ,フレーム番号,シーケンス番号などと呼ばれているものが対応します.現在のところ,符号付き 64bit 整数が割り当てられています.この値は連続である必要はありません.

StreamKey
ビルドの対象となるデータ断片の発生元を識別する値で,ビルドの対象となる全てのデータ断片がこの値を保持していることが想定されています.イベントビルダは,StreamKey の値ごとにイベント断片の到着が完了したかの判断をし,また,StreamKey の値ごとに,データレート等をモニタして生死の判断をします.概念的には,データ断片に対する空間方向の識別値で,時間変化しないものです.実際には,一般に,チャンネルやケーブル番号,モジュール番号,アドレスなどと呼ばれているものが対応します.Kinoko のデータソースIDやセクションIDなども StreamKey の一種として扱うことができます.現在のところ,符号付き 32bit 整数が割り当てられています.これも連続である必要はありません.

ChannelKey
StreamKey のひとつで,イベントビルダにとっての最小の空間方向の分割単位です.通常は,データ収集デバイスへの一つの入力信号ケーブルに対応します.イベントビルダはデータブロックが ChannelKey と EventKey で特定されるレベルまで分割されると,それ以上の中身については関知しません.ChannelKey でない StreamKey の例としては,ブロック読み出しを行うモジュールから読み出したデータのモジュール番号(Section ID など)や,クレート単位など部分的にビルドしたデータブロックに対する空間的識別値があります.

DataPacket
コンポーネント間を KinokoStream で転送されるデータのかたまりです.中身はビルディングのステージごとに異なったものとなります.

DataChunk
データのかたまりの一般的表現で,中身には関知しません.概念的には,単なる先頭アドレスとサイズで指定される連続データ領域です.実装上は,複数の不連続領域をまとめて一つのかたまりとして扱えるようになっています.

EventFragment
イベントを構成する(かもしれない)データのかたまりで,イベント単位,チャンネル単位に切り分けられていない段階のものです.つまり,複数のチャンネルからの複数のイベントの断片が混ざっている(かもしれない)状態です.この段階では,ある種の StreamKey はあるものの,ChannelKey や EventKey はありません.この段階における StreamKey の例としては,一枚のモジュールからブロック読み出ししたデータに対するモジュール番号などがあります.

EventPiece
イベントを構成する(かもしれない)データのかたまりで,イベント単位,チャンネル単位に切り分けられたものです.それぞれの EventPiece について,EventKey および ChannelKey が割り当てられます.また,中身の状態(破損していないかなど)や前後関係(到着遅れなど)を示す EventPieceType 属性を持っています.

EventPieceType
EventPiece の中身を分類する整数値で,以下の値をとります.この値によって,ビルダの処理内容が制御されます.

Normal
正しい EventKey および正しい ChannelKey を持ち,同じ StreamKey を持つ前後の EventPiece との間で正しい順序関係(EventKey が広義に昇順)を持っているものです.通常のビルディング処理が行われます.
Padding
保存の必要がないデータ領域で,ChannelKey や EventKey が割り当てられていないものです.アライメントのためのパディングやデータチェックのためのパターンなどが対応します.ChannelKey や EventKey が必要になった段階でデータストリームから削除されます.意味的に Padding でも,削除したくない場合は適切な ChannelKey および EventKey を割り当てた上で Normal Piece とします.
Unalinged
正しい EventKey および正しい ChannelKey を持つものの,同じ StreamKey を持つ前後の EventPiece との間の順序関係が正しくない(可能性がある)ものです.データ遅れによる見切りビルディングで生成された LateArrival や,何らかのバイパスに伴う EarlyArrival などがあります.ビルダは,多くの場合,この種類の EventPiece のために特別の処理をします.
Corrupted
ハードウェア障害などによりデータが壊れ, EventKey や ChannelKey が特定できないものです.データが可変長の場合は,データ境界が特定できず複数のイベントやチャンネルからのデータが混じる場合があります.破損データの出現位置を保持するために StreamKey や ChannelKey に値が割り振られることがありますが,これらの値はビルダ自身によっては使われません.多くの場合,ビルダのほとんどの処理を素通りします.

EventSegment
同じ EventKey を持つ EventPiece を0個以上まとめたものです.ビルドの途中で部分的にまとめたものである場合と,最終結果として全てをまとめたものである場合があります.

EventChopper
イベントビルダに入力されるデータ列 (EventFragment) を EventPiece に切り分ける機能を担うビルダの主要構成要素です.Chopper は EventFragement を入力 StreamKey に応じて整理し,必要なら複数の EventFragment の分解再結合を行います.

EventSorter
切り分けられた EventPiece を EventKey および ChannelKey 順に並べる機能を担うビルダの主要構成要素です.

EventSegmentPacker
複数のソート済み EventPiece をまとめて EventSegment を生成する機能を担うビルダの主要構成要素です.逆の機能を持った Unpacker もあります.

EventPieceScanner
EventChopper によって使われるユーザ定義のクラスで,Chopper により DataChunk として渡される EventFragment を解読し,サイズ・EventKey・ChannelKey を取り出します.Chopper はこの情報を使って DataChunk の再結合や EventPiece の生成を行います.

HorizontalBuilder
ビルダのうち,一つのデータソースからのデータをビルドするもので,Chopper,Sorter および Packer から構成されます.もしビルド対象に一つのデータソースしかない場合は,出力される EventSegment はイベント全体が完全にビルドされたものになります.そうでない場合は,すべての HorizontalBuilder からの出力を Buffer コンポーネントや kdfmerge コマンドなどで結合し,次の VerticalBuilder で処理する必要があります.

VerticalBuilder
ビルダのうち,複数のデータソースからのデータをビルドするもので,Sorter および Packer から構成されます.各データソース内のデータは HorizontalBuilder によってすでにビルドされていなければなりません.出力される EventSegment はイベント全体が完全にビルドされたものになります.

動作

デフラグと EventKey・ChannelKey の取得 (Horizontal Builder のみ)
Horizontal Builder に渡されたデータ列 (EventFragment) は,StreamKey ごとに分けられ,さらにそれぞれが EventPiece に切り分けられます.EventFragment から EventPiece の切り出しは,ユーザスキャナの助けを借りて,先頭にある EventPiece のサイズ分を取り出すことにより行われます.EventFragment が EventPiece のサイズよりも小さい(途中で分断されている)か,小さすぎてサイズを計算できない(サイズが記録されているフィールドが含まれていないなど)場合は,同じ StreamKey を持った次のデータの到着を待ち,それを後ろに結合して同じ処理を繰り返します.

この段階でユーザスキャナがデータ破壊を検出したら,その部分は以降破損データ (Corrupted) として処理されます.

EventPiece の切り分けができたら,やはりユーザスキャナの助けを借りて,EventKey および ChannelKey を取得し,その情報を EventPiece に付加します.

イベント完成判定
EventPiece へ切り分けられたデータは,ChannelKey ごとに EventKey を管理するテーブルに登録されます.すべてのチャネルにある EventKey のイベントが揃ったと判断されると,その EventKey をもつ EventPiece がまとめられて EventSegment が構築され,出力されます.

あるチャンネルにあるイベントが揃っているかどうかは,そのチャンネルにそれ以降のイベントのデータが到着しているかによって判定されます.特定のチャンネルにおいて,一つのイベントには高々一つの EventPiece しか含まれないということが確定している場合,ユーザスキャナがそのことを示すフラグを立てることにより,イベント完成判定基準が緩和されます.Unaligned とマークされている EventPiece は,この判定対象から除外されます.

完成イベントが存在しない状態でバッファが一杯になった場合,古いイベントから順に強制的にビルドされていきます.もし本来含まれるべき EventPiece がこの後到着したら,それは Unaligned とマークされそのまま出力されます (Late Arrival).強制ビルディングの際に完成判定基準を満たしていなかったチャンネルはイベントビルダが想定するデータレートでデータを送っていないとみなし,「死亡」とマークされ,以降のイベント完成判定対象から除外されます.もしこの後でそのチャンネルのデータが届いた場合,「死亡」状態は解除され,もとどおりの動作となります.

チャンネルテーブルの構成
イベント完成判定で「すべて」のチャンネルの到着データを比べる際,「すべて」を定義するのがチャンネルテーブルです.基本的には,新しい ChannelKey のデータが到着するたびにチャンネルテーブルにエントリが追加されます.チャンネルテーブル中のチャンネルのデータレートは常にモニタされ,データが到着しなくなったと判断される(次節)と,「すべて」の対象から一時的に除外されます.

このようにデータの到着によってテーブルを動的に構成する場合,最初のイベントの完成判定を行う時点でイベントテーブルが完成している必要があります.そうでないと不完全なテーブルを元に不完全なビルディングを行うことになってしまうためです(それでも,Late Arrival として後段で適切に処理することが可能です).KiNONO はイベントビルディング開始の条件を複数用意し,構成ファイルから指定できるようになっています.

もっとも単純な開始条件は,到着データの総量を指定するものです.読み出しスクリプトの制御により,例えば最初の 10MB には各チャンネルのデータが必ず最低1つ含まれていることが保証できれば,この値を指定することができます.

若干高度な方法として,各チャンネルのデータを含んだパケット数を計算して,「テーブルにすでに登録されているすべてのチャンネルに対してそのチャンネルが指定数以上のパケットデータを生成した」ことを開始条件とすることができます.多くの場合パケット数は読み出しのサイクル数に対応するので,すべてのチャンネルデータの到着を保証しやすくします.

一番安全な開始条件は,開始条件を指定しないことです.この場合,最初のイベントはバッファが一杯になることによる強制ビルディングとなります.この時点でもデータが到着していないデータがある場合でも,その部分はどのような方法をとったとしても Late Arrival となり,結果は変わりません.この方法の欠点は,ビルディング開始時に警告が出ることとと,最初のイベントのビルディングまでの遅延が大きいことです(最初の欠点は開始条件にバッファサイズより若干小さい到着総データサイズ条件を指定することにより回避できます).  

全く別の方法として,チャネルテーブルを構成ファイルから静的に記述することもできます.テーブル中に記載されたチャンネルからデータが到着しないとビルディングが開始されないので,その中に未使用チャンネルができた場合はバッファが一杯になるまで待ち続けることになります.ただし,この場合でも,最初の強制ビルディングにより未使用チャンネルが「死亡」とマークされるので,その後は問題なく動作することになります.

死亡チャンネルと生き返りチャンネル
すでに何度か言及しているとおり,KiNOKO はチャンネルごとにアクティビティをモニタし,チャンネルテーブルを動的に構成します.明らかにアクティビティが下がったと判断されるチャンネルまたはイベントビルダの動作に支障をきたすほどにアクティビティの低いチャンネルは「死亡」とマークされ,イベント完成判定から除外されます.

チャンネルが「死亡」したと判断されるのは,以下のいずれかの条件を満たした場合です.

「死亡」チャンネルが「生き返る」のは,以下のいずれかの条件を満たした場合です.

Early Arrival と異常パケットの処理
イベントビルダは,同じ ChannelKey に属する全ての EventPiece に対して,EventKey が広義に昇順で到着することを期待し,イベント完成判定を行っています.何らかの理由によってこの順序が変わることが想定される EventPiece に対しては,ユーザスキャナにおいて,IsPossiblyEarlyArrival フラグを指定することにより,完成判定から除外させることができます(Early Arrival 処理).ただし,この場合でも,EventKey が既にビルド済みのものであれば,Unaligned とマークされて,そのまま出力されます(Late Arrival 処理).

IsPossiblyEarlyArrival が指定されていない NormalPiece が,EventKey 昇順で到着しない場合,イベントビルダは EventKey の大きい方(先に到着した方)を自動で EarlyArrival とし,イベント完成判定から除外します.ただし,EventKey の小さい方(後に到着した方)の EventKey が既にビルド済みの場合は,Late Arrival となるので,後から到着した方が Unaglined としてそのまま送り出されることになります.

一度 Early Arrival となった EventPiece は,その後ビルディングが完了するまでイベント完成判定に使われることはありません.完成判定に使用できるタイミングを判断できないためです.Early Arrival の EventKey よりも大きい EventKey が到着すると,その直前に挿入されることになります.

EventKey が何らかの障害により不正に大きな値となっていると,これはイベントビルダ中で Early Arrival として長時間居残ることになります.これが大量発生するとバッファを大量消費し,イベントビルダの動作に支障が出るようになってしまう可能性があります.ユーザスキャナにおいて EventKey の変化を解析し,可能な限り不正を検出して,これをユーザスキャナ中において Corrupted とマークすることにより,この問題の発生を最小限にすることができます(Corrupted は全てのビルディング処理を素通りします).

データフォーマット

イベントビルダが出力するデータのフォーマットを以下に記します.ただし,通常の使用ではフォーマットの詳細を意識する必要はありません.ビルダが出力したファイルの読み方は 出力ファイルの読み方 の項を参照してください.
datasource "MyEvent01"<13310> { section "event_segment"<16385>: block { attribute ContentFormat = "EventSegment"; attribute ContentFormatVersion = "1.0"; } }
EventSegment セクションは block 型で,その中身は以下のようになっています.
Word 0: PieceType, NumberOfPieces
Word 1: EventKey(31 downto 0)
Word 2: EventKey(63 downto 32)
Block<EventPiece>*

ここで,<EventPiece>* は可変数個の可変長ブロックで,ひとつの可変長ブロックは以下のような構造になっています.

Word 0: ChannelKey
Word 1: Size
Block<RawData>
Word は全て 32bit 幅です.現在のところ,データブロックサイズは 4 byte の倍数のみ (32bit 幅ブロックのみ) サポートされています.

必要バッファサイズの見積り

イベントビルダの内部バッファのサイズは,Late Arraival の発生頻度が十分小さくなるように設定する必要があります.Horizontal Builder と Vertical Builder の間のバッファコンポーネントのバッファは,ストリームを結合することだけが目的なので,データがスムーズに流れる限りサイズは重要ではありません.Vertical Builder は入力データが読み込み可能になり次第すぐにそれを内部バッファへ取り込みます.
必要内部バッファサイズの計算方法
ここでは全てのチャンネルが一様に確率的にデータを生成するとして,偶発的に発生する Late Arraival の頻度を設定限界以下にするバッファサイズの計算をしてみます.なお,バッファサイズが EventPiece のサイズに大して十分に大きい(Late Arraival の許容出現頻度がデータ頻度よりも数桁以上小さい)ような状態で使用することを前提にして,近似計算を行います.
  1. 一つのチャンネルの一つの EventPiece のサイズを s とする.
  2. ビルド対象のチャンネル数を N とする
  3. s と N の積として特定チャンネルの平均イベント出現間隔 L=s*N が求まる
  4. 作業バッファのサイズを S とすると,バッファフル状態での特定チャンネルのバッファ中の平均イベント数 n が S/L として求まる
  5. あるバッファフルの状態で,バッファ中のイベント数が 1 以下になると Late Arrival となる.ある特定チャネルについて,この確率 p はポアソン分布で求められ,近似的に n/sqrt(n) シグマとなる
  6. あるバッファフルの状態で,少なくとも一つのチャンネルが Late Arrival となる確率 P は,P = 1 - (1-p)**N で,近似的に P = n*p.
  7. 連続動作状態を,毎回バッファフルまで貯めてから1イベントをビルドするモデルで考えると,イベントごとに上記の試行を行うことになる.
  8. 毎秒イベント数が f で,P が十分に小さければ,時間 T 秒の間に起こる Late Arrival の平均数は近似的に f*T*P 個.
  9. f*T*P 値が指定値以下になるように S の大きさを決める
バッファサイズが十分に大きい状態では,Late Arrival の出現確率はチャンネルの占拠率や読み出しブロックの大きさには依存しないことに注意してください.
計算例
  1. 1年間のイベント数: f*T = 1000 * 365*24*60*60 = 3.2e+10
  2. 1イベントあたりの Late Arrival 確率 P の上限: P < 0.1 / 3.2e+10 = 3.2e-12
  3. 1イベント1チャンネルあたりの Late Arrival 確率 p の上限: p = P / 4000 < 7.9e-16
  4. p の上限値はたぶん 10 シグマくらいなので,n の下限値は n > 10**2 = 100 くらい  
  5. チャンネルあたり平均出現間隔 L は L = 256 * 4000 = 1 Mbyte
  6. 必要バッファサイズ S は S = n * L > 100 M byte
Horizontal Builder でも Vertical Builder でも計算は基本的に同じですが,Horizontal Builder の方がビルド対象チャンネル数が小さくなるはずです.Vertical Builder は Horizoltal Builder が部分ビルドしたものを受け取るのでチャンネル数は Horizontal Builder の数と思うかもしれませんが,実際には,イベント出現間隔が重要なので,大元のチャンネル数と大元の EventPiece のサイズを使って計算しても結果に大きな違いはありません.

Horizontal Builder において,モジュールからの読み出しサイズがバッファサイズに比べて十分小さくないと,上記計算のチャンネルあたりイベント出現間隔のポアソン的扱いが妥当でなくなります.計算の妥当性を保証するという意味で,バッファサイズは読み出しサイズよりも十分大きいほうが安全です.Vertical Builder では読み出しブロックが解体されているのでこの問題はありません.

チャンネルからのデータ出現が確率的かつ一様でない場合は上記の計算はそのままでは適用できません.チャンネルごとに占拠率が大きく異なる場合は,イベント出現間隔を低頻度チャンネルに合わせて計算しなおします(必要バッファサイズは占拠率比に反比例します).特定のイベント(区間)が特異など,時間的に大きな変動がある場合は,そのイベント(区間)を別に計算して要求サイズの大きい方をとるか(特異性によっては和をとる),そのイベント(区間)をまるごと追加収容できるようにバッファサイズを設定するかします.Vertical Builder では,Horizoltal Builder による前処理のため,この問題の影響は比較的小さい(ほとんどの場合は全くない)ことが多いはずです.

ビルダの動作にとって,内部作業メモリは大きければ大きいほどよいので,状況が許す限り大きめにとるのが安全です.上記計算の数倍程度の余裕を持っておくと安心です.なお,ビルダは,管理テーブルなどにも,相当のメモリを使用することがあります.メモリ使用可能量に上限がある場合(32bit 環境で多く見られる 3GB 制限など),バッファサイズ上限はこれよりもかなり小さめにする必要があります.個々のイベント断片サイズが小さくかつチャンネルごとの頻度ばらつきが大きいなど,データの性質によっては,確保可能量の数分の一に設定しなければならない場合もあります(ビルダ自体は 64bit 環境でも動作確認されており,この場合この制限はかなりゆるくなります).

使用手順

概略

  1. モジュールのデータフォーマットに合わせたユーザスキャナクラスを作成する.
  2. TKinokoHorizontalBuilderCom にユーザスキャナを登録してコンポーネントを作成する.
  3. ビルダ構成ファイルを作成する.

  4. ここまでで作成したものを単体テストする.
  5. KCOM スクリプトを編集し,ビルダコンポーネントを配置接続する.

  6. 実行中に Late Arrival が出た場合,オフラインで Unaligned Piece を再構成する.

ここで使用しているサンプルの完全なコードが kinoko/local/tutorial/EventBuilder に置いてあります.

ユーザスキャナクラスの作成

ユーザスキャナクラスは,ビルダに入力される EventFragment を読んでその先頭にある EventPiece のサイズおよび EventKey や StreamKey などを Kinoko に教えるものです.実際には,Kinoko はユーザスキャナに先頭アドレスが設定された EventPiece オブジェクトを渡すので,ユーザスキャナはそれに EventKey や StreamKey の値を設定し,先頭の EventPiece のサイズを Kinoko に返します.

Kinoko の中で抽象クラス TKinokoEventPieceScanner が宣言されているので,これを継承し,コンストラクタ,デストラクタと以下の2つのメソッドを実装します.

/* KinokoEventPieceScanner.hh */ class TKinokoEventPieceScanner: public TKinokoEventPieceDefs { public: TKinokoEventPieceScanner(void); virtual ~TKinokoEventPieceScanner(); virtual int MaximumPieceSize(void) = 0; virtual int Scan(TStreamKey StreamKey, TKinokoEventPiece& EventPiece) = 0; };
int MaximumPieceSize(void)
処理対象のデータに対して可能性としてありうる最大の EventPiece サイズをバイト単位で返す.この値は Kinoko のエラーチェックに使われる.

int Scan(TStreamKey StreamKey, TKinokoEventPiece& EventPiece)
引数に EventPiece として渡されるデータを読み,そこから先頭の EventPiece を切り出して,その情報を EventPiece のメンバ変数に設定するとともに,その EventPiece のサイズを返す.渡されたデータに EventPiece が完全に含まれていない場合もしくはその判定ができない場合は 0 を返す.

TKinokoEventPiece::TPieceType PieceType
この EventPiece のタイプ.PieceType_Normal, PieceType_Padding, PieceType_Unaligned, PieceType_Corrupted のいずれか.

TStreamKey ChennelKey
この EventPiece の ChannelKey

TEventKey EventKey
この EventPiece の EventKey

int PieceFlag
この EventPiece の特性に関する付加的な情報.以下のビットフィールドの OR を設定する.特になければ 0 を設定する.
PieceFlag_IsPossiblyEarlyArrival
この EventPiece が何らかの理由により同一の _ChannelKey の他の EventPiece よりも早く到着した可能性があるときに設定する.

PieceFlag_LastOfTheEvent
この _ChannelKey のこの _EventKey の EventPiece がこの後にもう来ないことが確実な場合に設定する.

Scan() メソッドに渡される TKinokoEventPiece 型は次のように宣言されています.TKinokoDataChunk クラスから派生していることに注意してください.

/* KinokoEventPieceScanner.hh */ class TKinokoEventPiece: public TKinokoDataChunk { public: int PieceType; TStreamKey ChannelKey; TEventKey EventKey; int PieceFlag; };
Scan() メソッドでは,DataChunk のインターフェースを使ってデータを読みます.TKinokoDataChunk は,32bit 整数の配列としてその中身にアクセスできます.また,Size() メソッドによって全体のサイズを取得できます.
class TKinokoDataChunk { public: inline const U32bit& operator[](unsigned WordIndex) const; inline int Size(void) const;

引数に渡される StreamKey は,ビルダ設定ファイルで記述したものになります.

Scan() 関数が正の値を返すと,Kinoko は DataChunk から PieceSize 分を取り出して処理し,残りについて再び Scan() 関数を呼び出します.Scan() 関数が 0 を返すと,Kinoko はパケットが完結していないとし,同じ StreamKey の次のパケットを DataChunk の後ろにつなげて再び Scan() 関数を呼び出します.この過程で DataChunk のサイズが MaximumPieceSize() 関数が返す最大サイズに達した場合,Kinoko は全体を「破損データ」として処理し,次のパケットから再び Scan() による処理を開始します.

IsPossiblyEarlyArrival が設定されると,この EventPiece はビルディング待ちの列からはずされ,適切な挿入位置が見つかるまで退避されます.適切な挿入位置とは,同じ ChannelKey の EventPiece に対して,より大きい値の EventKey の直前です.退避された EventPiece は,EventKey の昇順チェックからはずされます.すでに LateArraival となっている場合は,この設定にかかわらず,LateArrival として処理されます.

通常,イベントのビルディングは全てのチャンネルの EventPiece が揃った段階で行われ,その判断は同じチャンネルに次のイベントの EventPiece が到着することによって行われます.IsLastOfTheEvent フラグが設定されていると,次の EventPiece の到着を待たずにこの判断が行われます.これによりビルディング開始までの待機時間が短縮されるので,バッファの使用量を減らす効果があります.一つのイベントの一つのチャンネルが必ず一つ(またはゼロ個)の EvnetPiece からのみ構成されると確実な場合にこのフラグを設定してください.

EventPiece がパディングでビルディング対象のデータでない場合は,PieceType に Padding を指定してください.この場合 EventKey や ChannelKey は使われないので設定しないままで構いません.ただし,戻り値に正しいサイズを返す必要があります.

データが破損していて EventKey および ChannelKey 取得できない場合は,PieceType に Corrupted を指定してください.戻り値には Corrupted としてビルディングから除外する範囲のサイズを返します.破損範囲が分からない場合もしくは MaxPieceSize を越えて大きい場合は渡された EventPiece の終了までを指定すれば,残りの破損部分は次の EventPiece で引き続き破損として処理することができます.破損データであっても EventKey および ChannelKey を任意の値で設定することができます.この値はビルディング処理では無視されますが,データとともに保存されるので,後から破損部分を特定する際の目印として使うことができます.もし EventKey や ChannelKey に負の値を指定すれば,直前の同じ StreamKey の正常な EventPiece のものと同じ値が Kinoko により書き込まれます(この場合に最初の EventPiece が破損していた場合は 0 が書き込まれます).

EventKey の値が正しくないのに Normal として処理されると,他の正常なものが異常と判断されることがあります.特に,不正ビットなどにより誤って遠い未来の値を示している場合,そのパケットは Early Arrival としてビルダのバッファに長時間居座ることになり,これが累積するとバッファ容量を圧迫することになります.この問題を避けるため,Scan() メソッドにおいて可能な限り EventKey の正当性チェックを行い,明らかに不正な EventKey を持った EventPiece を Corrupted するようにしてください.Corrupted となった EventPiece は,その後のビルダの処理を全て素通りするようになります.

ユーザクラス実装例
// MyEventPiece.hh // #include <KinokoEventPieceScanner.hh> // ユーザスキャナクラス class TMyEventPieceScanner: public TKinokoEventPieceScanner { public: typedef TKinokoEventPieceScanner::TStreamKey TStreamKey; public: TMyEventPieceScanner(void) {} virtual ~TMyEventPieceScanner() {} virtual int MaximumPieceSize(); virtual int Scan(TStreamKey StreamKey, TKinokoEventPiece& EventPiece); };
int TMyEventPieceScanner::MaximumPieceSize() { // 固定データ長の場合はその値 // // 可変データ長の場合はとりえる最大サイズを返す // return 256; } int TMyEventPieceScanner::Scan(TStreamKey StreamKey, TKinokoEventPiece& EventPiece) { // 渡されたブロックのサイズが小さければ 0 を返す // // その場合はより大きなブロックになって再び呼ばれる // if (EventPiece.Size() < 256) { return 0; } // ここでエラーチェックをするとよい // // エラーが検出されたら PieceType に PieceType_Corrupted を設定する // // エラーがない場合 // // キーやタイプなどを設定 // EventPiece.PieceType = PieceType_Normal; EvnetPiece.ChannelKey = EventPiece[0] & 0x0000ffff; EventPiece.EventKey = EventPiece[1]; EventPiece.PieceFlag = 0; // この EventPiece の実際のサイズを返す // return 256; }
スキャナテストプログラムの作成
スキャナはイベントビルダにおいて唯一のユーザロジックになります.可変長・可変フォーマットのデータを扱う場合や,ハードウェア障害などによるデータ破壊に対処したい場合は,比較的複雑なスキャナを開発しなければならないこともあります.そのような場合,スキャナだけを単体でテストするプログラムを作っておくと便利です.

KiNONO のビルダには,TKinokoBuilderScannterTester というスキャナをテストするためのクラスがすでにあるので,これにユーザスキャナを登録するだけで簡単にスキャナプログラムを作成することができます(以下の例のコードが kinoko/local/tutorial/EventBuilder に置いてあります).

// my-scanner-test.cc // #include <iostream> #include "MushArgumentList.hh" #include "KinokoStandaloneComponent.hh" #include "KinokoBuilderScannerTester.hh" #include "MyEventPiece.hh" using namespace std; int main(int argc, char** argv) { TMushArgumentList ArgumentList(argc, argv); string ConfigFileName = ArgumentList["--config"]; string BuilderName = ArgumentList["--name"]; if ((ArgumentList.NumberOfParameters() < 1) || ConfigFileName.empty() || BuilderName.empty() ){ cerr << "Usage: " << ArgumentList.ProgramName(); cerr << " --config=CONFIG_FILE_NAME --name=BUILDER_NAME"; cerr << " INPUT_FILE" << endl; return -1; } // この部分だけがアプリケーション依存 // TMyEventPieceScanner Scanner; TKinokoBuilderScannerDumper Dumper(cout); TKinokoBuilderScannerTester Tester(&Scanner, &Dumper); TKinokoStandaloneDataConsumer StandaloneConsumer(&Tester, "ScannerTester"); try { Tester.Configure(ConfigFileName, BuilderName); StandaloneConsumer.Start(ArgumentList); } catch (TKinokoException &e) { cerr << "ERROR: " << argv[0] << ": " << e << endl; } return 0; }
このプログラムは後でビルダ本体と一緒にコンパイルし,単体テストのところで使用します.

Horizontal Builder コンポーネントの作成

作成したユーザスキャナクラスを組み込んだ HorizontalBuilder コンポーネントを作成します.基本的にユーザコンポーネントの作成と同じ手順で,ユーザスキャナのインスタンス作成とその登録の2行だけがアプリケーション依存の部分となります.
/* MyHorizontalBuilder-kcom.cc */ #include <iostream> #include "KcomProcess.hh" #include "KinokoBuilderCom.hh" #include "MyEventPiece.hh" using namespace std; int main(int argc, char** argv) { TMushArgumentList ArgumentList(argc, argv); TKinokoHorizontalBuilderCom* Component = new TKinokoHorizontalBuilderCom(); TKcomProcess* ComProcess = new TKcomProcess(Component); // この部分だけがアプリケーション依存 // TKinokoEventPieceScanner* Scanner = new TMyEventPieceScanner(); Component->SetPieceScanner(Scanner); try { ComProcess->Start(ArgumentList); } catch (TKcomException &e) { cerr << "ERROR: " << argv[0] << ": " << e << endl; } delete Scanner; delete ComProcess; delete Component; return 0; }

ついでに,単体テストのためのスタンドアロン版もつくっておきます.

/* my-horizontal-builder.hh */ #include <iostream> #include "KinokoStandaloneBuilder.hh" #include "MyEventPiece.hh" using namespace std; int main(int argc, char** argv) { TKinokoStandaloneHorizontalBuilder Builder(argc, argv); // この部分だけがアプリケーション依存 // TMoguraEventPieceScanner Scanner; Builder.SetPieceScanner(&Scanner); try { return Builder.Start(); } catch (TKinokoException &e) { cerr << "ERROR: " << e << endl; return -1; } }

Makefile は以下のようになります(前章で作ったスキャナテストプログラムも含まれています).

# Makefile for MyHorizontalBuilder # BINS = MyHorizontalBuilder-kcom my-horizontal-builder my-scanner-test OBJS = MyEventPiece.o CXX=$(shell kinoko-config --cxx) CXXFLAGS=$(shell kinoko-config --cxxflags) LIBS=$(shell kinoko-config --libs) MyHorizontalBuilder-kcom: MyHorizontalBuilder-kcom.o $(OBJS) $(CXX) $(CXXFLAGS) -o $@ $@.o $(OBJS) $(LIBS) my-horizontal-builder: my-horizontal-builder.o $(OBJS) $(CXX) $(CXXFLAGS) -o $@ $@.o $(OBJS) $(LIBS) my-scanner-test: my-scanner-test.o $(OBJS) $(CXX) $(CXXFLAGS) -o $@ $@.o $(OBJS) $(LIBS) .cc.o: $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(DEFS) -c $<

設定ファイル

ビルダ設定ファイルは,Kinoko の基本スクリプトに builder エントリと set 文を追加したものになっています.builder エントリで対象ビルダを指定し,set 文でパラメータを設定します.ファイル拡張子には通常 kconf を使います(ファイル名 MyBuilder.kconf など).
Horizontal Builder
builder MoguraCrate03 { int crate = 3; set Type = "Horizontal"; set Name = "MoguraSorter" + dec(crate, 2); // 処理対象データソースの設定 // set TargetDataSource = "Mogura" + dec(crate, 2); // 処理対象セクションと StreamKey の設定 // list target_data_section; for (int card = 1; card <= 20; card++) { int key = 20 * (crate-1) + card; target_data_section <+>= { key => "mogura" + dec(card,2) }; }; set TargetDataSection = target_data_section; // 作業バッファサイズの設定 // set BufferSize = BufferSize; // 開始条件の設定:下記のうちどれかひとつ // set StartDataSize = 0x1000; //set StartPacketCycles = -1; //set StartChannelList = 240 * (crate-1) + [12,240]; }
ここで,builder の次の MoguraCrate03 はビルダ名です.一つの設定ファイルに異なったビルダ名で複数の設定を記述することができます.
Vertical Builder
builder Mogura { set Type = "Vertical"; set Name = "MoguraBuilder"; // 処理対象データソース と StreamKey の設定 // list target_data_source = { 0 => "MoguraTriggerSorter" }; for (int crate = 1; crate <= 6; crate++) { target_data_source <+>= { crate => "MoguraSorter" + dec(crate,2) }; }; set TargetDataSource = target_data_source; // 作業バッファサイズの設定 // set BufferSize = BufferSize; }
ここで,builder の次の Mogura はビルダ名です.一つの設定ファイルに異なったビルダ名で複数の設定を記述することができます.Horizontal Builder と Vertical Builder を混ぜても構いません.
パラメータ
set 文で設定できるパラメータは以下のとおりです.
共通パラメータ
Type
ビルダタイプを文字列で指定する.Horizontal もしくは Vertical
Name
ビルドされたデータのデータソース名を文字列で指定する

BufferSize
ビルダの作業バッファのサイズをバイト単位で指定する

StartDataSize
ビルディング開始条件にデータサイズを指定する場合のバイト単位のサイズ
StartPacketCycle
ビルディング開始条件にパケットサイクル数を指定する場合のサイクル数
StartChannelList
ビルディング開始条件にチャンネルテーブルを使用する場合の ChannelKey のリスト

IsInputPreserved
ビルダへ入力されたビルド対象データをビルド結果に加えて出力するかを指定する.true もしくは false (デフォルト).ビルド前のデータも合わせて記録したい場合に true を指定する.
Horizontal Builder のみのパラメータ
TargetDataSource
ビルド対象のデータソース名を文字列で指定する.
TargetDataSection
ビルド対象のデータセクション名を文字列リストで指定する.整数キーを指定するとその値がスキャナの Scan() メソッドの StreamKey パラメータとして渡される.
Vertical Builder のみのパラメータ
TargetDataSource
ビルド対象のデータソース名を文字列リストで指定する.整数キーを指定するとその値が StreamKey として使用され,同じイベントキーのデータに対してこの値の順にソートされる.

単体テスト

ビルダの開発には繰り返しテストが必要になることが多いので,KCOM を使わずに各コンポーネントのスタンドアロン版を使って開発作業を行うのが楽です.特に,ユーザロジックの集中するスキャナは,単体テストで確実に動作するようにしてからビルディングに進むのが,開発時の混乱を避けるのに有効です.
スキャナ単体テスト
スキャナの単体テストには,スキャナを作った際に作成したもの (my-scanner-test) を使います.
% ./my-scanner-test --config=MyConfigFile.kconf --name=MyCrate0 mydata-crate0.kdf # Title: Sorter Dump # Fields: PieceType ChannelKey EventKey PieceFlag Size # Command: RunBegin # Input: SectionId=1, Size=256 N 6 157834688 0 124 N 8 167855835 0 124 # Input: SectionId=2, Size=256 N 12 157834688 0 124 N 14 167855835 0 124
このプログラムは,引数に与えられたファイルをスキャナの入力として使います.--name パラメータは,ビルダ構成ファイルで記述したビルダ名(builder XXX の XXX の部分)です.テストのために,ビルディング前データの KDF ファイルを用意してください.多くの場合,読み出しスクリプトに tinykinoko を使うことで簡単に作成することができます.複数のデータソースがある場合で,そこからとったデータファイルがすでにある場合,それをそのまま使用して問題ありません(対象外のデータソースは単純に無視されます).

出力はスキャナに渡されたデータパケットのセクションIDとサイズ,スキャナの出力である ChannelKey と EventKey です.KinokoNtuple のプレインテキストファイル形式(kdftable の出力形式)で書き出され,入力側データに # が付いています.

スキャナテストプログラムで使っている TKinokoBuilderScannerDumper クラスを拡張することで,より多くの情報を書き出すようにすることができます.このクラスは kinoko/src/kernel/lib-domain/builder/KinokoBuilderScannerTester.hh/cc で定義されており,DumpOutputPiece() メソッドをオーバーライドすることにより,スキャナが生成する EventPiece の情報を全て見ることができます.データ自体のダンプなどに利用できます.

ビルダ単体テスト
Horizontal Builder には,コンポーネント版と同時に作成したもの(my-horizontal-builder)を使います.Vertical Builder には,Kinoko 標準の kinoko-vertical-builder が利用できます.

Vertical Builder のテストには複数の Horizontal Builder の出力をバッファでマージしたものが必要ですが,これは kdfmerge コマンドで作ることができます.kdfmerge は全ての入力から1パケットずつ順に取り出し出力に書き出します.この動作はバッファの到着時間順出力と異なりますが,ここでの単体テストには十分役に立ちます.

% ./my-horizontal-builder --config=MyConfigFile.kconf --name=MyCrate0 mydata-crate0.kdf mydata-crate0-sorted.kdf % ./my-horizontal-builder --config=MyConfigFile.kconf --name=MyCrate1 mydata-crate1.kdf built-crate1-sorted.kdf % kdfmerge mydata-crate0-sorted.kdf mydata-crate1-sorted.kdf mydata-sorted.kdf % kinoko-vertical-builder --config=MyConfigFile.kconf --name=MyBuilder mydata-sorted.kdf mydata-built.kdf
単体ビルダプログラムの第一引数が入力ファイル名,第2引数が出力ファイル名です. これらの各ステップにより,部分的または完全にビルディング処理が終わったファイルが生成されます.次の KCOM に進む前に,この後に解説している出力ファイルの読み方をみてファイル解読プログラムを作成し(サンプルの dump-event プログラムがそのまま使えます),ビルディング処理が想定どおりであることを確認します.

KCOM スクリプトの編集

ビルダコンポーネントは普通のパイプ型ストリームコンポーネントとして KCOM に組み込むことができます.つまり,KinokoTransporter コンポーネントとほぼ同じ記述をすればよいことになります(実際に,Transporter をプレースホルダーとしてシステムを作成しておき,あとからビルダコンポーネントに置き換えるのが便利です).Transporter コンポーネントとの違いは,宣言に加え,以下の KCOM イベントを加えることだけです.
// 必須:ビルダ構成ファイルとそのエントリ名を指定する // accepts setConfig(string config_file, string builder_name); // オプション:内部状態をロガーに記録する間隔を指定する.デフォルト 180 秒 // accepts setReportInterval(int interval_sec);
これらの設定は,他のコンポーネント同様,construct() の直前に行います.

出力ファイルの読み方

ビルドされたデータを読むためには,TKinokoEventSegmentProcessor を継承して MyEventSegmentProcessor クラスを作り,TKinokoEventConsumer に登録します.EventPiece を読みたい場合は,TKinokoEventPieceProcessor を継承して MyEventPieceProcessor クラスを作り,Unpacker を経由して TKinokoEventConsumer に登録します.TKinokoEventConsumer は TKinokoDataConsumer から派生しているので,通常のデータプロセッサとして使用することができます.

以下のクラスは,kinoko/src/kernel/lib-domain/builder にあるイベントプロセッサの例です.

/* KinokoEventDumper.hh */ #ifndef __KinokoEventDumper_hh__ #define __KinokoEventDumper_hh__ #include <iostream> #include "KinokoEventPiece.hh" #include "KinokoBuilderProcessor.hh" class TKinokoEventPieceDumper: public TKinokoEventPieceProcessor { public: TKinokoEventPieceDumper(std::ostream& Output); virtual ~TKinokoEventPieceDumper(); virtual void ProcessEventBegin(TEventKey EventKey, int PieceType, int NumberOfPieces, size_t TotalSize); virtual void ProcessEventEnd(void); virtual int ProcessPiece(const TKinokoEventPiece& EventPiece); protected: std::ostream& _Output; };
これを使うためのプログラムは以下のようになります.
#include <iostream> #include "MushArgumentList.hh" #include "KinokoEventProcessor.hh" #include "KinokoEventSegmentPacker.hh" #include "KinokoEventDumper.hh" #include "KinokoStandaloneComponent.hh" using namespace std; int main(int argc, char** argv) { if (argc < 3) { cerr << "Usage: " << argv[0] << " INPUT_FILE DATASOURCE_NAME" << endl; return -1; } TMushArgumentList ArgumentList(argc, argv); string InputDataSourceName = ArgumentList[1]; TKinokoEventPieceDumper PieceDumper(cout); TKinokoEventSegmentUnpacker Unpacker(&PieceDumper); TKinokoEventConsumer EventConsumer(InputDataSourceName, &Unpacker); // TKinokoEventConsumer は TKinokoDataConsumer から派生している // TKinokoStandaloneDataConsumer StandaloneConsumer(&EventConsumer, "EventDumper"); try { StandaloneConsumer.Start(ArgumentList); } catch (TKinokoException &e) { cerr << "ERROR: " << argv[0] << ": " << e << endl; } return 0; }
# Makefile # BINS = dump-event CXX=$(shell kinoko-config --cxx) CXXFLAGS=$(shell kinoko-config --cxxflags) LIBS=$(shell kinoko-config --libs) dump-event: dump-event.o $(CXX) $(CXXFLAGS) -o $@ $@.o $(LIBS) .cc.o: $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(DEFS) -c $<

使い方は通常のデータプロセッサと同じです.

% ./dump-event built.kdf MyBuilder
最初のパラメータがデータファイル名で,次のパラメータが処理対象のデータソース名です.

この例の入力は EventSegment なので,Horizontal Builder と Vertical Builder の両方の出力に対して使用できます.

現状の問題


Edited by: Enomoto Sanshiro