実装した ROS node のコードを社内に晒したらマサカリが飛んできた話

はじめまして。プラットフォーム事業部の足立(@moguriso)です。昨年中は、Cloud IoT OS開発チームに所属しながら、あまりCloud IoT OSとは関係のないIoT Gatewayデバイス(BL-02)の開発に関わって台湾*1に行ったり、最近はデータ収集用に構築されたROS環境にnodeを追加するお仕事をやっています。

はじめに

本稿は、当社が10/24に開催する”OPTiM TECH NIGHT”で話す予定の「社製ROS nodeのコードを直してCPU負荷を減らしたホボROSと関係ない話」のプレビュー版として、対応中に社内から飛んできた”マサカリ”をご紹介します。内容にご興味持たれた方は10/24の”OPTiM TECH NIGHT”へ是非ご参加ください。

optim.connpass.com

OPTiMでのROSの使い方

当社はソフトウェア開発を主力とする企業としては珍しく、冒頭で紹介したBL-02ドローンといったハードウェアの開発にも力を入れています。
(下記は当社エンジニア坂井のプレゼン資料)

また、IoT分野ではセンサーデータ、カメラ画像の取得・解析は必須事項と言えます。特に、現在私が参画しているプロジェクトでは特殊なプロトコルの利用、マシンスペックの制約等があるため、それら諸問題を回避しつつCloud IoT OSへデータを集積するためにもROSを活用しています。

実装したROS nodeについて

機器の構成(概略)は下記の通りです。*2
カメラからデータを読み取り、別のnodeが受け取れるように受け流すnodeを実装しました。

f:id:optim-tech:20191017154718p:plain:w550
nodeに関する要件としては、大きく下記2点です。

  • USB接続のカメラから画像データを読み取る
  • 読み取ったデータを他のnodeに無加工で受け流す

当初の構成では、カメラとのインタフェースはROSの既存モジュール(libuvc_camera等)の利用を見込んでおり、ロジックの実装はスクリプト言語で行う想定でした。ところが調査した限りでは、ROSのカメラモジュールはROS内で画像処理することを前提に作られており*3、Motion JPEG/JPEGで取り込んだ場合でも内部でビットマップ形式への変換が走ります。今回利用するエッジデバイスは前述の通りマシンスペックに制約があるため、余分な画像処理によるCPUのオーバーヘッドが無視出来ません。そこで、スクリプト言語利用の前提から、低レイヤーの実装も可能なC++で直接カメラとのインタフェース部分から実装することにしました。*4

初期の実装は2週間程度で完了しました。それまでは、GolangとJavaとを少し触り、稀にC言語のコードを直すぬくぬく生活を送っていた事もあって、一段落した日の日報にはゴリゴリのメモリ管理に対する怨嗟の内容が記載されています。(↓当時の日報、原文ママ)

■コメント
topで見ていたら順調にメモリ使用量が増えていく現象に名前をつけてください。。。orz
昨日のテックリード会で奥村さんがC++はスレッドやら色々辛いと言っていたのが如実に思い出されました、、、
■今日工夫した所
boostライブラリを駆使した
■今日の仕事を後30分効率化できたやり方
boost使いすぎたかも知れません。。。

今思い返すと、バイネームで当社エグゼグティブエンジニア奥村の名前を出したのが運の尽きだったのかも知れません。。

f:id:optim-tech:20191017154731p:plain:w120f:id:optim-tech:20191017154731p:plain:w120f:id:optim-tech:20191017154731p:plain:w120f:id:optim-tech:20191017154731p:plain:w120

マサカリが飛んできた

翌日に奥村から以下の返信を貰いました。

メモリリーク、リソースリーク、ハンドルリーク、etc...

C++11以降だと boost を使う機会がかなり減った印象ですが
何のために boost を使っているんですか?

こちらに対する私の返信は以下の通りです。*5

> メモリリーク、リソースリーク、ハンドルリーク、etc...
( ゚д゚)マジレス イタダキマシタ!

この後、社内のgitリポジトリにコードを共有して*6、長文で真面目なやり取りを一巡終え、一段落した所でR&Dチームの久保から別の返信を貰いました。

足立さん:
なにやら盛り上がっていたのでソースコードをチラ見しましたが,
 http://xxxx/xxx.cpp#L208
