データ管理をした時の性能
最後に、「大きなデータを送受信する時の性能」で使用したプログラムを使用して、データ量はほどほどにし、コネクション数を変化させた時の傾向を見ます。
検証数値は、コネクション数を10,000、処理回数を100回・500回・1,000回とし、データ量を1,024バイトとしました。その時の傾向を見ます。
# ./poll_performance_2 10000 100 1024 # ./epoll_level_performance_2 10000 100 1024 # ./epoll_edge_performance_2 10000 100 1024
# ./poll_performance_2 10000 500 1024 # ./epoll_level_performance_2 10000 500 1024 # ./epoll_edge_performance_2 10000 500 1024
# ./poll_performance_2 10000 1000 1024 # ./epoll_level_performance_2 10000 1000 1024 # ./epoll_edge_performance_2 10000 1000 1024
計測結果は下記の通りとなりました。送受信回数が1コネクションあたり100回の時はepollが勝っていますが、500回当たりでは逆転され、1,000回ではpoll完全に引き離されています。これには実は訳があります。
ディスクリプタへの送信/受信対象データの管理方法として、今回は簡潔に構造体の配列を用意し、メンバとしてディスクリプタおよび送受信データ量を管理しています。
epollの場合、readyになったディスクリプタのみが返ってくるため、そのディスクリプタが管理しているデータがどれなのかをディスクリプタ管理用構造体から検索する必要があり、そのロジックを今回は単純に先頭から舐める方法にしています。
100行目付近: for( j = 0; process_info[j].sock != evs[i].data.fd; j ++ );
pollの場合、返される値はreadyになったディスクリプタ数であり、どのディスクリプタがreadyになったか確認するためにpoll用配列を先頭から舐めていますが、poll用配列のインデックス値がそのままディスクリプタ管理用構造体のインデックス値と等しくなるので、管理情報を取得する際には先頭から舐める処理がいりません。
92: if(( pfds[i].revents & ( POLLIN | POLLOUT )) == 0 ) { 93: continue; 94: }
つまり何が言いたいかというと、各ディスクリプタに対してデータを管理する場合、いかがにepoll(2)
といえど、管理方法によっては性能値がpoll(2)
を使った場合よりも下回ることが十分にあり得るということです。ディスクリプタの管理方法がそのまま性能に直結することをしっかり認識し、epoll(2)
に頼らないアルゴリズムや設計が必要です。
まとめ
性能測定は以上になります。全体的にはpollよりもepollの方がより高い性能値を見せてくれました。
個人的な見解としては、性能結果が良かったのは非常に単純な使用方法の時のみであり、通常はコネクションによって処理が分かれるのは当たり前で、コネクションごと(=ディスクリプタごと)に処理が変わることで全体の性能値が変わるので、場合によってはpollの方が良い時もありそうです。
今回使用したプログラムは、疑似クライアントとしてスレッドを使用しており、スレッドの切り替え処理が発生しているはずで、性能結果としての厳密性は薄いと思いますが、まぁ参考にはなるかと思います。
いやいや、こんなプログラムではダメだ! こうしないと正確な性能測定はできない! などのご意見がございましたら、ぜひご連絡ください。
次回はシグナル駆動I/Oについて説明します。