NI製品ディスカッション

キャンセル
次の結果を表示 
次の代わりに検索 
もしかして: 

キューを用いたデータ取得におけるメモリ不足の解消

解決済み
解決策を見る

 

生産者・消費者アーキテクチャを用いてデータ取得をしているのですが、高いサンプルレートとサンプル数で回すと(rate:2M,samples/ch:400000,4ch同時測定)消費者ループが生産者ループよりも遅いためキューが満タンになってメモリ不足のエラーが出てしまいます。欲しいデータ数が充分あれば、キューが満タンになった時点で停止してしまってもいいのですが、明らかに欲しいデータ量にだってしていないため、できれば測定を続けたいと考えております。

 

 この場合、キューが満タンになったらキューが空になるまでエンキューを待機して(又はキューの全ての要素を捨てて)、空になった後にまたエンキューをし始める、といったプログラムは可能か、またもっと良い解決方法は無いでしょうか?

 

 やはりpcのスペックが問題でサンプルレートを低くするしかないのでしょうか?

0 件の賞賛
メッセージ1/9
2,134件の閲覧回数

1.6Mポイントのデータを200msで回すのはかなり高負荷ですが・・・

 

生産者・消費者デザインパターンを使う理由は何でしょうか?

消費者ループでは何をしていますか?

0 件の賞賛
メッセージ2/9
2,111件の閲覧回数

お返事ありがとうございます。

 

1.6M,200ms で回したのはどれくらい負荷をかけたらメモリがいっぱいになるのか実験的な目的で設定しました。

1時間ほどでメモリ一杯で停止しました。

 

生産者消費者ループを用いたのは、消費者側での処理が多いためです。

データの取得にはこの構成がいいとNIの記事などを読んで採用しました。

 

具体的には、生産者側でDAQmxでデータを読み込みキューに入れ、消費者側でデータのトリガー条件に一致するかの判別し、トリガーに一致したらもう一つのキューに入れて2つ目の消費者ループでデータのファイルへの書き込みをするといった形になります。

 

0 件の賞賛
メッセージ3/9
2,100件の閲覧回数

1時間耐えたのは、キューによって処理を分けた成果だと思いますが、やはり消費者側の処理が間に合わず、キューのデータが溜まってメモリオーバーになったと考えられます。

 

まずは処理を軽くすることを検討するのが良いと思います。

・ 波形データを整数で扱う(時間情報と物理値への換算係数は別に扱う必要があります)。

・ もしトリガの時間的位置が不要ならエッジ検索せずに配列の最大値だけで判定するのも手です。

・ キュー取得時にキューの最大サイズを指定できます(デフォルトでは無制限なのでメモリオーバーまで頑張ります)。その上で「エンキュー(ロッシー)」を使うとキューがいっぱいのとき最古のデータを捨ててくれます。

 

0 件の賞賛
メッセージ4/9
2,081件の閲覧回数

色々試してみましたが、サンプル数が高いとやはりメモリが一杯になってしまいます。

 

キューの最大値を設定するとありますが、どのくらいの値にするのが適切かわからないのですが教えていただけないでしょうか?

 

また、例えばキューが一杯になったとして最古のデータを捨てた後、また直ぐに一杯になってしまうような気がするのですが、それを何度も続けていくということでしょうか?

 

キューを使うといつかは必ずいっぱいになってしまうのでと思うのですが、3日間測定し続けるというのは難しいでしょうか?

 

0 件の賞賛
メッセージ5/9
1,970件の閲覧回数

いろいろ試してみた内容を教えてください。それによってアドバイスできることがあるかもしれません。たとえば、一度にエンキューするデータ数を増やして頻度を下げる(200ms→1sec)ほうが全体的な負荷が下がる場合があります。

 

また、例えばキューが一杯になったとして最古のデータを捨てた後、また直ぐに一杯になってしまうような気がするのですが、それを何度も続けていくということでしょうか?

そうです。メモリオーバーフローは避けられますがデータの欠損が許されない場合は使えません。

 

キューがあふれるかどうかは、エンキューとデキューの関係性によって決まります。デキューが間に合わないのは消費者側の処理が「常に」重いからです。消費者側の処理時間が増減するのなら減った時に遅れを取り戻せます。

対処としては、処理を軽くする、データサイズを減らす、PCを速くする、C言語で書く、といったところでしょうか。

0 件の賞賛
メッセージ6/9
1,966件の閲覧回数

試した内容としては、プログラム中のデータをできる限り小さいデータタイプを使用したり、4チャンネルの処理をForループで回していたのを並列Forループにしたりとかです。

 

たとえば、一度にエンキューするデータ数を増やして頻度を下げる(200ms→1sec)ほうが全体的な負荷が下がる場合があります。

それはデータの読み取り数を増やして処理側の速度と釣り合わせるということでしょうか?

 

 

>メモリオーバーフローは避けられますがデータの欠損が許されない場合は使えません。

例えばメモリがいっぱいになったら生産者側ループを一旦停止して、キューを空になるまで処理をしてから、生産者ループを再開するといったことは可能でしょうか?データの欠損は個々のパルス毎に対してはあってはならないですが、エンキューしたデータを全て連続して保存するわけではないため、少しデータの読み取りを停止する程度なら許容できます。

 

>消費者側の処理時間が増減するのなら減った時に遅れを取り戻せます。

放射線の測定なので増減しますが、カウントレートが高いと0.2ms間隔で4chのデータを保存しなければならないためこのようなエラーがあると考えられます。

 

 

0 件の賞賛
メッセージ7/9
1,962件の閲覧回数
解決策
受理者 Teion905

「できる限り小さい」とは具体的にどのデータタイプですか?

 

頻度を下げて1回のデータ量を増やすと間に合うケースがあるのは確かです。以下個人の見解ですが:

DAQからの読み取り、キュー送信、処理、保存、それぞれにメモリ操作などのオーバーヘッドがあります。頻度を下げると一回のデータ量が増えることによる負荷の増大より、繰り返しが頻度が高いことによるオーバーヘッドの積み増しのほうが影響が大きくなるのではないかと理解しています。

今回の場合当てはまるかどうかはわかりません。ちなみにまさかデータのグラフ表示など(パフォーマンスコストでかい)はしてないですよね?

 

キューサイズを指定しておくと、キューが満杯のときエンキュー関数は待たされます。キューステータス関数で状態は見られるので、満杯になる前にタスク停止で一時停止して(タスククリアしてはいけません)、キューがある程度空いたらタスクスタートすることはできると思います。

 

メッセージ8/9
1,958件の閲覧回数

出来るだけ小さいとは言っても、保存するデータの倍精度を単精度にしたぐらいです。

 

オーバーヘッドについては見逃しておりました。一度試して見ます。

 

グラフ表示はノーティファイアによって別のループで回しているので処理速度には影響ないと考えておりましたが、オーバーヘッドを考えると無くした方が良い気がしました。

今のviでは4チャンネル×3の12個もグラフ表示させていたので流石に厳しいですよね…

 

タスク停止の方法についても一度試して見ます。

0 件の賞賛
メッセージ9/9
1,954件の閲覧回数