From 37914d1be23b89f7bd747d02ee5a56a18a12d7c3 Mon Sep 17 00:00:00 2001 From: sigiesec Date: Thu, 26 Oct 2017 09:46:11 +0200 Subject: [PATCH] Problem: get_fd_family call is expensive and called frequently for the same fds Solution: cache results of get_fd_family --- src/select.cpp | 35 ++++++++++++++++++++++++++++++++++- src/select.hpp | 7 ++++++- 2 files changed, 40 insertions(+), 2 deletions(-) diff --git a/src/select.cpp b/src/select.cpp index e5b2e479..33eb9af5 100644 --- a/src/select.cpp +++ b/src/select.cpp @@ -58,6 +58,10 @@ zmq::select_t::select_t (const zmq::ctx_t &ctx_) : #endif stopping (false) { +#if defined ZMQ_HAVE_WINDOWS + for (size_t i = 0; i < fd_family_cache_size; ++i) + fd_family_cache[i] = std::make_pair(retired_fd, 0); +#endif } zmq::select_t::~select_t () @@ -466,7 +470,36 @@ bool zmq::select_t::is_retired_fd (const fd_entry_t &entry) #if defined ZMQ_HAVE_WINDOWS u_short zmq::select_t::get_fd_family (fd_t fd_) { - // Use sockaddr_storage instead of sockaddr to accomodate differect structure sizes + // cache the results of determine_fd_family, as this is frequently called + // for the same sockets, and determine_fd_family is expensive + size_t i; + for (i = 0; i < fd_family_cache_size; ++i) + { + const std::pair &entry = fd_family_cache[i]; + if (entry.first == fd_) + { + return entry.second; + } + if (entry.first == retired_fd) + break; + } + + std::pair res = std::make_pair(fd_, determine_fd_family (fd_)); + if (i < fd_family_cache_size) { + fd_family_cache [i] = res; + } + else { + // just overwrite a random entry + // could be optimized by some LRU strategy + fd_family_cache [rand() % fd_family_cache_size] = res; + } + + return res.second; +} + +u_short zmq::select_t::determine_fd_family (fd_t fd_) +{ + // Use sockaddr_storage instead of sockaddr to accommodate different structure sizes sockaddr_storage addr = { 0 }; int addr_size = sizeof addr; diff --git a/src/select.hpp b/src/select.hpp index ad244146..bad2cd51 100644 --- a/src/select.hpp +++ b/src/select.hpp @@ -148,8 +148,13 @@ namespace zmq #endif #if defined ZMQ_HAVE_WINDOWS + static const size_t fd_family_cache_size = 8; + std::pair fd_family_cache [fd_family_cache_size]; + + u_short get_fd_family (fd_t fd_); + // Socket's family or AF_UNSPEC on error. - static u_short get_fd_family (fd_t fd_); + static u_short determine_fd_family (fd_t fd_); #endif // Checks if an fd_entry_t is retired. static bool is_retired_fd (const fd_entry_t &entry);