ROSをPythonで書いてる人はお帰りください.
今日はROSのノード間通信の速度について調べてみた結果をご紹介します.
Nodeletってすごいらしい
知っての通り,ROSはノード間通信がSocketで実現されているため,物理的に離れたPC間でもroscoreを共有してROSノード同士が互いに通信を行うことができますが,同一PC内でも通信にオーバーヘッドが入ってしまって遅いという難点があります.
それを解決するのがNodeletという仕組み.1つのプロセス内でNodelet化した複数のROSノードをスレッド化して動作させ,且つそこで動いているROSノード間の通信をshared_ptr渡しにすることで,メッセージのシリアライズ/デシリアライズ処理を無くし,共有メモリによるコピー,いわゆるゼロコピーを行って通信の高速化を行うことができると言われています.そのため,様々な画像処理を行うimage_pipelineなんてパッケージは,そのほぼ全てがNodeletで提供されていたりします.まぁ,とりあえず「Nodelet Everything」という,Clearpath Roboticsの人が書いた記事をみんな読むんだ.
評価パッケージ作った
さて,「速くなる」って言っても,実際どれくらい速くなるのか興味があったので,メッセージのやりとりにかかる時間を計測するパッケージを作成しました.
ROSノード間のメッセージパッシング速度を評価するパッケージを作りました. https://t.co/AsxbANMSSo
— yoneken (@k_yone) December 8, 2016
使い方
パッケージをROSワークスペースにダウンロードしてビルドしたら,以下のようにroslaunchを立ち上げることでそれぞれの場合におけるメッセージのやりとりにかかる時間を計測することができます.
roslaunch measure_message_passing one_node.launch
roslaunch measure_message_passing one_node_ptr.launch
roslaunch measure_message_passing two_node.launch
roslaunch measure_message_passing two_node_ptr.launch
roslaunch measure_message_passing two_nodelet.launch
roslaunch measure_message_passing two_nodelet_ptr.launch
roslaunchを立ち上げてしばらくすると,1024x768のサイズでbgr8型(OpenCVのCV_8UC3型:符号なし8ビット3チャンネル)の画像データを1000回メッセージパッシングをしたときにかかる時間の平均値・中央値・最悪値(最大値)を出力します.
結果
MSIのゲーミングPC GS30 2Mで実際に計測した結果は,
- one_node (not pointer): Mean: 0.00140118, Median: 0.00139828, Max: 0.00454532
- one_node (pointer): Mean: 5.4087e-06, Median: 3.53647e-06, Max: 0.000275296
- two_node (not_pointer): Mean: 0.00235323, Median: 0.00236079, Max: 0.00825729
- two_node (pointer): Mean: 0.00088381, Median: 0.00087349, Max: 0.0030891
- two_nodelet (not pointer): Mean: 0.000689175, Median: 0.000686938, Max: 0.00333391
- two_nodelet (pointer): Mean: 5.41813e-05, Median: 4.98603e-05, Max: 0.000194368
となり,だいたい 2,6 <<< 5,4 < 1 < 3 くらいの順でメッセージのやり取りにかかる時間は大きくなりました.
この結果から,やはりNodelet+shared_ptrの効果は絶大だということがわかりました.また,それが難しい場合でも,Nodelet化かメッセージの型をshared_ptrにするかのどちらかをするだけでも,メッセージやりとりの高速化になかなか効果があることがわかりました.
おまけ
最初,subscribeする関数について,普通の型とshared_ptrにした型の2つを同じ名前でオーバーロードで実装していたのですが,こうすると普通の型で渡そうとしても,なぜか勝手にshared_ptrで渡されてしまい,思ったとおりの結果が出ないということがありました.ROSの機能なのかC++の機能なのかコンパイラの機能なのか,shared_ptrによるゼロコピーが可能な場合は,できるだけ自動でゼロコピーになるようになっているようです.
蛇足
12月17日(土)に秋葉原で古今東西の(自称)ロボット屋を集めて忘年会をします.もしご興味がありましたら,ぜひご参加ください.参加者は毎回流動的なので,初めての方もお気軽にご参加ください.学生歓迎.詳しくはこちらのページで.
申込み〆切までに登録しておいてもらえれば,参加者枠を広げられると思います.
追記(20/07/27)
やり取りしているメッセージのサイズについて追記しました。