で xxx_ctrl::output_jpeg を呼び出して
 http://xxxx/yyy.cpp##L16
によって ptr ポインタの指す先が新たに new で確保されたアドレスに変わっていますが,それを解放していませんね.
ここでリークしているんじゃないかと思います.

該当部分のソースは↓のような感じでした。

189	void xxx_core::data_read()		
190	{		
191		this->is_term_data_read = false;	
192		//this->cam_buffer.set_capacity(60);	
193		//this->cam_buffer_size.set_capacity(60);	
194		init_camera(camera_ctrl::MJPEG);	
195		while(!this->is_term_data_read) {	
196			int32_t cam_buf_sz = this->cam_ctrl.get_buffer_size();
197			uint8_t* cam_buf = new uint8_t[cam_buf_sz];
198			//boost::shared_ptr<uint8_t*> cam_buf(new uint8_t(cam_buf_sz));
199			//boost::shared_array<uint8_t> cam_buf(new uint8_t(cam_buf_sz));
200			//boost::scoped_array<uint8_t> cam_buf(new uint8_t[cam_buf_sz]);
201			uint8_t* _ptr;
202			uint8_t* tm_ptr = NULL;
203			DEBUG_PRINT("alloc addr = 0x%08X\n", (uint32_t)cam_buf);
204			size_t sz = this->cam_ctrl.read_camera(&cam_buf);
205	#ifdef __DEFINEの定義__		
206			_ptr = cam_buf;
207	#else /* __DEFINEの定義__ */		
208			sz = jpg_ctrl.output_jpeg(&_ptr, cam_buf, sz);
209	#endif /* __DEFINEの定義__ */		
210			if(this->cam_buffer.size() > 30) {

この時の私は「そんな見落とし私がするわけ無いじゃん」と言う発想が有ったため

ざんねん、そこは動かしてないのです( ̄ー ̄)ニヤッ

と、返していたのです*7。しかしながら、返す刀で久保から

__DEFINEの定義__ を定義しているのってここですよね?
http://xxxx/xxxx.cpp#L240

そうすると,
http://xxxx/xxxx.cpp#L205
の時点では else の方に入るのでそこが動いちゃってることになると思いますが.

「そんなバカな・・・」と思いつつ確認をすると。。。

205	#ifdef __DEFINEの定義__		
206			_ptr = cam_buf;
207	#else /* __DEFINEの定義__ */		
208			sz = jpg_ctrl.output_jpeg(&_ptr, cam_buf, sz);
209	#endif /* __DEFINEの定義__ */		
210			if(this->cam_buffer.size() > 30) {
~~~~(略)~~~~
240 #define __DEFINEの定義__
241 void xxx_core::publish()
242 {

指摘箇所を修正(L240の定義をL188に移動)した結果、、、

f:id:optim-tech:20191017154722p:plain:w240

正解
増えなくなりました ... orz

完全放置したつもりだったのに、ビルドが通って動いていたようです ... orz orz

このやり取りには、普段は日報に余り反応してくれないディレクターの谷口からもサムズアップが付きました。

終わりに

本稿執筆の目的はぼっちLTの回避にあります。

tech-blog.optim.co.jp

本イベントでは、会場が2ステージ構成になっています。参加者はステージ間を随時、自由に移動可能です。講演者は当社選りすぐりのエンジニア陣*8が担当します。このことが何を指し示すかと申しますと、例えばOPTiMのAI開発を頂点から主導する奥村と同じ枠の裏になってしまうと、私の聴講者はゼロと言う可能性も有り得ます。

f:id:optim-tech:20191017154727p:plain:w240
本稿をご覧の方は是非とも本イベントにご参加頂き、LTもご覧頂けますと私の精神衛生が保たれます。
よろしくどうぞ、お願いいたします。

optim.connpass.com

*1:小籠包、マンゴーかき氷美味しかったです

*2:イメージを含みます。直接車が繋がることはありません

*3:当たり前ですが

*4:もっと有った紆余曲折は10/24の”OPTiM TECH NIGHT”でお話できる…かも知れません

*5:なお、このやり取りは社長を含む全社に共有されています

*6:思えばこれが「止め」だった

*7:なお、このやり取りも(ry

*8:自画自賛?