UDP パケットを受信する (送信なし) GTKmm Windows アプリケーション (MinGW で構築) があります。ソケットはネイティブの winsock で、glibmm IOChannel を使用してアプリケーションのメイン ループに接続します。ソケットは recvfrom で読み取られます。
私の問題は、このセットアップが 3 GHz ワークステーションで 25% の CPU 時間を消費することです。誰かが理由を教えてもらえますか?
この場合、アプリケーションはアイドル状態であり、UDP コードを削除すると、CPU 使用率がほぼゼロに低下します。アプリケーションは CPU を集中的に使用するタスクを実行する必要があるため、その 25% を費やすより良い方法を想像できます。
ここにいくつかのコードの抜粋があります: (printf で申し訳ありません ;) )
/* bind */
void UDPInterface::bindToPort(unsigned short port)
{
struct sockaddr_in target;
WSADATA wsaData;
target.sin_family = AF_INET;
target.sin_port = htons(port);
target.sin_addr.s_addr = 0;
if ( WSAStartup ( 0x0202, &wsaData ) )
{
printf("WSAStartup failed!\n");
exit(0); // :)
WSACleanup();
}
sock = socket( AF_INET, SOCK_DGRAM, 0 );
if (sock == INVALID_SOCKET)
{
printf("invalid socket!\n");
exit(0);
}
if (bind(sock,(struct sockaddr*) &target, sizeof(struct sockaddr_in) ) == SOCKET_ERROR)
{
printf("failed to bind to port!\n");
exit(0);
}
printf("[UDPInterface::bindToPort] listening on port %i\n", port);
}
/* read */
bool UDPInterface::UDPEvent(Glib::IOCondition io_condition)
{
recvfrom(sock, (char*)buf, BUF_SIZE*4, 0, NULL, NULL);
/* process packet... */
}
/* glibmm connect */
Glib::RefPtr channel = Glib::IOChannel::create_from_win32_socket(udp.sock);
Glib::signal_io().connect( sigc::mem_fun(udp, &UDPInterface::UDPEvent), channel, Glib::IO_IN );
私はここで他の質問を読んだことがあります。また、ソケットが非ブロックモードになっていることを glib ドキュメント (g_io_channel_win32_new_socket()) で読んだことがあります。これは「実装の副作用であり、避けられない」ものです。これで CPU 効果が説明できますか?
パケットが到着する前に CPU が使い果たされ、読み取りハンドラーが呼び出されるため、glib を使用してソケットにアクセスするか、recvfrom() を直接呼び出すかどうかは、大きな違いはないようです。また、glibmm ドキュメントでは、ソケットがポーリングされていても recvfrom() を呼び出しても問題ないと述べています (Glib::IOChannel::create_from_win32_socket())。
-pg を使用してプログラムをコンパイルし、gprof を使用して関数ごとの CPU 使用率レポートを作成してみました。時間は私のプログラムではなく、外部の glib/glibmm dll で費やされているため、これは役に立ちませんでした。